Bug 4821: Implement page zoom (backend). r+sr=roc.
authorsharparrow1@yahoo.com
Wed, 25 Jul 2007 20:34:16 -0700
changeset 4003 d0e1067feda5ce704fd241e3d5c826a208b6cfbc
parent 4002 1e69aaeac53b237a40bd137c16175e723b571cbe
child 4004 ff3ee80e23d64f1090d53cc6d94876bd40834eeb
push idunknown
push userunknown
push dateunknown
bugs4821
milestone1.9a7pre
Bug 4821: Implement page zoom (backend). r+sr=roc.
content/events/src/nsDOMUIEvent.cpp
docshell/base/nsIMarkupDocumentViewer.idl
gfx/public/nsIDeviceContext.h
gfx/src/nsDeviceContext.cpp
gfx/src/thebes/nsThebesDeviceContext.cpp
gfx/src/thebes/nsThebesDeviceContext.h
layout/base/nsDocumentViewer.cpp
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -130,22 +130,23 @@ nsPoint nsDOMUIEvent::GetScreenPoint() {
        mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
        !NS_IS_DRAG_EVENT(mEvent))) {
     return nsPoint(0, 0);
   }
 
   if (!((nsGUIEvent*)mEvent)->widget ) {
     return mEvent->refPoint;
   }
-    
+
   nsRect bounds(mEvent->refPoint, nsSize(1, 1));
   nsRect offset;
   ((nsGUIEvent*)mEvent)->widget->WidgetToScreen ( bounds, offset );
-  return nsPoint(nsPresContext::AppUnitsToIntCSSPixels(mPresContext->DevPixelsToAppUnits(offset.x)),
-                 nsPresContext::AppUnitsToIntCSSPixels(mPresContext->DevPixelsToAppUnits(offset.y)));
+  PRInt32 factor = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
+  return nsPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
+                 nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
 }
 
 nsPoint nsDOMUIEvent::GetClientPoint() {
   if (!mEvent ||
       (mEvent->eventStructType != NS_MOUSE_EVENT &&
        mEvent->eventStructType != NS_POPUP_EVENT &&
        mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
        !NS_IS_DRAG_EVENT(mEvent)) ||
--- a/docshell/base/nsIMarkupDocumentViewer.idl
+++ b/docshell/base/nsIMarkupDocumentViewer.idl
@@ -59,16 +59,19 @@ interface nsIMarkupDocumentViewer : nsIS
 	/*
 	Scrolls to a given DOM content node. 
 	*/
 	void scrollToNode(in nsIDOMNode node);
 
 	/** The amount by which to scale all text. Default is 1.0. */
 	attribute float textZoom;
 
+	/** The amount by which to scale all lengths. Default is 1.0. */
+	attribute float fullZoom;
+
 	/** Disable entire author style level (including HTML presentation hints) */
 	attribute boolean authorStyleDisabled;
 
 	/*
 	XXX Comment here!
 	*/
 	attribute ACString defaultCharacterSet;
 
--- a/gfx/public/nsIDeviceContext.h
+++ b/gfx/public/nsIDeviceContext.h
@@ -460,16 +460,37 @@ public:
 
   /**
    * Check to see if the DPI has changed
    * @return whether there was actually a change in the DPI
    *         (whether AppUnitsPerDevPixel() or AppUnitsPerInch() changed)
   */
   virtual PRBool CheckDPIChange() = 0;
 
+  /**
+   * Set the pixel scaling factor: all lengths are multiplied by this factor
+   * when we convert them to device pixels. Returns whether the ratio of 
+   * app units to dev pixels changed because of the scale factor.
+   */
+  virtual PRBool SetPixelScale(float aScale) = 0;
+
+  /**
+   * Get the pixel scaling factor; defaults to 1.0, but can be changed with
+   * SetPixelScale.
+   */
+  float GetPixelScale() const { return mPixelScale; }
+
+  /**
+   * Get the unscaled ratio of app units to dev pixels; useful if something
+   * needs to be converted from to unscaled pixels
+   */
+  PRInt32 UnscaledAppUnitsPerDevPixel() { return mAppUnitsPerDevNotScaledPixel; }
+
 protected:
   PRInt32 mAppUnitsPerDevPixel;
   PRInt32 mAppUnitsPerInch;
+  PRInt32 mAppUnitsPerDevNotScaledPixel;
+  float  mPixelScale;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDeviceContext, NS_IDEVICE_CONTEXT_IID)
 
 #endif /* nsIDeviceContext_h___ */
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -52,16 +52,19 @@
 #include "nsIRenderingContext.h"
 
 NS_IMPL_ISUPPORTS3(DeviceContextImpl, nsIDeviceContext, nsIObserver, nsISupportsWeakReference)
 
 DeviceContextImpl::DeviceContextImpl()
 {
   mAppUnitsPerDevPixel = -1;
   mAppUnitsPerInch = -1;
+  mAppUnitsPerDevNotScaledPixel = -1;
+  mPixelScale = 1.0f;
+
   mFontCache = nsnull;
   mWidget = nsnull;
   mFontAliasTable = nsnull;
 
 #ifdef NS_DEBUG
   mInitialized = PR_FALSE;
 #endif
 }
--- a/gfx/src/thebes/nsThebesDeviceContext.cpp
+++ b/gfx/src/thebes/nsThebesDeviceContext.cpp
@@ -225,28 +225,30 @@ nsThebesDeviceContext::SetDPI()
 
     NS_ASSERTION(dpi != -1, "no dpi set");
 
     if (dotsArePixels) {
         // First figure out the closest multiple of 96, which is the number of
         // dev pixels per CSS pixel.  Then, divide that into AppUnitsPerCSSPixel()
         // to get the number of app units per dev pixel.  The PR_MAXes are to
         // make sure we don't end up dividing by zero.
-        mAppUnitsPerDevPixel = PR_MAX(1, AppUnitsPerCSSPixel() /
-                                      PR_MAX(1, (dpi + 48) / 96));
+        mAppUnitsPerDevNotScaledPixel = PR_MAX(1, AppUnitsPerCSSPixel() /
+                                        PR_MAX(1, (dpi + 48) / 96));
 
     } else {
         /* set mAppUnitsPerDevPixel so we're using exactly 72 dpi, even
          * though that means we have a non-integer number of device "pixels"
          * per CSS pixel
          */
-        mAppUnitsPerDevPixel = (AppUnitsPerCSSPixel() * 96) / dpi;
+        mAppUnitsPerDevNotScaledPixel = (AppUnitsPerCSSPixel() * 96) / dpi;
     }
 
-    mAppUnitsPerInch = NSIntPixelsToAppUnits(dpi, mAppUnitsPerDevPixel);
+    mAppUnitsPerInch = NSIntPixelsToAppUnits(dpi, mAppUnitsPerDevNotScaledPixel);
+
+    UpdateScaledAppUnits();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsThebesDeviceContext::Init(nsNativeWidget aWidget)
 {
     mWidget = aWidget;
@@ -722,16 +724,35 @@ nsThebesDeviceContext::CalcPrintingSize(
         printf("%d %d\n", (PRInt32)mWidth, (PRInt32)mHeight);
     } else {
         mWidth = NSToIntRound(size.width);
         mHeight = NSToIntRound(size.height);
     }
 }
 
 PRBool nsThebesDeviceContext::CheckDPIChange() {
-    PRInt32 oldDevPixels = mAppUnitsPerDevPixel;
+    PRInt32 oldDevPixels = mAppUnitsPerDevNotScaledPixel;
     PRInt32 oldInches = mAppUnitsPerInch;
 
     SetDPI();
 
-    return oldDevPixels != mAppUnitsPerDevPixel ||
+    return oldDevPixels != mAppUnitsPerDevNotScaledPixel ||
            oldInches != mAppUnitsPerInch;
 }
+
+PRBool
+nsThebesDeviceContext::SetPixelScale(float aScale)
+{
+    if (aScale <= 0) {
+        NS_NOTREACHED("Invalid pixel scale value");
+        return PR_FALSE;
+    }
+    PRInt32 oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
+    mPixelScale = aScale;
+    UpdateScaledAppUnits();
+    return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
+}
+
+void
+nsThebesDeviceContext::UpdateScaledAppUnits()
+{
+    mAppUnitsPerDevPixel = PR_MAX(1, PRInt32(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale));
+}
--- a/gfx/src/thebes/nsThebesDeviceContext.h
+++ b/gfx/src/thebes/nsThebesDeviceContext.h
@@ -111,16 +111,18 @@ public:
     NS_IMETHOD BeginPage(void);
     NS_IMETHOD EndPage(void);
     /* end printing goop */
 
     static void DebugShowCairoSurface (const char *aName, cairo_surface_t *aSurface);
 
     virtual PRBool CheckDPIChange();
 
+    virtual PRBool SetPixelScale(float aScale);
+
     nsNativeWidget GetWidget() { return mWidget; }
 #ifdef XP_WIN
     HDC GetPrintHDC() {
         if (mPrintingSurface) {
             NS_ASSERTION(mPrintingSurface->GetType() == gfxASurface::SurfaceTypeWin32, "invalid surface type");
             return reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC();
         }
         return nsnull;
@@ -137,16 +139,17 @@ public:
 #endif
 
 protected:
     nsresult SetDPI();
     void ComputeClientRectUsingScreen(nsRect *outRect);
     void ComputeFullAreaUsingScreen(nsRect *outRect);
     void FindScreen(nsIScreen **outScreen);
     void CalcPrintingSize();
+    void UpdateScaledAppUnits();
 
     PRUint32 mDepth;
 
 private:
     nsCOMPtr<nsIScreenManager> mScreenManager;
 
     nscoord mWidth;
     nscoord mHeight;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2567,16 +2567,34 @@ DocumentViewerImpl::GetTextZoom(float* a
   NS_ENSURE_ARG_POINTER(aTextZoom);
   NS_ASSERTION(!mPresContext || mPresContext->TextZoom() == mTextZoom, 
                "mPresContext->TextZoom() != mTextZoom");
 
   *aTextZoom = mTextZoom;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+DocumentViewerImpl::SetFullZoom(float aFullZoom)
+{
+  if (mPresContext) {
+      mPresContext->SetFullZoom(aFullZoom);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DocumentViewerImpl::GetFullZoom(float* aFullZoom)
+{
+  NS_ENSURE_ARG_POINTER(aFullZoom);
+  *aFullZoom = mPresContext ? mPresContext->GetFullZoom() : 1.0;
+  return NS_OK;
+}
+
 static void
 SetChildAuthorStyleDisabled(nsIMarkupDocumentViewer* aChild, void* aClosure)
 {
   PRBool styleDisabled  = *static_cast<PRBool*>(aClosure);
   aChild->SetAuthorStyleDisabled(styleDisabled);
 }
 
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -1068,19 +1068,33 @@ nsPresContext::GetDefaultFontInternal(PR
 
 const nsFont*
 nsPresContext::GetDefaultFontExternal(PRUint8 aFontID) const
 {
   return GetDefaultFontInternal(aFontID);
 }
 
 void
-nsPresContext::SetTextZoomExternal(float aZoom)
+nsPresContext::SetFullZoom(float aZoom)
 {
-  SetTextZoomInternal(aZoom);
+  nsPresContext* rootPresContext = RootPresContext();
+  if (rootPresContext != this) {
+    NS_WARNING("Zoom set on non-root prescontext");
+    rootPresContext->SetFullZoom(aZoom);
+    return;
+  }
+  nsRect bounds(mVisibleArea);
+  bounds.ScaleRoundPreservingCentersInverse(AppUnitsPerDevPixel());
+  if (!mShell || !mDeviceContext->SetPixelScale(aZoom))
+    return;
+  mDeviceContext->FlushFontCache();
+  nscoord width = DevPixelsToAppUnits(bounds.width);
+  nscoord height = DevPixelsToAppUnits(bounds.height);
+  GetViewManager()->SetWindowDimensions(width, height);
+  ClearStyleDataAndReflow();
 }
 
 imgIRequest*
 nsPresContext::LoadImage(imgIRequest* aImage, nsIFrame* aTargetFrame)
 {
   // look and see if we have a loader for the target frame.
   nsCOMPtr<nsImageLoader> loader;
   mImageLoaders.Get(aTargetFrame, getter_AddRefs(loader));
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -457,26 +457,23 @@ public:
   float GetPrintPreviewScale() { return mPPScale; }
   void SetPrintPreviewScale(float aScale) { mPPScale = aScale; }
 
   nsIDeviceContext* DeviceContext() { return mDeviceContext; }
   nsIEventStateManager* EventStateManager() { return mEventManager; }
   nsIAtom* GetLangGroup() { return mLangGroup; }
 
   float TextZoom() { return mTextZoom; }
-  void SetTextZoomInternal(float aZoom) {
+  void SetTextZoom(float aZoom) {
     mTextZoom = aZoom;
     ClearStyleDataAndReflow();
   }
-  virtual NS_HIDDEN_(void) SetTextZoomExternal(float aZoom);
-#ifdef _IMPL_NS_LAYOUT
-  void SetTextZoom(float aZoom) { SetTextZoomInternal(aZoom); }
-#else
-  void SetTextZoom(float aZoom) { SetTextZoomExternal(aZoom); }
-#endif
+
+  float GetFullZoom() {return mDeviceContext->GetPixelScale();}
+  void SetFullZoom(float aZoom);
 
   static PRInt32 AppUnitsPerCSSPixel() { return nsIDeviceContext::AppUnitsPerCSSPixel(); }
   PRInt32 AppUnitsPerDevPixel() const  { return mDeviceContext->AppUnitsPerDevPixel(); }
   PRInt32 AppUnitsPerInch() const      { return mDeviceContext->AppUnitsPerInch(); }
 
   static nscoord CSSPixelsToAppUnits(PRInt32 aPixels)
   { return NSIntPixelsToAppUnits(aPixels,
                                  nsIDeviceContext::AppUnitsPerCSSPixel()); }