wpfawesomium

Awesomium WebControl WPF seems to misinterpret Scaling


I'm trying to build a simple prototype (that use Awesomium 1.7 RC3) that allows a WPF application to display a WebPage, allowing the page to be zoomed in / out. I don't want to preserve the layout, but adapt the layout in the same manner that you can resize the window. It's the same behavior as the zoom feature of Internet Explorer. The logical display area is raised while the actual rendering is zoomed.

For exemple, here is a screenshot of the app with a 100% zoom:

Zoom 100% Zoom 100%
(source: hand-net.com)

The upper slider allows to control the zoom. When I change the zoom to 90% or 110%, here is what I get:

Zoom 90% Zoom 90%
(source: hand-net.com)

And

Zoom 110% Zoom 110%
(source: hand-net.com)

As you can see, the browser rendering is messy. Not only the internal rendering does not match the WebBrowser control area, but the picture resizing has a very low quality.

All of this were properly working with Awesomium 1.6.6.

How can I get the desired result?

The sample application can be downloaded here. The key parts are :

Xaml :

    <Slider Value="{Binding Path=Zoom, Mode=TwoWay}"
            IsSnapToTickEnabled="True"
            TickPlacement="Both"
            Grid.ColumnSpan="2"
            Minimum="0.1"
            Maximum="2.0"
            TickFrequency="0.1"
            LargeChange="0.1" />

    <Grid x:Name="Container"
          Background="SaddleBrown"
          Grid.Row="1"
          utils:SizeObserver.Observe="true"
          utils:SizeObserver.ObservedWidth="{Binding ContainerActualWidth, Mode=OneWayToSource}"
          utils:SizeObserver.ObservedHeight="{Binding ContainerActualHeight, Mode=OneWayToSource}">
        <Grid x:Name="Containee"
              Background="LightBlue"
              RenderTransformOrigin="0,0"
              Width="{Binding ContaineeWidth, Mode=OneWay}"
              Height="{Binding ContaineeHeight, Mode=OneWay}">
            <Grid.LayoutTransform>
                <TransformGroup>
                    <ScaleTransform ScaleX="{Binding Zoom, Mode=OneWay}"
                                    ScaleY="{Binding Zoom, Mode=OneWay}" />
                    <SkewTransform />
                    <RotateTransform />
                    <TranslateTransform />
                </TransformGroup>
            </Grid.LayoutTransform>
            <awe:WebControl Source="http://www.flickr.com/search/?q=strasbourg&amp;z=m" />
        </Grid>
    </Grid>

ViewModel that is used as DataContext:

public class ViewPortViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void RaisePropertyChanged(string propertyName)
    {
        Debug.WriteLine("Property changes: " + propertyName);
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private double m_Zoom = 1D;

    public double Zoom
    {
        get { return m_Zoom; }
        set
        {
            if (value != m_Zoom)
            {
                m_Zoom = value;
                RaisePropertyChanged("Zoom");
                RaisePropertyChanged("ContaineeWidth");
                RaisePropertyChanged("ContaineeHeight");
            }
        }
    }

    private double m_ContainerActualWidth = 100D;

    public double ContainerActualWidth
    {
        get { return m_ContainerActualWidth; }
        set
        {
            if (value != m_ContainerActualWidth)
            {
                m_ContainerActualWidth = value;
                RaisePropertyChanged("ContainerActualWidth");
                RaisePropertyChanged("ContaineeWidth");
            }
        }
    }

    private double m_ContainerActualHeight = 100D;

    public double ContainerActualHeight
    {
        get { return m_ContainerActualHeight; }
        set
        {
            if (value != m_ContainerActualHeight)
            {
                m_ContainerActualHeight = value;
                RaisePropertyChanged("ContainerActualHeight");
                RaisePropertyChanged("ContaineeHeight");
            }
        }
    }

    public double ContaineeWidth
    {
        get { return m_ContainerActualWidth / Zoom; }
    }

    public double ContaineeHeight
    {
        get { return m_ContainerActualHeight / Zoom; }
    }

Solution

  • I found the solution in my awesomium support forum question, gave by Perikles.

    Two steps to solve my issue:

    1. Also apply layout tranform to the webcontrol :

      <Grid x:Name="Containee"
          Background="LightBlue"
          RenderTransformOrigin="0,0"
          Width="{Binding ContaineeWidth, Mode=OneWay}"
          Height="{Binding ContaineeHeight, Mode=OneWay}">
      <Grid.LayoutTransform>
        <TransformGroup>
          <ScaleTransform ScaleX="{Binding Zoom, Mode=OneWay}"
                          ScaleY="{Binding Zoom, Mode=OneWay}" />
        </TransformGroup>
      </Grid.LayoutTransform>
      <awe:WebControl Source="http://www.flickr.com/search/?q=strasbourg&amp;z=m"
                              LoadingFrameComplete="WebControl_LoadingFrameComplete_1">
        <awe:WebControl.LayoutTransform>
          <ScaleTransform ScaleX="{Binding Zoom, Mode=OneWay}"
                          ScaleY="{Binding Zoom, Mode=OneWay}" />
        </awe:WebControl.LayoutTransform>
      </awe:WebControl>
      </Grid>
      
    2. Subscribe to the LoadingFrameComplete event to apply rendering transform options after the page is loaded :

      private bool renderingOptionsApplied;
      
      private void WebControl_LoadingFrameComplete_1(object sender, Awesomium.Core.FrameEventArgs e)
      {
          if (renderingOptionsApplied)
              return;
          var webControl = sender as Awesomium.Windows.Controls.WebControl;
      
          if ((webControl.Surface != null) && (webControl.Surface is WebViewPresenter))
          {
              RenderOptions.SetBitmapScalingMode(webControl.Surface as WebViewPresenter, BitmapScalingMode.Linear);
              renderingOptionsApplied = true;
          }
      }