From 7ad90a7dc73567fcb3bbcaeed84ab599231f8134 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Fri, 17 Feb 2023 08:19:53 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1208829 - Use the effective visible region to calculate the intermediate surface size. r=mstange (c3f8290088) - Bug 1168263 - Annotate layers with a perspective transform. r=mattwoodrow (a79c34590c) - Bug 1199798 - Use more generic tree traversal algorithms in APZCTreeManager. r=botond (9fede80160) - Bug 1179287 - Skip TestTiledLayerBuffer due to Linux PGO bustage. CLOSED TREE (c8dc548010) - Bug 1199798 - Create tests for TreeTraversal.h r=botond Move queue and stack includes outside of mozilla namespace. (37ba7ca2fe) - Bug 1226920 - Allow calling ForEachNode() with an action returning void r=botond (8368fcecc6) - Bug 1208829 - static_assert that IntRegionTyped is instantiated with a proper unit type. r=mstange (6acc37e149) - Bug 1208829 - Add utilities for converting between typed and untyped regions. r=mstange (40402a2f11) - Bug 1208829 - Rename LayerManagerComposite::ApplyOcclusionCulling to PostProcessLayers, and clean it up a bit. r=mstange (34f0bfe970) - Bug 1208829 - Recompute visible regions during composition. r=mstange (21304a1854) - Bug 1220873 - Make Layer::mVisibleRegion a LayerIntRegion. r=botond (5b8c30825e) - Bug 1168263 - Introduce a helper function IntersectMaybeRects(). r=kats (71f5087b64) - Bug 1168263 - Propagate the scroll-clip of a descendant of a layer with a perspective transform up to the layer itself. r=kats,mstange (fea1d86d5b) - Bug 1221694 - Add a basic telemetry probe for checkerboarding. r=botond,vladan (5725e19e0d) - Bug 1168263 - Simplify GetResultingTransformMatrix calculations to avoid unnecessary origin changes. r=roc (80368ae14f) - Bug 1127170 - Add TYPE_RENDERS_NO_IMAGES for display item with transform type to bypass invalidation during image decode. r=mattwoodrow (f6a207ee9d) - Bug 1168263 - Add nsDisplayPerspective and build separate layers for perspective. r=roc (b2b23687fb) - Bug 1176453 - Do not increment the cluster counter for input elements with label. r=kats (5bc312ca59) - Bug 1165128 - Enable zoomedview by default. r=mcomella (544b50df8b) - Bug 1181763 - Allow the target fluffing code to fluff even when directly hitting something clickable. r=roc (6ca7dd6904) - Bug 1188185 - Zoomed View appears when the two links are the same link. r=kats (813fca7975) - Bug 1192075 - Change copy in Settings for Zoomed View/ magnifying glass preference. r=mcomella (8430d9a907) - Bug 1191041 - Increase the likelihood of zoomed view triggering for small elements but decreased the likelihood for large elements. r=kats (eedeb65931) - Bug 1208370 - Deactivate the size heuristic in cluster detection. r=mcomella (360bca3b20) - Bug 1171731 - Ignore elements with 0 font size in cluster detection. r=kats (16d602f9d7) - Bug 1172488 - Small clickable text nodes are wrongly detected in cluster detection process. r=kats (d87c933ae2) - Bug 1191277 - Ensure that we don't find clusters of clickable elements when there is no possible way for the heuristic to actually target those elements. r=domivinc (50608494f9) - Bug 1226872 - Remove unnecessary wrapper methods in nsLayoutUtils. r=roc (6fbe70a794) - Bug 1208023 - Remove unused function. r=botond (c4f79eff8e) - Bug 1208023 - Ensure the minimum scale is a sane value greater than zero and add a separate flag to track if the default zoom is valid. r=botond (523cd967e2) - Bug 1225508 - Add a displayport on non-scrollable frames which have a resolution. r=botond (106045f0c9) - Bug 1201272 - use a SkBlurImageFilter for Skia canvas shadows so we can better control composite operations. r=gwright (bca9f2a21a) - Bug 998042 - 4-byte align Skia surfaces to interoperate with Cairo r=jrmuizel (5311a66ba1) - Bug 1083101 - Use win32's CreateEventW instead of CreateEvent to avoid macro name collision (68f94fa48c) - Bug 1148131 - Enable DrawTargetTiled on Android r=Bas (23f7fbca56) - Bug 1131264 - Extend the workaround for drawing D2D circles. r=bas (67ce725cfe) - Bug 1174922 - NativeZip does not null-terminate zip entry comparisons correctly, r=nchen (308848c1ef) - Bug 1127464 - Assert when we unexpectedly unload libraries on Android r=glandium (d55cda6129) - Bug 497495 late-breaking followup: s/GetAllocatedSize/GetFrameId/ in documentation, to reflect the same change having happened in code. (no review, comment-only, DONTBUILD) (f3cb3cf27c) - Bug 1216332 - Remove framearena helpers from abstract frame classes and stop them from being instantiated. r=dbaron (5b30fe7cba) - Bug 1178382 - Ignore overflow: -moz-hidden-unscrollable on , @@ -48,7 +48,7 @@ namespace mozilla { * event radii are disabled), we always use that element. Otherwise we collect * all frames intersecting a rectangle around the event position (taking CSS * transforms into account) and choose the best candidate in GetClosest(). - * Only IsElementClickable() candidates are considered; if none are found, + * Only GetClickableAncestor() candidates are considered; if none are found, * then we revert to targeting the element under the event position. * We ignore candidates outside the document subtree rooted by the * document of the element directly under the event position. This ensures that @@ -76,8 +76,10 @@ struct EventRadiusPrefs bool mRegistered; bool mTouchOnly; bool mRepositionEventCoords; - bool mTouchClusterDetection; + bool mTouchClusterDetectionEnabled; + bool mSimplifiedClusterDetection; uint32_t mLimitReadableSize; + uint32_t mKeepLimitSizeForCluster; }; static EventRadiusPrefs sMouseEventRadiusPrefs; @@ -126,10 +128,16 @@ GetPrefsFor(EventClassID aEventClassID) Preferences::AddBoolVarCache(&prefs->mRepositionEventCoords, repositionPref.get(), false); nsPrintfCString touchClusterPref("ui.zoomedview.enabled", prefBranch); - Preferences::AddBoolVarCache(&prefs->mTouchClusterDetection, touchClusterPref.get(), false); + Preferences::AddBoolVarCache(&prefs->mTouchClusterDetectionEnabled, touchClusterPref.get(), false); + + nsPrintfCString simplifiedClusterDetectionPref("ui.zoomedview.simplified", prefBranch); + Preferences::AddBoolVarCache(&prefs->mSimplifiedClusterDetection, simplifiedClusterDetectionPref.get(), false); nsPrintfCString limitReadableSizePref("ui.zoomedview.limitReadableSize", prefBranch); Preferences::AddUintVarCache(&prefs->mLimitReadableSize, limitReadableSizePref.get(), 8); + + nsPrintfCString keepLimitSize("ui.zoomedview.keepLimitSize", prefBranch); + Preferences::AddUintVarCache(&prefs->mKeepLimitSizeForCluster, keepLimitSize.get(), 16); } return prefs; @@ -173,7 +181,22 @@ HasTouchListener(nsIContent* aContent) } static bool -IsElementClickable(nsIFrame* aFrame, nsIAtom* stopAt = nullptr) +IsDescendant(nsIFrame* aFrame, nsIContent* aAncestor, nsAutoString* aLabelTargetId) +{ + for (nsIContent* content = aFrame->GetContent(); content; + content = content->GetFlattenedTreeParent()) { + if (aLabelTargetId && content->IsHTMLElement(nsGkAtoms::label)) { + content->GetAttr(kNameSpaceID_None, nsGkAtoms::_for, *aLabelTargetId); + } + if (content == aAncestor) { + return true; + } + } + return false; +} + +static nsIContent* +GetClickableAncestor(nsIFrame* aFrame, nsIAtom* stopAt = nullptr, nsAutoString* aLabelTargetId = nullptr) { // Input events propagate up the content tree so we'll follow the content // ancestors to look for elements accepting the click. @@ -183,14 +206,19 @@ IsElementClickable(nsIFrame* aFrame, nsIAtom* stopAt = nullptr) break; } if (HasTouchListener(content) || HasMouseListener(content)) { - return true; + return content; } if (content->IsAnyOfHTMLElements(nsGkAtoms::button, nsGkAtoms::input, nsGkAtoms::select, - nsGkAtoms::textarea, - nsGkAtoms::label)) { - return true; + nsGkAtoms::textarea)) { + return content; + } + if (content->IsHTMLElement(nsGkAtoms::label)) { + if (aLabelTargetId) { + content->GetAttr(kNameSpaceID_None, nsGkAtoms::_for, *aLabelTargetId); + } + return content; } // Bug 921928: we don't have access to the content of remote iframe. @@ -201,7 +229,7 @@ IsElementClickable(nsIFrame* aFrame, nsIAtom* stopAt = nullptr) nsGkAtoms::_true, eIgnoreCase) && content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote, nsGkAtoms::_true, eIgnoreCase)) { - return true; + return content; } // See nsCSSFrameConstructor::FindXULTagData. This code is not @@ -216,24 +244,24 @@ IsElementClickable(nsIFrame* aFrame, nsIAtom* stopAt = nullptr) nsGkAtoms::menulist, nsGkAtoms::scrollbarbutton, nsGkAtoms::resizer)) { - return true; + return content; } static nsIContent::AttrValuesArray clickableRoles[] = { &nsGkAtoms::button, &nsGkAtoms::key, nullptr }; if (content->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::role, clickableRoles, eIgnoreCase) >= 0) { - return true; + return content; } if (content->IsEditable()) { - return true; + return content; } nsCOMPtr linkURI; if (content->IsLink(getter_AddRefs(linkURI))) { - return true; + return content; } } - return false; + return nullptr; } static nscoord @@ -320,12 +348,44 @@ SubtractFromExposedRegion(nsRegion* aExposedRegion, const nsRegion& aRegion) } } +// Search in the list of frames aCandidates if the element with the id "aLabelTargetId" +// is present. +static bool IsElementPresent(nsTArray& aCandidates, const nsAutoString& aLabelTargetId) +{ + for (uint32_t i = 0; i < aCandidates.Length(); ++i) { + nsIFrame* f = aCandidates[i]; + nsIContent* aContent = f->GetContent(); + if (aContent && aContent->IsElement()) { + if (aContent->GetID() && aLabelTargetId == nsAtomString(aContent->GetID())) { + return true; + } + } + } + return false; +} + +static bool +IsLargeElement(nsIFrame* aFrame, const EventRadiusPrefs* aPrefs) +{ + uint32_t keepLimitSizeForCluster = aPrefs->mKeepLimitSizeForCluster; + nsSize frameSize = aFrame->GetSize(); + nsPresContext* pc = aFrame->PresContext(); + nsIPresShell* presShell = pc->PresShell(); + float cumulativeResolution = presShell->GetCumulativeResolution(); + if ((pc->AppUnitsToGfxUnits(frameSize.height) * cumulativeResolution) > keepLimitSizeForCluster && + (pc->AppUnitsToGfxUnits(frameSize.width) * cumulativeResolution) > keepLimitSizeForCluster) { + return true; + } + return false; +} + static nsIFrame* GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, const nsRect& aTargetRect, const EventRadiusPrefs* aPrefs, - nsIFrame* aRestrictToDescendants, nsTArray& aCandidates, - int32_t* aElementsInCluster) + nsIFrame* aRestrictToDescendants, nsIContent* aClickableAncestor, + nsTArray& aCandidates, int32_t* aElementsInCluster) { + std::vector mContentsInCluster; // List of content elements in the cluster without duplicate nsIFrame* bestTarget = nullptr; // Lower is better; distance is in appunits float bestDistance = 1e6f; @@ -339,7 +399,6 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, nsRect(nsPoint(0, 0), f->GetSize()), aRoot, &preservesAxisAlignedRectangles); nsRegion region; region.And(exposedRegion, borderBox); - if (region.IsEmpty()) { PET_LOG(" candidate %p had empty hit region\n", f); continue; @@ -351,7 +410,14 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, SubtractFromExposedRegion(&exposedRegion, region); } - if (!IsElementClickable(f, nsGkAtoms::body)) { + nsAutoString labelTargetId; + if (aClickableAncestor && !IsDescendant(f, aClickableAncestor, &labelTargetId)) { + PET_LOG(" candidate %p is not a descendant of required ancestor\n", f); + continue; + } + + nsIContent* clickableContent = GetClickableAncestor(f, nsGkAtoms::body, &labelTargetId); + if (!aClickableAncestor && !clickableContent) { PET_LOG(" candidate %p was not clickable\n", f); continue; } @@ -361,12 +427,21 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, PET_LOG(" candidate %p was ancestor for bestTarget %p\n", f, bestTarget); continue; } - if (!nsLayoutUtils::IsAncestorFrameCrossDoc(aRestrictToDescendants, f, aRoot)) { + if (!aClickableAncestor && !nsLayoutUtils::IsAncestorFrameCrossDoc(aRestrictToDescendants, f, aRoot)) { PET_LOG(" candidate %p was not descendant of restrictroot %p\n", f, aRestrictToDescendants); continue; } - (*aElementsInCluster)++; + // If the first clickable ancestor of f is a label element + // and "for" attribute is present in label element, search the frame list for the "for" element + // If this element is present in the current list, do not count the frame in + // the cluster elements counter + if ((labelTargetId.IsEmpty() || !IsElementPresent(aCandidates, labelTargetId)) && + !IsLargeElement(f, aPrefs)) { + if (std::find(mContentsInCluster.begin(), mContentsInCluster.end(), clickableContent) == mContentsInCluster.end()) { + mContentsInCluster.push_back(clickableContent); + } + } // distance is in appunits float distance = ComputeDistanceFromRegion(aPointRelativeToRootFrame, region); @@ -382,21 +457,29 @@ GetClosest(nsIFrame* aRoot, const nsPoint& aPointRelativeToRootFrame, bestTarget = f; } } + *aElementsInCluster = mContentsInCluster.size(); return bestTarget; } /* * Return always true when touch cluster detection is OFF. - * When cluster detection is ON, return true if the text inside - * the frame is readable (by human eyes): - * in this case, the frame is really clickable. - * Frames with a too small size will return false: - * in this case, the frame is considered not clickable. + * When cluster detection is ON, return true: + * if the text inside the frame is readable (by human eyes) + * or + * if the structure is too complex to determine the size. + * In both cases, the frame is considered as clickable. + * + * Frames with a too small size will return false. + * In this case, the frame is considered not clickable. */ static bool IsElementClickableAndReadable(nsIFrame* aFrame, WidgetGUIEvent* aEvent, const EventRadiusPrefs* aPrefs) { - if (!aPrefs->mTouchClusterDetection) { + if (!aPrefs->mTouchClusterDetectionEnabled) { + return true; + } + + if (aPrefs->mSimplifiedClusterDetection) { return true; } @@ -413,11 +496,38 @@ IsElementClickableAndReadable(nsIFrame* aFrame, WidgetGUIEvent* aEvent, const Ev (pc->AppUnitsToGfxUnits(frameSize.width) * cumulativeResolution) < limitReadableSize) { return false; } - RefPtr fm; - nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm), - nsLayoutUtils::FontSizeInflationFor(aFrame)); - if (fm) { - if ((pc->AppUnitsToGfxUnits(fm->EmHeight()) * cumulativeResolution) < limitReadableSize) { + // We want to detect small clickable text elements using the font size. + // Two common cases are supported for now: + // 1. text node + // 2. any element with only one child of type text node + // All the other cases are currently ignored. + nsIContent *content = aFrame->GetContent(); + bool testFontSize = false; + if (content) { + nsINodeList* childNodes = content->ChildNodes(); + uint32_t childNodeCount = childNodes->Length(); + if ((content->IsNodeOfType(nsINode::eTEXT)) || + // click occurs on the text inside or other clickable tags with text inside + + (childNodeCount == 1 && childNodes->Item(0) && + childNodes->Item(0)->IsNodeOfType(nsINode::eTEXT))) { + // The click occurs on an element with only one text node child. In this case, the font size + // can be tested. + // The number of child nodes is tested to avoid the following cases (See bug 1172488): + // Some jscript libraries transform text elements into Canvas elements but keep the text nodes + // with a very small size (1px) to handle the selection of text. + // With such libraries, the font size of the text elements is not relevant to detect small elements. + + testFontSize = true; + } + } + + if (testFontSize) { + RefPtr fm; + nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm), + nsLayoutUtils::FontSizeInflationFor(aFrame)); + if (fm && fm->EmHeight() > 0 && // See bug 1171731 + (pc->AppUnitsToGfxUnits(fm->EmHeight()) * cumulativeResolution) < limitReadableSize) { return false; } } @@ -445,12 +555,20 @@ FindFrameTargetedByInputEvent(WidgetGUIEvent* aEvent, PET_LOG("Retargeting disabled\n"); return target; } - if (target && IsElementClickable(target, nsGkAtoms::body)) { - if (!IsElementClickableAndReadable(target, aEvent, prefs)) { - aEvent->AsMouseEventBase()->hitCluster = true; + nsIContent* clickableAncestor = nullptr; + if (target) { + clickableAncestor = GetClickableAncestor(target, nsGkAtoms::body); + if (clickableAncestor) { + if (!IsElementClickableAndReadable(target, aEvent, prefs)) { + aEvent->AsMouseEventBase()->hitCluster = true; + } + PET_LOG("Target %p is clickable\n", target); + // If the target that was directly hit has a clickable ancestor, that + // means it too is clickable. And since it is the same as or a descendant + // of clickableAncestor, it should become the root for the GetClosest + // search. + clickableAncestor = target->GetContent(); } - PET_LOG("Target %p is clickable\n", target); - return target; } // Do not modify targeting for actual mouse hardware; only for mouse @@ -465,7 +583,7 @@ FindFrameTargetedByInputEvent(WidgetGUIEvent* aEvent, // If the exact target is non-null, only consider candidate targets in the same // document as the exact target. Otherwise, if an ancestor document has - // a mouse event handler for example, targets that are !IsElementClickable can + // a mouse event handler for example, targets that are !GetClickableAncestor can // never be targeted --- something nsSubDocumentFrame in an ancestor document // would be targeted instead. nsIFrame* restrictToDescendants = target ? @@ -485,9 +603,10 @@ FindFrameTargetedByInputEvent(WidgetGUIEvent* aEvent, nsIFrame* closestClickable = GetClosest(aRootFrame, aPointRelativeToRootFrame, targetRect, prefs, - restrictToDescendants, candidates, &elementsInCluster); + restrictToDescendants, clickableAncestor, candidates, + &elementsInCluster); if (closestClickable) { - if ((prefs->mTouchClusterDetection && elementsInCluster > 1) || + if ((prefs->mTouchClusterDetectionEnabled && elementsInCluster > 1) || (!IsElementClickableAndReadable(closestClickable, aEvent, prefs))) { if (aEvent->mClass == eMouseEventClass) { WidgetMouseEventBase* mouseEventBase = aEvent->AsMouseEventBase(); diff --git a/layout/base/UnitTransforms.h b/layout/base/UnitTransforms.h index dc803efb37..7f503a73d6 100644 --- a/layout/base/UnitTransforms.h +++ b/layout/base/UnitTransforms.h @@ -9,6 +9,7 @@ #include "Units.h" #include "mozilla/gfx/Matrix.h" +#include "nsRegion.h" namespace mozilla { @@ -78,6 +79,10 @@ template gfx::IntMarginTyped ViewAs(const gfx::IntMarginTyped& aMargin, PixelCastJustification) { return gfx::IntMarginTyped(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left); } +template +gfx::IntRegionTyped ViewAs(const gfx::IntRegionTyped& aRegion, PixelCastJustification) { + return gfx::IntRegionTyped::FromUnknownRegion(aRegion.ToUnknownRegion()); +} template gfx::ScaleFactor ViewTargetAs( const gfx::ScaleFactor& aScaleFactor, @@ -112,6 +117,10 @@ template gfx::IntRectTyped ViewAs(const nsIntRect& aRect) { return gfx::IntRectTyped(aRect.x, aRect.y, aRect.width, aRect.height); } +template +gfx::IntRegionTyped ViewAs(const nsIntRegion& aRegion) { + return gfx::IntRegionTyped::FromUnknownRegion(aRegion); +} // Convenience functions for transforming an entity from one strongly-typed // coordinate system to another using the provided transformation matrix. @@ -140,6 +149,12 @@ static gfx::IntRectTyped TransformTo(const gfx::Matrix4x4& aTransfo gfx::Rect rect(aRect.ToUnknownRect()); return RoundedToInt(ViewAs(aTransform.TransformBounds(rect))); } +template +static gfx::IntRegionTyped TransformTo(const gfx::Matrix4x4& aTransform, + const gfx::IntRegionTyped& aRegion) +{ + return ViewAs(aRegion.ToUnknownRegion().Transform(aTransform)); +} // Transform |aVector|, which is anchored at |aAnchor|, by the given transform // matrix, yielding a point in |TargetUnits|. diff --git a/layout/base/nsDisplayItemTypesList.h b/layout/base/nsDisplayItemTypesList.h index 41b4b540c8..5addec0aed 100644 --- a/layout/base/nsDisplayItemTypesList.h +++ b/layout/base/nsDisplayItemTypesList.h @@ -64,7 +64,8 @@ DECLARE_DISPLAY_ITEM_TYPE(TEXT) DECLARE_DISPLAY_ITEM_TYPE(TEXT_DECORATION) DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW) DECLARE_DISPLAY_ITEM_TYPE(TEXT_SHADOW) -DECLARE_DISPLAY_ITEM_TYPE(TRANSFORM) +DECLARE_DISPLAY_ITEM_TYPE_FLAGS(TRANSFORM,TYPE_RENDERS_NO_IMAGES) +DECLARE_DISPLAY_ITEM_TYPE_FLAGS(PERSPECTIVE,TYPE_RENDERS_NO_IMAGES) DECLARE_DISPLAY_ITEM_TYPE(VIDEO) DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST) DECLARE_DISPLAY_ITEM_TYPE(ZOOM) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 5e43841ec5..ed4aa32098 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -567,16 +567,6 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer, float scale = devPixelsToAppUnits; Point3D offsetToTransformOrigin = nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds); - Point3D offsetToPerspectiveOrigin = - nsDisplayTransform::GetDeltaToPerspectiveOrigin(aFrame, scale); - nscoord perspective = 0.0; - nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent(); - if (parentStyleContext) { - const nsStyleDisplay* disp = parentStyleContext->StyleDisplay(); - if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) { - perspective = disp->mChildPerspective.GetCoordValue(); - } - } nsPoint origin; if (aItem) { // This branch is for display items to leverage the cache of @@ -594,8 +584,7 @@ nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer, } data = TransformData(origin, offsetToTransformOrigin, - offsetToPerspectiveOrigin, bounds, perspective, - devPixelsToAppUnits); + bounds, devPixelsToAppUnits); } else if (aProperty == eCSSProperty_opacity) { data = null_t(); } @@ -631,6 +620,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID), mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID), mCurrentScrollbarFlags(0), + mPerspectiveItemIndex(0), mIsBuildingScrollbar(false), mCurrentScrollbarWillHaveLayer(false), mBuildCaret(aBuildCaret), @@ -5085,51 +5075,61 @@ nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, aAppUnitsPerPixel)); } -/* Returns the delta specified by the -moz-perspective-origin property. - * This is a positive delta, meaning that it indicates the direction to move - * to get from (0, 0) of the frame to the perspective origin. This function is - * called off the main thread. - */ -/* static */ Point3D -nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, - float aAppUnitsPerPixel) +/* static */ bool +nsDisplayTransform::ComputePerspectiveMatrix(const nsIFrame* aFrame, + float aAppUnitsPerPixel, + Matrix4x4& aOutMatrix) { NS_PRECONDITION(aFrame, "Can't get delta for a null frame!"); NS_PRECONDITION(aFrame->IsTransformed() || aFrame->StyleDisplay()->BackfaceIsHidden() || aFrame->Combines3DTransformWithAncestors(), "Shouldn't get a delta for an untransformed frame!"); + NS_PRECONDITION(aOutMatrix.IsIdentity(), "Must have a blank output matrix"); if (!aFrame->IsTransformed()) { - return Point3D(); + return false; } - /* For both of the coordinates, if the value of -moz-perspective-origin is a - * percentage, it's relative to the size of the frame. Otherwise, if it's - * a distance, it's already computed for us! + /* Find our containing block, which is the element that provides the + * value for perspective we need to use */ - //TODO: Should this be using our bounds or the parent's bounds? - // How do we handle aBoundsOverride in the latter case? + //TODO: Is it possible that the cbFrame's bounds haven't been set correctly yet + // (similar to the aBoundsOverride case for GetResultingTransformMatrix)? nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME); if (!cbFrame) { - return Point3D(); + return false; } - const nsStyleDisplay* display = cbFrame->StyleDisplay(); + + /* Grab the values for perspective and perspective-origin (if present) */ + + const nsStyleDisplay* cbDisplay = cbFrame->StyleDisplay(); + if (cbDisplay->mChildPerspective.GetUnit() != eStyleUnit_Coord) { + return false; + } + nscoord perspective = cbDisplay->mChildPerspective.GetCoordValue(); + if (perspective <= 0) { + return false; + } + TransformReferenceBox refBox(cbFrame); /* Allows us to access named variables by index. */ - Point3D result; - result.z = 0.0f; - gfx::Float* coords[2] = {&result.x, &result.y}; + Point3D perspectiveOrigin; + gfx::Float* coords[2] = {&perspectiveOrigin.x, &perspectiveOrigin.y}; TransformReferenceBox::DimensionGetter dimensionGetter[] = { &TransformReferenceBox::Width, &TransformReferenceBox::Height }; + /* For both of the coordinates, if the value of perspective-origin is a + * percentage, it's relative to the size of the frame. Otherwise, if it's + * a distance, it's already computed for us! + */ for (uint8_t index = 0; index < 2; ++index) { - /* If the transform-origin specifies a percentage, take the percentage + /* If the -transform-origin specifies a percentage, take the percentage * of the size of the box. */ - const nsStyleCoord &coord = display->mPerspectiveOrigin[index]; + const nsStyleCoord &coord = cbDisplay->mPerspectiveOrigin[index]; if (coord.GetUnit() == eStyleUnit_Calc) { const nsStyleCoord::Calc *calc = coord.GetCalcValue(); *coords[index] = @@ -5147,13 +5147,25 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, } } - nsPoint parentOffset = aFrame->GetOffsetTo(cbFrame); - Point3D gfxOffset( - NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel), - NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel), + /* GetOffsetTo computes the offset required to move from 0,0 in cbFrame to 0,0 + * in aFrame. Although we actually want the inverse of this, it's faster to + * compute this way. + */ + nsPoint frameToCbOffset = -aFrame->GetOffsetTo(cbFrame); + Point3D frameToCbGfxOffset( + NSAppUnitsToFloatPixels(frameToCbOffset.x, aAppUnitsPerPixel), + NSAppUnitsToFloatPixels(frameToCbOffset.y, aAppUnitsPerPixel), 0.0f); - return result - gfxOffset; + /* Move the perspective origin to be relative to aFrame, instead of relative + * to the containing block which is how it was specified in the style system. + */ + perspectiveOrigin += frameToCbGfxOffset; + + aOutMatrix._34 = + -1.0 / NSAppUnitsToFloatPixels(perspective, aAppUnitsPerPixel); + aOutMatrix.ChangeBasis(perspectiveOrigin); + return true; } nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame* aFrame, @@ -5162,20 +5174,7 @@ nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsI : mFrame(aFrame) , mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform) , mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride)) - , mChildPerspective(0) { - nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME); - if (cbFrame) { - const nsStyleDisplay* display = cbFrame->StyleDisplay(); - if (display->mChildPerspective.GetUnit() == eStyleUnit_Coord) { - mChildPerspective = display->mChildPerspective.GetCoordValue(); - // Calling GetDeltaToPerspectiveOrigin can be expensive, so we avoid - // calling it unnecessarily. - if (mChildPerspective > 0.0) { - mToPerspectiveOrigin = GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel); - } - } - } } /* Wraps up the transform matrix in a change-of-basis matrix pair that @@ -5219,6 +5218,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp nsIFrame** aOutAncestor) { const nsIFrame *frame = aProperties.mFrame; + NS_ASSERTION(frame || !(aFlags & INCLUDE_PERSPECTIVE), "Must have a frame to compute perspective!"); if (aOutAncestor) { *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(frame); @@ -5273,13 +5273,17 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y), 0); - bool hasPerspective = aProperties.mChildPerspective > 0.0; + Matrix4x4 perspectiveMatrix; + bool hasPerspective = aFlags & INCLUDE_PERSPECTIVE; + if (hasPerspective) { + hasPerspective = ComputePerspectiveMatrix(frame, aAppUnitsPerPixel, + perspectiveMatrix); + } if (!hasSVGTransforms || !hasTransformFromSVGParent) { // This is a simplification of the following |else| block, the // simplification being possible because we don't need to apply // mToTransformOrigin between two transforms. - Point3D offsets = roundedOrigin + aProperties.mToTransformOrigin; if ((aFlags & OFFSET_BY_ORIGIN) && !hasPerspective) { // We can fold the final translation by roundedOrigin into the first matrix @@ -5287,9 +5291,9 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp // insufficient floating point precision than reversing the translation // afterwards. result.PreTranslate(-aProperties.mToTransformOrigin); - result.PostTranslate(offsets); + result.PostTranslate(roundedOrigin + aProperties.mToTransformOrigin); } else { - result.ChangeBasis(offsets); + result.ChangeBasis(aProperties.mToTransformOrigin); } } else { Point3D refBoxOffset(NSAppUnitsToFloatPixels(refBox.X(), aAppUnitsPerPixel), @@ -5314,26 +5318,20 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp // Similar to the code in the |if| block above, but since we've accounted // for mToTransformOrigin so we don't include that. We also need to reapply // refBoxOffset. - Point3D offsets = roundedOrigin + refBoxOffset; if ((aFlags & OFFSET_BY_ORIGIN) && !hasPerspective) { result.PreTranslate(-refBoxOffset); - result.PostTranslate(offsets); + result.PostTranslate(roundedOrigin + refBoxOffset); } else { - result.ChangeBasis(offsets); + result.ChangeBasis(refBoxOffset); } } if (hasPerspective) { - Matrix4x4 perspective; - perspective._34 = - -1.0 / NSAppUnitsToFloatPixels(aProperties.mChildPerspective, aAppUnitsPerPixel); - - perspective.ChangeBasis(aProperties.GetToPerspectiveOrigin() + roundedOrigin); - result = result * perspective; + result = result * perspectiveMatrix; if (aFlags & OFFSET_BY_ORIGIN) { - result.PreTranslate(roundedOrigin); + result.PostTranslate(roundedOrigin); } } @@ -5352,7 +5350,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp // then we're not a reference frame so no offset to origin will be added. Our // parent transform however *is* the reference frame, so we pass // OFFSET_BY_ORIGIN to convert into the correct coordinate space. - uint32_t flags = aFlags & (INCLUDE_PRESERVE3D_ANCESTORS); + uint32_t flags = aFlags & (INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE); if (!frame->IsTransformed()) { flags |= OFFSET_BY_ORIGIN; } @@ -5504,7 +5502,7 @@ nsDisplayTransform::GetTransform() bool isReference = mFrame->IsTransformed() || mFrame->Combines3DTransformWithAncestors() || mFrame->Extend3DContext(); - uint32_t flags = 0; + uint32_t flags = INCLUDE_PERSPECTIVE; if (isReference) { flags |= OFFSET_BY_ORIGIN; } @@ -5515,6 +5513,20 @@ nsDisplayTransform::GetTransform() return mTransform; } +Matrix4x4 +nsDisplayTransform::GetTransformForRendering() +{ + if (!mFrame->HasPerspective() || mTransformGetter || mIsTransformSeparator) { + return GetTransform(); + } + MOZ_ASSERT(!mTransformGetter); + + float scale = mFrame->PresContext()->AppUnitsPerDevPixel(); + // Don't include perspective transform, or the offset to origin, since + // nsDisplayPerspective will handle both of those. + return GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale, 0); +} + const Matrix4x4& nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBuilder) { @@ -5538,7 +5550,7 @@ nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBu nsPoint offset = mFrame->GetOffsetToCrossDoc(establisherReference); float scale = mFrame->PresContext()->AppUnitsPerDevPixel(); - uint32_t flags = INCLUDE_PRESERVE3D_ANCESTORS|OFFSET_BY_ORIGIN; + uint32_t flags = INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN; mTransformPreserves3D = GetResultingTransformMatrix(mFrame, offset, scale, flags); } @@ -5562,7 +5574,7 @@ already_AddRefed nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu * backface hidden here. But, it would be removed by the init * function of nsDisplayTransform. */ - const Matrix4x4& newTransformMatrix = GetTransform(); + const Matrix4x4& newTransformMatrix = GetTransformForRendering(); uint32_t flags = ShouldPrerender(aBuilder) ? FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0; @@ -5967,7 +5979,7 @@ nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds, float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); - uint32_t flags = 0; + uint32_t flags = INCLUDE_PERSPECTIVE; if (aPreserves3D) { flags |= INCLUDE_PRESERVE3D_ANCESTORS; } @@ -5988,7 +6000,7 @@ bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds, float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); - uint32_t flags = 0; + uint32_t flags = INCLUDE_PERSPECTIVE; if (aPreserves3D) { flags |= INCLUDE_PRESERVE3D_ANCESTORS; } @@ -6048,6 +6060,71 @@ nsDisplayTransform::WriteDebugInfo(std::stringstream& aStream) AppendToString(aStream, GetTransform()); } +nsDisplayPerspective::nsDisplayPerspective(nsDisplayListBuilder* aBuilder, + nsIFrame* aTransformFrame, + nsIFrame* aPerspectiveFrame, + nsDisplayList* aList) + : nsDisplayItem(aBuilder, aPerspectiveFrame) + , mList(aBuilder, aPerspectiveFrame, aList) + , mTransformFrame(aTransformFrame) + , mIndex(aBuilder->AllocatePerspectiveItemIndex()) +{} + +already_AddRefed +nsDisplayPerspective::BuildLayer(nsDisplayListBuilder *aBuilder, + LayerManager *aManager, + const ContainerLayerParameters& aContainerParameters) +{ + float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); + + Matrix4x4 perspectiveMatrix; + DebugOnly hasPerspective = + nsDisplayTransform::ComputePerspectiveMatrix(mTransformFrame, appUnitsPerPixel, + perspectiveMatrix); + MOZ_ASSERT(hasPerspective, "Why did we create nsDisplayPerspective?"); + + /* + * The resulting matrix is still in the coordinate space of the transformed + * frame. Append a translation to the reference frame coordinates. + */ + nsDisplayTransform* transform = + static_cast(mList.GetChildren()->GetTop()); + + Point3D newOrigin = + Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x, appUnitsPerPixel), + NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y, appUnitsPerPixel), + 0.0f); + Point3D roundedOrigin(NS_round(newOrigin.x), + NS_round(newOrigin.y), + 0); + + perspectiveMatrix.PostTranslate(roundedOrigin); + + RefPtr container = aManager->GetLayerBuilder()-> + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList.GetChildren(), + aContainerParameters, &perspectiveMatrix, 0); + + if (!container) { + return nullptr; + } + + // Sort of a lie, but we want to pretend that the perspective layer extends a 3d context + // so that it gets its transform combined with children. Might need a better name that reflects + // this use case and isn't specific to preserve-3d. + container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_EXTEND_3D_CONTEXT); + container->SetTransformIsPerspective(true); + + return container.forget(); +} + +LayerState +nsDisplayPerspective::GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) +{ + return LAYER_ACTIVE; +} + nsDisplayItemGeometry* nsCharClipDisplayItem::AllocateGeometry(nsDisplayListBuilder* aBuilder) { diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 78d152a006..3e8722a259 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -743,6 +743,32 @@ public: bool mOldValue; }; + class AutoSaveRestorePerspectiveIndex; + friend class AutoSaveRestorePerspectiveIndex; + class AutoSaveRestorePerspectiveIndex { + public: + AutoSaveRestorePerspectiveIndex(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) + : mBuilder(nullptr) + { + if (aFrame->ChildrenHavePerspective()) { + mBuilder = aBuilder; + mCachedItemIndex = aBuilder->mPerspectiveItemIndex; + aBuilder->mPerspectiveItemIndex = 0; + } + } + + ~AutoSaveRestorePerspectiveIndex() + { + if (mBuilder) { + mBuilder->mPerspectiveItemIndex = mCachedItemIndex; + } + } + + private: + nsDisplayListBuilder* mBuilder; + uint32_t mCachedItemIndex; + }; + /** * A helper class to temporarily set the value of mCurrentScrollParentId. */ @@ -995,6 +1021,8 @@ public: return mContainedBlendModes; } + uint32_t AllocatePerspectiveItemIndex() { return mPerspectiveItemIndex++; } + DisplayListClipState& ClipState() { return mClipState; } /** @@ -1199,6 +1227,7 @@ private: uint32_t mCurrentScrollbarFlags; BlendModeSet mContainedBlendModes; Preserves3DContext mPreserves3DCtx; + uint32_t mPerspectiveItemIndex; bool mIsBuildingScrollbar; bool mCurrentScrollbarWillHaveLayer; bool mBuildCaret; @@ -3818,7 +3847,15 @@ public: INDEX_MAX = UINT32_MAX >> nsDisplayItem::TYPE_BITS }; + /** + * We include the perspective matrix from our containing block for the + * purposes of visibility calculations, but we exclude it from the transform + * we set on the layer (for rendering), since there will be an + * nsDisplayPerspective created for that. + */ const Matrix4x4& GetTransform(); + Matrix4x4 GetTransformForRendering(); + /** * Return the transform that is aggregation of all transform on the * preserves3d chain. @@ -3868,8 +3905,18 @@ public: float aAppUnitsPerPixel, const nsRect* aBoundsOverride); - static Point3D GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, - float aAppUnitsPerPixel); + /* + * Returns true if aFrame has perspective applied from its containing + * block. + * Returns the matrix to append to apply the persective (taking + * perspective-origin into account), relative to aFrames coordinate + * space). + * aOutMatrix is assumed to be the identity matrix, and isn't explicitly + * cleared. + */ + static bool ComputePerspectiveMatrix(const nsIFrame* aFrame, + float aAppUnitsPerPixel, + Matrix4x4& aOutMatrix); struct FrameTransformProperties { @@ -3877,30 +3924,15 @@ public: float aAppUnitsPerPixel, const nsRect* aBoundsOverride); FrameTransformProperties(nsCSSValueSharedList* aTransformList, - const Point3D& aToTransformOrigin, - const Point3D& aToPerspectiveOrigin, - nscoord aChildPerspective) + const Point3D& aToTransformOrigin) : mFrame(nullptr) , mTransformList(aTransformList) , mToTransformOrigin(aToTransformOrigin) - , mChildPerspective(aChildPerspective) - , mToPerspectiveOrigin(aToPerspectiveOrigin) {} - const Point3D& GetToPerspectiveOrigin() const - { - MOZ_ASSERT(mChildPerspective > 0, "Only valid with mChildPerspective > 0"); - return mToPerspectiveOrigin; - } - const nsIFrame* mFrame; RefPtr mTransformList; const Point3D mToTransformOrigin; - nscoord mChildPerspective; - - private: - // mToPerspectiveOrigin is only valid if mChildPerspective > 0. - Point3D mToPerspectiveOrigin; }; /** @@ -3920,10 +3952,13 @@ public: * @param aFlags INCLUDE_PRESERVE3D_ANCESTORS The computed transform will * include the transform of any ancestors participating in the same * 3d rendering context. + * @param aFlags INCLUDE_PERSPECTIVE The resulting matrix will include the + * perspective transform from the containing block if applicable. */ enum { OFFSET_BY_ORIGIN = 1 << 0, INCLUDE_PRESERVE3D_ANCESTORS = 1 << 1, + INCLUDE_PERSPECTIVE = 1 << 2, }; static Matrix4x4 GetResultingTransformMatrix(const nsIFrame* aFrame, const nsPoint& aOrigin, @@ -4049,6 +4084,85 @@ private: bool mTransformPreserves3DInited; }; +/* A display item that applies a perspective transformation to a single + * nsDisplayTransform child item. We keep this as a separate item since the + * perspective-origin is relative to an ancestor of the transformed frame, and + * APZ can scroll the child separately. + */ +class nsDisplayPerspective : public nsDisplayItem +{ + typedef mozilla::gfx::Point3D Point3D; + +public: + NS_DISPLAY_DECL_NAME("nsDisplayPerspective", TYPE_PERSPECTIVE) + + nsDisplayPerspective(nsDisplayListBuilder* aBuilder, nsIFrame* aTransformFrame, + nsIFrame* aPerspectiveFrame, + nsDisplayList* aList); + + virtual uint32_t GetPerFrameKey() override { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); } + + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, + HitTestState* aState, nsTArray *aOutFrames) override + { + return mList.HitTest(aBuilder, aRect, aState, aOutFrames); + } + + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override + { + return mList.GetBounds(aBuilder, aSnap); + } + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) override + {} + + virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, + bool* aSnap) override + { + return mList.GetOpaqueRegion(aBuilder, aSnap); + } + + virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) override + { + return mList.IsUniform(aBuilder, aColor); + } + + virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) override; + + virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) override + { + return mList.ShouldBuildLayerEvenIfInvisible(aBuilder); + } + + virtual already_AddRefed BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) override; + + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) override + { + mList.RecomputeVisibility(aBuilder, aVisibleRegion); + return true; + } + virtual nsDisplayList* GetSameCoordinateSystemChildren() override { return mList.GetChildren(); } + virtual nsDisplayList* GetChildren() override { return mList.GetChildren(); } + virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override + { + return mList.GetComponentAlphaBounds(aBuilder); + } + + nsIFrame* TransformFrame() { return mTransformFrame; } + +private: + nsDisplayWrapList mList; + nsIFrame* mTransformFrame; + uint32_t mIndex; +}; + /** * This class adds basic support for limiting the rendering (in the inline axis * of the writing mode) to the part inside the specified edges. It's a base diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 8de36c361d..9f8baccc5a 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -8498,18 +8498,6 @@ nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell) return false; } -/* static */ float -nsLayoutUtils::GetResolution(nsIPresShell* aPresShell) -{ - return aPresShell->GetResolution(); -} - -/* static */ void -nsLayoutUtils::SetResolutionAndScaleTo(nsIPresShell* aPresShell, float aResolution) -{ - aPresShell->SetResolutionAndScaleTo(aResolution); -} - static void MaybeReflowForInflationScreenSizeChange(nsPresContext *aPresContext) { diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index cfd0bd0e14..85864a3147 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2724,19 +2724,6 @@ public: static bool HasDocumentLevelListenersForApzAwareEvents(nsIPresShell* aShell); - /** - * Get the resolution at which rescalable web content is drawn - * (see nsIDOMWindowUtils.getResolution). - */ - static float GetResolution(nsIPresShell* aPresShell); - - /** - * Set the resolution at which rescalable web content is drawn, - * and scales the content by the amount of the resolution - * (see nsIDOMWindowUtils.setResolutionAndScaleTo). - */ - static void SetResolutionAndScaleTo(nsIPresShell* aPresShell, float aResolution); - /** * Set the scroll port size for the purpose of clamping the scroll position * for the root scroll frame of this document diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 2853adaaa7..f2dc13c64b 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2505,7 +2505,7 @@ nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer, return; } - nsIntPoint topLeft = aContainer->GetVisibleRegion().GetBounds().TopLeft(); + nsIntPoint topLeft = aContainer->GetVisibleRegion().ToUnknownRegion().GetBounds().TopLeft(); nsIntRegionRectIterator iter(aRegion); while (const nsIntRect* r = iter.Next()) { diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 15c41ca844..7298742ab6 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -6154,7 +6154,7 @@ PresShell::Paint(nsView* aViewToPaint, pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel()); bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor); root->SetColor(Color::FromABGR(bgcolor)); - root->SetVisibleRegion(bounds); + root->SetVisibleRegion(LayerIntRegion::FromUnknownRegion(bounds)); layerManager->SetRoot(root); } MaybeSetupTransactionIdAllocator(layerManager, aViewToPaint); diff --git a/layout/base/tests/test_event_target_radius.html b/layout/base/tests/test_event_target_radius.html index c251c1a437..fd78029d06 100644 --- a/layout/base/tests/test_event_target_radius.html +++ b/layout/base/tests/test_event_target_radius.html @@ -38,8 +38,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=780847 + @@ -187,13 +189,30 @@ function test3() { // Test behavior of nested elements. // The following behaviors are questionable and may need to be changed. setShowing("t6", true); + setShowing("t6_outer", true); testMouseClick("t6_inner", -1, 10, "t6_inner", "inner element is clickable because its parent is, even when it sticks outside parent"); - testMouseClick("t6_inner", 19, -1, "t6_inner", + testMouseClick("t6_inner", 39, -1, "t6_inner", "when outside both inner and parent, but in range of both, the inner is selected"); - testMouseClick("t6_inner", 25, -1, "t6", - "clicking in clickable parent close to inner activates parent, not inner"); + testMouseClick("t6_inner", 45, -1, "t6_inner", + "clicking in clickable parent close to inner activates inner, not parent"); + testMouseClick("t6_inner_clickable", 1, -1, "t6_inner", + "clicking on inner doesn't get redirected to inner_clickable because they are both clickable"); + testMouseClick("t6_inner_clickable", 1, 1, "t6_inner_clickable", + "clicking on inner_clickable doesn't get redirected to inner because they are both clickable"); + testMouseClick("t6_inner_clickable", 45, -1, "t6_inner", + "clicking on inner while backed by its parent still doesn't get redirected to inner_clickable"); + testMouseClick("t6_inner_clickable", 45, 1, "t6_inner_clickable", + "clicking on inner_clickable while backed by its parent still doesn't get redirected to inner"); + testMouseClick("t6_inner_clickable", 45, 6, "t6_inner_clickable", + "clicking on parent near inner_clickable gets redirected to inner_clickable rather than inner because it is closer"); + ok(13*mm < 80, "no point inside t6 that's not within radius of t6_inner; adjust layout of t6/inner/outer as needed"); + testMouseClick("t6_outer", -40 + 13*mm, -1, "t6", + "clicking in clickable container close to outer activates parent, not outer"); + testMouseClick("t6_outer", 1, 1, "t6_outer", + "clicking directly on the outer activates it"); setShowing("t6", false); + setShowing("t6_outer", false); setShowing("t7", true); setShowing("t7_over", true); diff --git a/layout/forms/nsFormControlFrame.cpp b/layout/forms/nsFormControlFrame.cpp index 2e42ccdaaa..464ed40a28 100644 --- a/layout/forms/nsFormControlFrame.cpp +++ b/layout/forms/nsFormControlFrame.cpp @@ -44,8 +44,6 @@ NS_QUERYFRAME_HEAD(nsFormControlFrame) NS_QUERYFRAME_ENTRY(nsIFormControlFrame) NS_QUERYFRAME_TAIL_INHERITING(nsLeafFrame) -NS_IMPL_FRAMEARENA_HELPERS(nsFormControlFrame) - nscoord nsFormControlFrame::GetIntrinsicISize() { diff --git a/layout/forms/nsFormControlFrame.h b/layout/forms/nsFormControlFrame.h index 4c57b2b77a..b3f2bece0c 100644 --- a/layout/forms/nsFormControlFrame.h +++ b/layout/forms/nsFormControlFrame.h @@ -35,7 +35,7 @@ public: } NS_DECL_QUERYFRAME - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsFormControlFrame) /** * Respond to a gui event diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 930345002a..2dcba6521c 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -42,8 +42,6 @@ using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::layout; -NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame) - nsContainerFrame::~nsContainerFrame() { } diff --git a/layout/generic/nsContainerFrame.h b/layout/generic/nsContainerFrame.h index 54f45daad2..6438d34765 100644 --- a/layout/generic/nsContainerFrame.h +++ b/layout/generic/nsContainerFrame.h @@ -44,7 +44,7 @@ class FramePropertyTable; class nsContainerFrame : public nsSplittableFrame { public: - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsContainerFrame) NS_DECL_QUERYFRAME_TARGET(nsContainerFrame) NS_DECL_QUERYFRAME diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 30162d5904..079795cd84 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -61,6 +61,7 @@ #include "nsBidiPresUtils.h" #include "RubyUtils.h" +#include "nsAnimationManager.h" // For triple-click pref #include "imgIContainer.h" @@ -686,7 +687,7 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) } } - if (nsLayoutUtils::HasCurrentAnimations(static_cast(this))) { + if (HasCSSAnimations()) { // If no new frame for this element is created by the end of the // restyling process, stop animations for this frame RestyleManager::AnimationsWithDestroyedFrame* adf = @@ -1905,7 +1906,7 @@ CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) * True if aDescendant participates the context aAncestor participating. */ static bool -Participate3DContextFrame(nsIFrame* aAncestor, nsIFrame* aDescendant) { +FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) { MOZ_ASSERT(aAncestor != aDescendant); MOZ_ASSERT(aAncestor->Extend3DContext()); nsIFrame* frame; @@ -1920,6 +1921,20 @@ Participate3DContextFrame(nsIFrame* aAncestor, nsIFrame* aDescendant) { return true; } +static bool +ItemParticipatesIn3DContext(nsIFrame* aAncestor, nsDisplayItem* aItem) +{ + nsIFrame* transformFrame; + if (aItem->GetType() == nsDisplayItem::TYPE_TRANSFORM) { + transformFrame = aItem->Frame(); + } else if (aItem->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) { + transformFrame = static_cast(aItem)->TransformFrame(); + } else { + return false; + } + return FrameParticipatesIn3DContext(aAncestor, transformFrame); +} + static void WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsRect& aDirtyRect, @@ -2045,6 +2060,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, DisplayListClipState::AutoSaveRestore clipState(aBuilder); + nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex perspectiveIndex(aBuilder, this); + if (isTransformed || useBlendMode || usingSVGEffects || useStickyPosition) { // We don't need to pass ancestor clipping down to our children; // everything goes inside a display item's child list, and the display @@ -2200,8 +2217,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, int index = 1; while (nsDisplayItem* item = resultList.RemoveBottom()) { - if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM && - Participate3DContextFrame(this, item->Frame())) { + if (ItemParticipatesIn3DContext(this, item)) { // The frame of this item participates the same 3D context. WrapSeparatorTransform(aBuilder, this, dirtyRect, &nonparticipants, &participants, index++); @@ -2223,7 +2239,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, } // Restore clip state now so nsDisplayTransform is clipped properly. - clipState.Restore(); + if (!HasPerspective()) { + clipState.Restore(); + } // Revert to the dirtyrect coming in from the parent, without our transform // taken into account. buildingDisplayList.SetDirtyRect(dirtyRectOutsideTransform); @@ -2238,6 +2256,15 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, nsDisplayTransform *transformItem = new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList, dirtyRect); resultList.AppendNewToTop(transformItem); + + if (HasPerspective()) { + clipState.Restore(); + resultList.AppendNewToTop( + new (aBuilder) nsDisplayPerspective( + aBuilder, this, + GetContainingBlock()->GetContent()->GetPrimaryFrame(), &resultList)); + } + } /* If we're doing VR rendering, then we need to wrap everything in a nsDisplayVR @@ -2297,7 +2324,8 @@ WrapInWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList) { nsDisplayItem* item = aList->GetBottom(); - if (!item || item->GetAbove() || item->Frame() != aFrame) { + if (!item || item->GetAbove() || + (item->Frame() != aFrame && item->GetType() != nsDisplayItem::TYPE_PERSPECTIVE)) { return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList); } aList->RemoveBottom(); @@ -5038,7 +5066,7 @@ nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor, int32_t scaleFactor = PresContext()->AppUnitsPerDevPixel(); Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this, - nsPoint(0, 0), scaleFactor, 0, + nsPoint(0, 0), scaleFactor, nsDisplayTransform::INCLUDE_PERSPECTIVE, nullptr, aOutAncestor); // XXXjwatt: seems like this will double count offsets in the face of preserve-3d: nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor); @@ -7479,6 +7507,7 @@ UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform, nsIAtom* fType = aFrame->GetType(); if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) || fType == nsGkAtoms::scrollFrame || + fType == nsGkAtoms::listControlFrame || fType == nsGkAtoms::svgOuterSVGFrame) { return u; } @@ -9059,6 +9088,14 @@ nsIFrame::CaretPosition::~CaretPosition() { } +bool +nsFrame::HasCSSAnimations() +{ + AnimationCollection* collection = + PresContext()->AnimationManager()->GetAnimationCollection(this); + return collection && collection->mAnimations.Length() > 0; +} + // Box layout debugging #ifdef DEBUG_REFLOW int32_t gIndent2 = 0; diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index a890148f58..a268f7ace7 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -78,11 +78,14 @@ #define NS_FRAME_TRACE_REFLOW_OUT(_method, _status) #endif -// Frame allocation boilerplate macros. Every subclass of nsFrame -// must define its own operator new and GetAllocatedSize. If they do -// not, the per-frame recycler lists in nsPresArena will not work -// correctly, with potentially catastrophic consequences (not enough -// memory is allocated for a frame object). +// Frame allocation boilerplate macros. Every subclass of nsFrame must +// either use NS_{DECL,IMPL}_FRAMEARENA_HELPERS pair for allocating +// memory correctly, or use NS_DECL_ABSTRACT_FRAME to declare a frame +// class abstract and stop it from being instantiated. If a frame class +// without its own operator new and GetFrameId gets instantiated, the +// per-frame recycler lists in nsPresArena will not work correctly, +// with potentially catastrophic consequences (not enough memory is +// allocated for a frame object). #define NS_DECL_FRAMEARENA_HELPERS \ void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE; \ @@ -94,6 +97,10 @@ nsQueryFrame::FrameIID class::GetFrameId() \ { return nsQueryFrame::class##_id; } +#define NS_DECL_ABSTRACT_FRAME(class) \ + void* operator new(size_t, nsIPresShell*) MOZ_MUST_OVERRIDE = delete; \ + virtual nsQueryFrame::FrameIID GetFrameId() override MOZ_MUST_OVERRIDE = 0; + //---------------------------------------------------------------------- struct nsBoxLayoutMetrics; @@ -582,8 +589,10 @@ public: static bool ShouldApplyOverflowClipping(const nsIFrame* aFrame, const nsStyleDisplay* aDisp) { - // clip overflow:-moz-hidden-unscrollable ... - if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP)) { + // clip overflow:-moz-hidden-unscrollable, except for nsListControlFrame, + // which is an nsHTMLScrollFrame. + if (MOZ_UNLIKELY(aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP && + aFrame->GetType() != nsGkAtoms::listControlFrame)) { return true; } @@ -667,6 +676,9 @@ private: NS_IMETHODIMP RefreshSizeCache(nsBoxLayoutState& aState); + // Returns true if this frame has any kind of CSS animations. + bool HasCSSAnimations(); + #ifdef DEBUG_FRAME_DUMP public: /** diff --git a/layout/generic/nsLeafFrame.cpp b/layout/generic/nsLeafFrame.cpp index bd30b5cb84..1650852054 100644 --- a/layout/generic/nsLeafFrame.cpp +++ b/layout/generic/nsLeafFrame.cpp @@ -14,8 +14,6 @@ nsLeafFrame::~nsLeafFrame() { } -NS_IMPL_FRAMEARENA_HELPERS(nsLeafFrame) - /* virtual */ nscoord nsLeafFrame::GetMinISize(nsRenderingContext *aRenderingContext) { diff --git a/layout/generic/nsLeafFrame.h b/layout/generic/nsLeafFrame.h index 5c8b69088b..57606b9e0e 100644 --- a/layout/generic/nsLeafFrame.h +++ b/layout/generic/nsLeafFrame.h @@ -20,7 +20,7 @@ */ class nsLeafFrame : public nsFrame { public: - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsLeafFrame) // nsIFrame replacements virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, diff --git a/layout/generic/nsRubyContentFrame.cpp b/layout/generic/nsRubyContentFrame.cpp index 12f9bc9c77..ce806553c0 100644 --- a/layout/generic/nsRubyContentFrame.cpp +++ b/layout/generic/nsRubyContentFrame.cpp @@ -15,13 +15,6 @@ using namespace mozilla; //---------------------------------------------------------------------- -// Frame class boilerplate -// ======================= - -NS_IMPL_FRAMEARENA_HELPERS(nsRubyContentFrame) - -//---------------------------------------------------------------------- - // nsRubyContentFrame Method Implementations // ====================================== diff --git a/layout/generic/nsRubyContentFrame.h b/layout/generic/nsRubyContentFrame.h index 1a2b47e7ec..b33e6b0993 100644 --- a/layout/generic/nsRubyContentFrame.h +++ b/layout/generic/nsRubyContentFrame.h @@ -16,7 +16,7 @@ typedef nsInlineFrame nsRubyContentFrameSuper; class nsRubyContentFrame : public nsRubyContentFrameSuper { public: - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsRubyContentFrame) // nsIFrame overrides virtual bool IsFrameOfType(uint32_t aFlags) const override; diff --git a/layout/generic/nsSplittableFrame.cpp b/layout/generic/nsSplittableFrame.cpp index 7e018322b9..eb2331d346 100644 --- a/layout/generic/nsSplittableFrame.cpp +++ b/layout/generic/nsSplittableFrame.cpp @@ -14,8 +14,6 @@ using namespace mozilla; -NS_IMPL_FRAMEARENA_HELPERS(nsSplittableFrame) - void nsSplittableFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, diff --git a/layout/generic/nsSplittableFrame.h b/layout/generic/nsSplittableFrame.h index 634f05eccb..9a12a33e84 100644 --- a/layout/generic/nsSplittableFrame.h +++ b/layout/generic/nsSplittableFrame.h @@ -18,7 +18,7 @@ class nsSplittableFrame : public nsFrame { public: - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsSplittableFrame) virtual void Init(nsIContent* aContent, nsContainerFrame* aParent, diff --git a/layout/mathml/nsMathMLContainerFrame.cpp b/layout/mathml/nsMathMLContainerFrame.cpp index f3570d4859..96bad76c91 100644 --- a/layout/mathml/nsMathMLContainerFrame.cpp +++ b/layout/mathml/nsMathMLContainerFrame.cpp @@ -30,8 +30,6 @@ using namespace mozilla::gfx; // nsMathMLContainerFrame implementation // -NS_IMPL_FRAMEARENA_HELPERS(nsMathMLContainerFrame) - NS_QUERYFRAME_HEAD(nsMathMLContainerFrame) NS_QUERYFRAME_ENTRY(nsIMathMLFrame) NS_QUERYFRAME_ENTRY(nsMathMLContainerFrame) diff --git a/layout/mathml/nsMathMLContainerFrame.h b/layout/mathml/nsMathMLContainerFrame.h index 2555b0470a..27f5b23ee2 100644 --- a/layout/mathml/nsMathMLContainerFrame.h +++ b/layout/mathml/nsMathMLContainerFrame.h @@ -35,7 +35,7 @@ public: NS_DECL_QUERYFRAME_TARGET(nsMathMLContainerFrame) NS_DECL_QUERYFRAME - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsMathMLContainerFrame) // -------------------------------------------------------------------------- // Overloaded nsMathMLFrame methods -- see documentation in nsIMathMLFrame.h diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list index 0cfd6c8ff5..3c944a6bd1 100644 --- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -3,9 +3,8 @@ skip-if(B2G||Mulet) == ellipsis-font-fallback.html ellipsis-font-fallback-ref.ht fuzzy-if(Android,16,244) skip-if(B2G||Mulet) HTTP(..) == marker-basic.html marker-basic-ref.html # Bug 1128229 # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) HTTP(..) == marker-string.html marker-string-ref.html # Initial mulet triage: parity with B2G/B2G Desktop skip-if(Android||B2G) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing -skip-if(!gtkWidget) fuzzy-if(gtkWidget,1,104) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing -skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,9,2545) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1770) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop -fuzzy-if(OSX==1008,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html +skip-if(!gtkWidget) fuzzy-if(gtkWidget,2,289) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing +skip-if(B2G||Mulet) fuzzy-if(Android&&AndroidVersion<15,206,41) fuzzy-if(Android&&AndroidVersion>=15,24,4000) fuzzy-if(cocoaWidget,1,40) fuzzy-if(asyncPan&&!layersGPUAccelerated,102,1770) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 # Initial mulet triage: parity with B2G/B2G Desktop fuzzy-if(OSX==1008,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html skip-if(B2G||Mulet) HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html # Initial mulet triage: parity with B2G/B2G Desktop HTTP(..) == visibility-hidden.html visibility-hidden-ref.html diff --git a/layout/style/ImageLoader.cpp b/layout/style/ImageLoader.cpp index 37e3709f4a..30d08494c5 100644 --- a/layout/style/ImageLoader.cpp +++ b/layout/style/ImageLoader.cpp @@ -343,6 +343,10 @@ void InvalidateImagesCallback(nsIFrame* aFrame, return; } + if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { + printf_stderr("Invalidating display item(type=%d) based on frame %p \ + because it might contain an invalidated image\n", type, aFrame); + } aItem->Invalidate(); aFrame->SchedulePaint(); diff --git a/layout/svg/moz.build b/layout/svg/moz.build index 5fba8a3c82..a59e8f0e2b 100644 --- a/layout/svg/moz.build +++ b/layout/svg/moz.build @@ -36,7 +36,6 @@ UNIFIED_SOURCES += [ 'nsSVGMarkerFrame.cpp', 'nsSVGMaskFrame.cpp', 'nsSVGOuterSVGFrame.cpp', - 'nsSVGPaintServerFrame.cpp', 'nsSVGPathGeometryFrame.cpp', 'nsSVGPatternFrame.cpp', 'nsSVGStopFrame.cpp', diff --git a/layout/svg/nsSVGGradientFrame.cpp b/layout/svg/nsSVGGradientFrame.cpp index e2ea80835c..8de01d5a50 100644 --- a/layout/svg/nsSVGGradientFrame.cpp +++ b/layout/svg/nsSVGGradientFrame.cpp @@ -55,8 +55,6 @@ nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext) : { } -NS_IMPL_FRAMEARENA_HELPERS(nsSVGGradientFrame) - //---------------------------------------------------------------------- // nsIFrame methods: diff --git a/layout/svg/nsSVGGradientFrame.h b/layout/svg/nsSVGGradientFrame.h index 591b83089b..8e6eba9766 100644 --- a/layout/svg/nsSVGGradientFrame.h +++ b/layout/svg/nsSVGGradientFrame.h @@ -45,7 +45,7 @@ protected: explicit nsSVGGradientFrame(nsStyleContext* aContext); public: - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsSVGGradientFrame) // nsSVGPaintServerFrame methods: virtual already_AddRefed diff --git a/layout/svg/nsSVGPaintServerFrame.cpp b/layout/svg/nsSVGPaintServerFrame.cpp deleted file mode 100644 index b065c2864b..0000000000 --- a/layout/svg/nsSVGPaintServerFrame.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -// Main header first: -#include "nsSVGPaintServerFrame.h" - -// Keep others in (case-insensitive) order: -#include "gfxContext.h" -#include "nsSVGElement.h" - -NS_IMPL_FRAMEARENA_HELPERS(nsSVGPaintServerFrame) diff --git a/layout/svg/nsSVGPaintServerFrame.h b/layout/svg/nsSVGPaintServerFrame.h index bf0006b3bc..caf6a82164 100644 --- a/layout/svg/nsSVGPaintServerFrame.h +++ b/layout/svg/nsSVGPaintServerFrame.h @@ -40,7 +40,7 @@ protected: } public: - NS_DECL_FRAMEARENA_HELPERS + NS_DECL_ABSTRACT_FRAME(nsSVGPaintServerFrame) /** * Constructs a gfxPattern of the paint server rendering. diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index d2f88a2e6f..cb06e3c037 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4624,6 +4624,11 @@ pref("layers.tiles.edge-padding", false); #endif +#ifdef MOZ_WIDGET_ANDROID +pref("layers.tiled-drawtarget.enabled", true); +pref("layers.tiles.edge-padding", true); +#endif + // same effect as layers.offmainthreadcomposition.enabled, but specifically for // use with tests. pref("layers.offmainthreadcomposition.testing.enabled", false); diff --git a/mozglue/linker/ElfLoader.cpp b/mozglue/linker/ElfLoader.cpp index 10c5fd3b05..be1e51eb84 100644 --- a/mozglue/linker/ElfLoader.cpp +++ b/mozglue/linker/ElfLoader.cpp @@ -517,6 +517,10 @@ ElfLoader::~ElfLoader() { LibHandleList list; + if (!Singleton.IsShutdownExpected()) { + MOZ_CRASH("Unexpected shutdown"); + } + /* Release self_elf and libc */ self_elf = nullptr; #if defined(ANDROID) diff --git a/mozglue/linker/ElfLoader.h b/mozglue/linker/ElfLoader.h index 247efca862..0d26a011ee 100644 --- a/mozglue/linker/ElfLoader.h +++ b/mozglue/linker/ElfLoader.h @@ -432,6 +432,12 @@ public: */ static Mappable *GetMappableFromPath(const char *path); + void ExpectShutdown(bool val) { expect_shutdown = val; } + bool IsShutdownExpected() { return expect_shutdown; } + +private: + bool expect_shutdown; + protected: /** * Registers the given handle. This method is meant to be called by @@ -455,6 +461,7 @@ protected: const char *lastError; private: + ElfLoader() : expect_shutdown(true) {} ~ElfLoader(); /* Initialization code that can't run during static initialization. */ diff --git a/mozglue/linker/Zip.h b/mozglue/linker/Zip.h index e45de11a3d..398bbc5536 100644 --- a/mozglue/linker/Zip.h +++ b/mozglue/linker/Zip.h @@ -271,7 +271,7 @@ private: */ bool Equals(const char *str) const { - return strncmp(str, buf, length) == 0; + return (strncmp(str, buf, length) == 0 && str[length] == '\0'); } private: diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 118f421cd6..29d8127d89 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -89,6 +89,15 @@ "kind": "boolean", "description": "blocklist.xml has been loaded synchronously *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, + "CHECKERBOARDED_CSSPIXELS_MS": { + "alert_emails": ["kgupta@mozilla.com"], + "bug_numbers": [1221694], + "expires_in_version": "55", + "kind": "exponential", + "high": "3840 * 2160 * 16", + "n_buckets": 50, + "description": "Magnitude of checkerboarding in CSSPixel-milliseconds per scrollable frame per composite" + }, "COMPOSITE_TIME" : { "expires_in_version": "never", "description": "Composite times in milliseconds", diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp index 17347bf20c..f57c4db5a8 100644 --- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -278,7 +278,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer, bool fillColor = false; - const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion(); + const nsIntRegion visibleRegion = aLayer->GetEffectiveVisibleRegion().ToUnknownRegion(); if (visibleRegion.IsEmpty()) { return true; }