Bug 1248309 - Fix caret size not updated when only zoom level is changed. r=roc
authorTing-Yu Lin <tlin@mozilla.com>
Mon, 15 Feb 2016 18:29:32 +0800
changeset 331598 1378bf53b053c9b06e108d1c865428290d1e3d96
parent 331597 fc71db9db3e56330b8dd577f35c7d8e07adde6ad
child 331599 b6287d1e98969a5af6cd82310dd38a30aa23856f
push id11020
push userjolesen@mozilla.com
push dateWed, 17 Feb 2016 18:16:38 +0000
reviewersroc
bugs1248309
milestone47.0a1
Bug 1248309 - Fix caret size not updated when only zoom level is changed. r=roc On Fennec, it's possible that after automatically zooming an editable input, the mImaginaryCaretRect for the caret remains the same. Only the zoom level is changed. Therefore, the zoom level should also be considered to determine whether the position is changed or not so that the caret can get updated. MozReview-Commit-ID: CrictS4S0Yl
layout/base/AccessibleCaret.cpp
layout/base/AccessibleCaret.h
--- a/layout/base/AccessibleCaret.cpp
+++ b/layout/base/AccessibleCaret.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AccessibleCaret.h"
 
 #include "AccessibleCaretLogger.h"
+#include "mozilla/FloatingPoint.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ToString.h"
 #include "nsCanvasFrame.h"
 #include "nsCaret.h"
 #include "nsDOMTokenList.h"
 #include "nsIFrame.h"
 
 namespace mozilla {
@@ -111,16 +112,17 @@ AccessibleCaret::SetAppearance(Appearanc
   AC_LOG("%s: %s -> %s", __FUNCTION__, ToString(mAppearance).c_str(),
          ToString(aAppearance).c_str());
 
   mAppearance = aAppearance;
 
   // Need to reset rect since the cached rect will be compared in SetPosition.
   if (mAppearance == Appearance::None) {
     mImaginaryCaretRect = nsRect();
+    mZoomLevel = 0.0f;
   }
 }
 
 void
 AccessibleCaret::SetSelectionBarEnabled(bool aEnabled)
 {
   if (mSelectionBarEnabled == aEnabled) {
     return;
@@ -250,94 +252,97 @@ AccessibleCaret::SetPosition(nsIFrame* a
     nsCaret::GetGeometryForFrame(aFrame, aOffset, nullptr);
 
   imaginaryCaretRectInFrame =
     nsLayoutUtils::ClampRectToScrollFrames(aFrame, imaginaryCaretRectInFrame);
 
   if (imaginaryCaretRectInFrame.IsEmpty()) {
     // Don't bother to set the caret position since it's invisible.
     mImaginaryCaretRect = nsRect();
+    mZoomLevel = 0.0f;
     return PositionChangedResult::Invisible;
   }
 
   nsRect imaginaryCaretRect = imaginaryCaretRectInFrame;
   nsLayoutUtils::TransformRect(aFrame, RootFrame(), imaginaryCaretRect);
+  float zoomLevel = GetZoomLevel();
 
-  if (imaginaryCaretRect.IsEqualEdges(mImaginaryCaretRect)) {
+  if (imaginaryCaretRect.IsEqualEdges(mImaginaryCaretRect) &&
+      FuzzyEqualsMultiplicative(zoomLevel, mZoomLevel)) {
     return PositionChangedResult::NotChanged;
   }
 
   mImaginaryCaretRect = imaginaryCaretRect;
+  mZoomLevel = zoomLevel;
 
   // SetCaretElementStyle() and SetSelectionBarElementStyle() require the
   // input rect relative to container frame.
   nsRect imaginaryCaretRectInContainerFrame = imaginaryCaretRectInFrame;
   nsLayoutUtils::TransformRect(aFrame, CustomContentContainerFrame(),
                                imaginaryCaretRectInContainerFrame);
-  SetCaretElementStyle(imaginaryCaretRectInContainerFrame);
-  SetSelectionBarElementStyle(imaginaryCaretRectInContainerFrame);
+  SetCaretElementStyle(imaginaryCaretRectInContainerFrame, mZoomLevel);
+  SetSelectionBarElementStyle(imaginaryCaretRectInContainerFrame, mZoomLevel);
 
   return PositionChangedResult::Changed;
 }
 
 nsIFrame*
 AccessibleCaret::CustomContentContainerFrame() const
 {
   nsCanvasFrame* canvasFrame = mPresShell->GetCanvasFrame();
   Element* container = canvasFrame->GetCustomContentContainer();
   nsIFrame* containerFrame = container->GetPrimaryFrame();
   return containerFrame;
 }
 
 void
-AccessibleCaret::SetCaretElementStyle(const nsRect& aRect)
+AccessibleCaret::SetCaretElementStyle(const nsRect& aRect, float aZoomLevel)
 {
   nsPoint position = CaretElementPosition(aRect);
   nsAutoString styleStr;
   styleStr.AppendPrintf("left: %dpx; top: %dpx; padding-top: %dpx;",
                         nsPresContext::AppUnitsToIntCSSPixels(position.x),
                         nsPresContext::AppUnitsToIntCSSPixels(position.y),
                         nsPresContext::AppUnitsToIntCSSPixels(aRect.height));
 
-  float zoomLevel = GetZoomLevel();
   styleStr.AppendPrintf(" width: %.2fpx; height: %.2fpx; margin-left: %.2fpx",
-                        sWidth / zoomLevel,
-                        sHeight / zoomLevel,
-                        sMarginLeft / zoomLevel);
+                        sWidth / aZoomLevel,
+                        sHeight / aZoomLevel,
+                        sMarginLeft / aZoomLevel);
 
   ErrorResult rv;
   CaretElement()->SetAttribute(NS_LITERAL_STRING("style"), styleStr, rv);
   MOZ_ASSERT(!rv.Failed());
 
   AC_LOG("Set caret style: %s", NS_ConvertUTF16toUTF8(styleStr).get());
 }
 
 void
-AccessibleCaret::SetSelectionBarElementStyle(const nsRect& aRect)
+AccessibleCaret::SetSelectionBarElementStyle(const nsRect& aRect,
+                                             float aZoomLevel)
 {
   int32_t height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
   nsAutoString barStyleStr;
   barStyleStr.AppendPrintf("margin-top: -%dpx; height: %dpx;",
                            height, height);
 
-  float zoomLevel = GetZoomLevel();
-  barStyleStr.AppendPrintf(" width: %.2fpx;", sBarWidth / zoomLevel);
+  barStyleStr.AppendPrintf(" width: %.2fpx;", sBarWidth / aZoomLevel);
 
   ErrorResult rv;
   SelectionBarElement()->SetAttribute(NS_LITERAL_STRING("style"), barStyleStr, rv);
   MOZ_ASSERT(!rv.Failed());
 
   AC_LOG("Set bar style: %s", NS_ConvertUTF16toUTF8(barStyleStr).get());
 }
 
 float
 AccessibleCaret::GetZoomLevel()
 {
   // Full zoom on desktop.
   float fullZoom = mPresShell->GetPresContext()->GetFullZoom();
 
-  // Pinch-zoom on B2G.
+  // Pinch-zoom on B2G or fennec.
   float resolution = mPresShell->GetCumulativeResolution();
 
   return fullZoom * resolution;
 }
 
 } // namespace mozilla
--- a/layout/base/AccessibleCaret.h
+++ b/layout/base/AccessibleCaret.h
@@ -99,17 +99,17 @@ public:
   // Visual Spec" in bug 921965.
   virtual void SetSelectionBarEnabled(bool aEnabled);
 
   // This enumeration representing the result returned by SetPosition().
   enum class PositionChangedResult : uint8_t {
     // Position is not changed.
     NotChanged,
 
-    // Position is changed.
+    // Position or zoom level is changed.
     Changed,
 
     // Position is out of scroll port.
     Invisible
   };
 
   friend std::ostream& operator<<(std::ostream& aStream,
                                   const PositionChangedResult& aResult);
@@ -133,18 +133,18 @@ public:
   // Element for 'Intersects' test. Container of image and bar elements.
   dom::Element* CaretElement() const
   {
     return mCaretElementHolder->GetContentNode();
   }
 
 protected:
   // Argument aRect should be relative to CustomContentContainerFrame().
-  void SetCaretElementStyle(const nsRect& aRect);
-  void SetSelectionBarElementStyle(const nsRect& aRect);
+  void SetCaretElementStyle(const nsRect& aRect, float aZoomLevel);
+  void SetSelectionBarElementStyle(const nsRect& aRect, float aZoomLevel);
 
   // Get current zoom level.
   float GetZoomLevel();
 
   // Element which contains the caret image for 'Contains' test.
   dom::Element* CaretImageElement() const
   {
     return CaretElement()->GetFirstElementChild();
@@ -205,16 +205,19 @@ protected:
   // outlive mPresShell.
   nsIPresShell* MOZ_NON_OWNING_REF const mPresShell = nullptr;
 
   RefPtr<dom::AnonymousContent> mCaretElementHolder;
 
   // mImaginaryCaretRect is relative to root frame.
   nsRect mImaginaryCaretRect;
 
+  // Cache current zoom level to determine whether position is changed.
+  float mZoomLevel = 0.0f;
+
   // A no-op touch-start listener which prevents APZ from panning when dragging
   // the caret.
   RefPtr<DummyTouchListener> mDummyTouchListener{new DummyTouchListener()};
 
   // Static class variables
   static float sWidth;
   static float sHeight;
   static float sMarginLeft;