1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsDisplayList.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,5347 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: set ts=2 sw=2 et tw=78: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + */ 1.10 + 1.11 +/* 1.12 + * structures that represent things to be painted (ordered in z-order), 1.13 + * used during painting and hit testing 1.14 + */ 1.15 + 1.16 +#include "mozilla/dom/TabChild.h" 1.17 +#include "mozilla/layers/PLayerTransaction.h" 1.18 + 1.19 +#include "nsDisplayList.h" 1.20 + 1.21 +#include "nsCSSRendering.h" 1.22 +#include "nsRenderingContext.h" 1.23 +#include "nsISelectionController.h" 1.24 +#include "nsIPresShell.h" 1.25 +#include "nsRegion.h" 1.26 +#include "nsStyleStructInlines.h" 1.27 +#include "nsStyleTransformMatrix.h" 1.28 +#include "gfxMatrix.h" 1.29 +#include "nsSVGIntegrationUtils.h" 1.30 +#include "nsLayoutUtils.h" 1.31 +#include "nsIScrollableFrame.h" 1.32 +#include "nsIFrameInlines.h" 1.33 +#include "nsThemeConstants.h" 1.34 +#include "LayerTreeInvalidation.h" 1.35 + 1.36 +#include "imgIContainer.h" 1.37 +#include "BasicLayers.h" 1.38 +#include "nsBoxFrame.h" 1.39 +#include "nsViewportFrame.h" 1.40 +#include "nsSubDocumentFrame.h" 1.41 +#include "nsSVGEffects.h" 1.42 +#include "nsSVGElement.h" 1.43 +#include "nsSVGClipPathFrame.h" 1.44 +#include "GeckoProfiler.h" 1.45 +#include "nsAnimationManager.h" 1.46 +#include "nsTransitionManager.h" 1.47 +#include "nsViewManager.h" 1.48 +#include "ImageLayers.h" 1.49 +#include "ImageContainer.h" 1.50 +#include "nsCanvasFrame.h" 1.51 +#include "StickyScrollContainer.h" 1.52 +#include "mozilla/EventStates.h" 1.53 +#include "mozilla/LookAndFeel.h" 1.54 +#include "mozilla/Preferences.h" 1.55 +#include "ActiveLayerTracker.h" 1.56 +#include "nsContentUtils.h" 1.57 +#include "nsPrintfCString.h" 1.58 +#include "UnitTransforms.h" 1.59 + 1.60 +#include <stdint.h> 1.61 +#include <algorithm> 1.62 + 1.63 +using namespace mozilla; 1.64 +using namespace mozilla::css; 1.65 +using namespace mozilla::layers; 1.66 +using namespace mozilla::dom; 1.67 +typedef FrameMetrics::ViewID ViewID; 1.68 + 1.69 +static inline nsIFrame* 1.70 +GetTransformRootFrame(nsIFrame* aFrame) 1.71 +{ 1.72 + return nsLayoutUtils::GetTransformRootFrame(aFrame); 1.73 +} 1.74 + 1.75 +static void AddTransformFunctions(nsCSSValueList* aList, 1.76 + nsStyleContext* aContext, 1.77 + nsPresContext* aPresContext, 1.78 + nsRect& aBounds, 1.79 + float aAppUnitsPerPixel, 1.80 + InfallibleTArray<TransformFunction>& aFunctions) 1.81 +{ 1.82 + if (aList->mValue.GetUnit() == eCSSUnit_None) { 1.83 + return; 1.84 + } 1.85 + 1.86 + for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) { 1.87 + const nsCSSValue& currElem = curr->mValue; 1.88 + NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function, 1.89 + "Stream should consist solely of functions!"); 1.90 + nsCSSValue::Array* array = currElem.GetArrayValue(); 1.91 + bool canStoreInRuleTree = true; 1.92 + switch (nsStyleTransformMatrix::TransformFunctionOf(array)) { 1.93 + case eCSSKeyword_rotatex: 1.94 + { 1.95 + double theta = array->Item(1).GetAngleValueInRadians(); 1.96 + aFunctions.AppendElement(RotationX(theta)); 1.97 + break; 1.98 + } 1.99 + case eCSSKeyword_rotatey: 1.100 + { 1.101 + double theta = array->Item(1).GetAngleValueInRadians(); 1.102 + aFunctions.AppendElement(RotationY(theta)); 1.103 + break; 1.104 + } 1.105 + case eCSSKeyword_rotatez: 1.106 + { 1.107 + double theta = array->Item(1).GetAngleValueInRadians(); 1.108 + aFunctions.AppendElement(RotationZ(theta)); 1.109 + break; 1.110 + } 1.111 + case eCSSKeyword_rotate: 1.112 + { 1.113 + double theta = array->Item(1).GetAngleValueInRadians(); 1.114 + aFunctions.AppendElement(Rotation(theta)); 1.115 + break; 1.116 + } 1.117 + case eCSSKeyword_rotate3d: 1.118 + { 1.119 + double x = array->Item(1).GetFloatValue(); 1.120 + double y = array->Item(2).GetFloatValue(); 1.121 + double z = array->Item(3).GetFloatValue(); 1.122 + double theta = array->Item(4).GetAngleValueInRadians(); 1.123 + aFunctions.AppendElement(Rotation3D(x, y, z, theta)); 1.124 + break; 1.125 + } 1.126 + case eCSSKeyword_scalex: 1.127 + { 1.128 + double x = array->Item(1).GetFloatValue(); 1.129 + aFunctions.AppendElement(Scale(x, 1, 1)); 1.130 + break; 1.131 + } 1.132 + case eCSSKeyword_scaley: 1.133 + { 1.134 + double y = array->Item(1).GetFloatValue(); 1.135 + aFunctions.AppendElement(Scale(1, y, 1)); 1.136 + break; 1.137 + } 1.138 + case eCSSKeyword_scalez: 1.139 + { 1.140 + double z = array->Item(1).GetFloatValue(); 1.141 + aFunctions.AppendElement(Scale(1, 1, z)); 1.142 + break; 1.143 + } 1.144 + case eCSSKeyword_scale: 1.145 + { 1.146 + double x = array->Item(1).GetFloatValue(); 1.147 + // scale(x) is shorthand for scale(x, x); 1.148 + double y = array->Count() == 2 ? x : array->Item(2).GetFloatValue(); 1.149 + aFunctions.AppendElement(Scale(x, y, 1)); 1.150 + break; 1.151 + } 1.152 + case eCSSKeyword_scale3d: 1.153 + { 1.154 + double x = array->Item(1).GetFloatValue(); 1.155 + double y = array->Item(2).GetFloatValue(); 1.156 + double z = array->Item(3).GetFloatValue(); 1.157 + aFunctions.AppendElement(Scale(x, y, z)); 1.158 + break; 1.159 + } 1.160 + case eCSSKeyword_translatex: 1.161 + { 1.162 + double x = nsStyleTransformMatrix::ProcessTranslatePart( 1.163 + array->Item(1), aContext, aPresContext, canStoreInRuleTree, 1.164 + aBounds.Width(), aAppUnitsPerPixel); 1.165 + aFunctions.AppendElement(Translation(x, 0, 0)); 1.166 + break; 1.167 + } 1.168 + case eCSSKeyword_translatey: 1.169 + { 1.170 + double y = nsStyleTransformMatrix::ProcessTranslatePart( 1.171 + array->Item(1), aContext, aPresContext, canStoreInRuleTree, 1.172 + aBounds.Height(), aAppUnitsPerPixel); 1.173 + aFunctions.AppendElement(Translation(0, y, 0)); 1.174 + break; 1.175 + } 1.176 + case eCSSKeyword_translatez: 1.177 + { 1.178 + double z = nsStyleTransformMatrix::ProcessTranslatePart( 1.179 + array->Item(1), aContext, aPresContext, canStoreInRuleTree, 1.180 + 0, aAppUnitsPerPixel); 1.181 + aFunctions.AppendElement(Translation(0, 0, z)); 1.182 + break; 1.183 + } 1.184 + case eCSSKeyword_translate: 1.185 + { 1.186 + double x = nsStyleTransformMatrix::ProcessTranslatePart( 1.187 + array->Item(1), aContext, aPresContext, canStoreInRuleTree, 1.188 + aBounds.Width(), aAppUnitsPerPixel); 1.189 + // translate(x) is shorthand for translate(x, 0) 1.190 + double y = 0; 1.191 + if (array->Count() == 3) { 1.192 + y = nsStyleTransformMatrix::ProcessTranslatePart( 1.193 + array->Item(2), aContext, aPresContext, canStoreInRuleTree, 1.194 + aBounds.Height(), aAppUnitsPerPixel); 1.195 + } 1.196 + aFunctions.AppendElement(Translation(x, y, 0)); 1.197 + break; 1.198 + } 1.199 + case eCSSKeyword_translate3d: 1.200 + { 1.201 + double x = nsStyleTransformMatrix::ProcessTranslatePart( 1.202 + array->Item(1), aContext, aPresContext, canStoreInRuleTree, 1.203 + aBounds.Width(), aAppUnitsPerPixel); 1.204 + double y = nsStyleTransformMatrix::ProcessTranslatePart( 1.205 + array->Item(2), aContext, aPresContext, canStoreInRuleTree, 1.206 + aBounds.Height(), aAppUnitsPerPixel); 1.207 + double z = nsStyleTransformMatrix::ProcessTranslatePart( 1.208 + array->Item(3), aContext, aPresContext, canStoreInRuleTree, 1.209 + 0, aAppUnitsPerPixel); 1.210 + 1.211 + aFunctions.AppendElement(Translation(x, y, z)); 1.212 + break; 1.213 + } 1.214 + case eCSSKeyword_skewx: 1.215 + { 1.216 + double x = array->Item(1).GetAngleValueInRadians(); 1.217 + aFunctions.AppendElement(SkewX(x)); 1.218 + break; 1.219 + } 1.220 + case eCSSKeyword_skewy: 1.221 + { 1.222 + double y = array->Item(1).GetAngleValueInRadians(); 1.223 + aFunctions.AppendElement(SkewY(y)); 1.224 + break; 1.225 + } 1.226 + case eCSSKeyword_skew: 1.227 + { 1.228 + double x = array->Item(1).GetAngleValueInRadians(); 1.229 + // skew(x) is shorthand for skew(x, 0) 1.230 + double y = 0; 1.231 + if (array->Count() == 3) { 1.232 + y = array->Item(2).GetAngleValueInRadians(); 1.233 + } 1.234 + aFunctions.AppendElement(Skew(x, y)); 1.235 + break; 1.236 + } 1.237 + case eCSSKeyword_matrix: 1.238 + { 1.239 + gfx::Matrix4x4 matrix; 1.240 + matrix._11 = array->Item(1).GetFloatValue(); 1.241 + matrix._12 = array->Item(2).GetFloatValue(); 1.242 + matrix._13 = 0; 1.243 + matrix._14 = 0; 1.244 + matrix._21 = array->Item(3).GetFloatValue(); 1.245 + matrix._22 = array->Item(4).GetFloatValue(); 1.246 + matrix._23 = 0; 1.247 + matrix._24 = 0; 1.248 + matrix._31 = 0; 1.249 + matrix._32 = 0; 1.250 + matrix._33 = 1; 1.251 + matrix._34 = 0; 1.252 + matrix._41 = array->Item(5).GetFloatValue(); 1.253 + matrix._42 = array->Item(6).GetFloatValue(); 1.254 + matrix._43 = 0; 1.255 + matrix._44 = 1; 1.256 + aFunctions.AppendElement(TransformMatrix(matrix)); 1.257 + break; 1.258 + } 1.259 + case eCSSKeyword_matrix3d: 1.260 + { 1.261 + gfx::Matrix4x4 matrix; 1.262 + matrix._11 = array->Item(1).GetFloatValue(); 1.263 + matrix._12 = array->Item(2).GetFloatValue(); 1.264 + matrix._13 = array->Item(3).GetFloatValue(); 1.265 + matrix._14 = array->Item(4).GetFloatValue(); 1.266 + matrix._21 = array->Item(5).GetFloatValue(); 1.267 + matrix._22 = array->Item(6).GetFloatValue(); 1.268 + matrix._23 = array->Item(7).GetFloatValue(); 1.269 + matrix._24 = array->Item(8).GetFloatValue(); 1.270 + matrix._31 = array->Item(9).GetFloatValue(); 1.271 + matrix._32 = array->Item(10).GetFloatValue(); 1.272 + matrix._33 = array->Item(11).GetFloatValue(); 1.273 + matrix._34 = array->Item(12).GetFloatValue(); 1.274 + matrix._41 = array->Item(13).GetFloatValue(); 1.275 + matrix._42 = array->Item(14).GetFloatValue(); 1.276 + matrix._43 = array->Item(15).GetFloatValue(); 1.277 + matrix._44 = array->Item(16).GetFloatValue(); 1.278 + aFunctions.AppendElement(TransformMatrix(matrix)); 1.279 + break; 1.280 + } 1.281 + case eCSSKeyword_interpolatematrix: 1.282 + { 1.283 + gfx3DMatrix matrix; 1.284 + nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array, 1.285 + aContext, 1.286 + aPresContext, 1.287 + canStoreInRuleTree, 1.288 + aBounds, 1.289 + aAppUnitsPerPixel); 1.290 + gfx::Matrix4x4 transform; 1.291 + gfx::ToMatrix4x4(matrix, transform); 1.292 + aFunctions.AppendElement(TransformMatrix(transform)); 1.293 + break; 1.294 + } 1.295 + case eCSSKeyword_perspective: 1.296 + { 1.297 + aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue())); 1.298 + break; 1.299 + } 1.300 + default: 1.301 + NS_ERROR("Function not handled yet!"); 1.302 + } 1.303 + } 1.304 +} 1.305 + 1.306 +static TimingFunction 1.307 +ToTimingFunction(css::ComputedTimingFunction& aCTF) 1.308 +{ 1.309 + if (aCTF.GetType() == nsTimingFunction::Function) { 1.310 + const nsSMILKeySpline* spline = aCTF.GetFunction(); 1.311 + return TimingFunction(CubicBezierFunction(spline->X1(), spline->Y1(), 1.312 + spline->X2(), spline->Y2())); 1.313 + } 1.314 + 1.315 + uint32_t type = aCTF.GetType() == nsTimingFunction::StepStart ? 1 : 2; 1.316 + return TimingFunction(StepFunction(aCTF.GetSteps(), type)); 1.317 +} 1.318 + 1.319 +static void 1.320 +AddAnimationForProperty(nsIFrame* aFrame, nsCSSProperty aProperty, 1.321 + mozilla::StyleAnimation* ea, Layer* aLayer, 1.322 + AnimationData& aData, bool aPending) 1.323 +{ 1.324 + NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer"); 1.325 + nsStyleContext* styleContext = aFrame->StyleContext(); 1.326 + nsPresContext* presContext = aFrame->PresContext(); 1.327 + nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame); 1.328 + // all data passed directly to the compositor should be in css pixels 1.329 + float scale = nsDeviceContext::AppUnitsPerCSSPixel(); 1.330 + 1.331 + mozilla::layers::Animation* animation = 1.332 + aPending ? 1.333 + aLayer->AddAnimationForNextTransaction() : 1.334 + aLayer->AddAnimation(); 1.335 + 1.336 + animation->startTime() = ea->mStartTime + ea->mDelay; 1.337 + animation->duration() = ea->mIterationDuration; 1.338 + animation->numIterations() = 1.339 + ea->mIterationCount != NS_IEEEPositiveInfinity() ? ea->mIterationCount : -1; 1.340 + animation->direction() = ea->mDirection; 1.341 + animation->property() = aProperty; 1.342 + animation->data() = aData; 1.343 + 1.344 + for (uint32_t propIdx = 0; propIdx < ea->mProperties.Length(); propIdx++) { 1.345 + AnimationProperty* property = &ea->mProperties[propIdx]; 1.346 + 1.347 + if (aProperty != property->mProperty) { 1.348 + continue; 1.349 + } 1.350 + 1.351 + for (uint32_t segIdx = 0; segIdx < property->mSegments.Length(); segIdx++) { 1.352 + AnimationPropertySegment* segment = &property->mSegments[segIdx]; 1.353 + 1.354 + AnimationSegment* animSegment = animation->segments().AppendElement(); 1.355 + if (aProperty == eCSSProperty_transform) { 1.356 + animSegment->startState() = InfallibleTArray<TransformFunction>(); 1.357 + animSegment->endState() = InfallibleTArray<TransformFunction>(); 1.358 + 1.359 + nsCSSValueSharedList* list = segment->mFromValue.GetCSSValueSharedListValue(); 1.360 + AddTransformFunctions(list->mHead, styleContext, presContext, bounds, scale, 1.361 + animSegment->startState().get_ArrayOfTransformFunction()); 1.362 + 1.363 + list = segment->mToValue.GetCSSValueSharedListValue(); 1.364 + AddTransformFunctions(list->mHead, styleContext, presContext, bounds, scale, 1.365 + animSegment->endState().get_ArrayOfTransformFunction()); 1.366 + } else if (aProperty == eCSSProperty_opacity) { 1.367 + animSegment->startState() = segment->mFromValue.GetFloatValue(); 1.368 + animSegment->endState() = segment->mToValue.GetFloatValue(); 1.369 + } 1.370 + 1.371 + animSegment->startPortion() = segment->mFromKey; 1.372 + animSegment->endPortion() = segment->mToKey; 1.373 + animSegment->sampleFn() = ToTimingFunction(segment->mTimingFunction); 1.374 + } 1.375 + } 1.376 +} 1.377 + 1.378 +template<class T> 1.379 +static void 1.380 +AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty, 1.381 + nsTArray<T>& aAnimations, 1.382 + Layer* aLayer, AnimationData& aData, 1.383 + bool aPending) { 1.384 + mozilla::TimeStamp currentTime = 1.385 + aFrame->PresContext()->RefreshDriver()->MostRecentRefresh(); 1.386 + for (uint32_t animIdx = 0; animIdx < aAnimations.Length(); animIdx++) { 1.387 + mozilla::StyleAnimation* anim = &aAnimations[animIdx]; 1.388 + if (!(anim->HasAnimationOfProperty(aProperty) && 1.389 + anim->IsRunningAt(currentTime))) { 1.390 + continue; 1.391 + } 1.392 + AddAnimationForProperty(aFrame, aProperty, anim, aLayer, aData, aPending); 1.393 + anim->mIsRunningOnCompositor = true; 1.394 + } 1.395 +} 1.396 + 1.397 +/* static */ void 1.398 +nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer, 1.399 + nsDisplayListBuilder* aBuilder, 1.400 + nsDisplayItem* aItem, 1.401 + nsIFrame* aFrame, 1.402 + nsCSSProperty aProperty) 1.403 +{ 1.404 + // This function can be called in two ways: from 1.405 + // nsDisplay*::BuildLayer while constructing a layer (with all 1.406 + // pointers non-null), or from RestyleManager's handling of 1.407 + // UpdateOpacityLayer/UpdateTransformLayer hints. 1.408 + MOZ_ASSERT(!aBuilder == !aItem, 1.409 + "should only be called in two configurations, with both " 1.410 + "aBuilder and aItem, or with neither"); 1.411 + MOZ_ASSERT(!aItem || aFrame == aItem->Frame(), "frame mismatch"); 1.412 + 1.413 + bool pending = !aBuilder; 1.414 + 1.415 + if (pending) { 1.416 + aLayer->ClearAnimationsForNextTransaction(); 1.417 + } else { 1.418 + aLayer->ClearAnimations(); 1.419 + } 1.420 + 1.421 + nsIContent* content = aFrame->GetContent(); 1.422 + if (!content) { 1.423 + return; 1.424 + } 1.425 + ElementTransitions* et = 1.426 + nsTransitionManager::GetTransitionsForCompositor(content, aProperty); 1.427 + 1.428 + ElementAnimations* ea = 1.429 + nsAnimationManager::GetAnimationsForCompositor(content, aProperty); 1.430 + 1.431 + if (!ea && !et) { 1.432 + return; 1.433 + } 1.434 + 1.435 + // If the frame is not prerendered, bail out. 1.436 + // Do this check only during layer construction; during updating the 1.437 + // caller is required to check it appropriately. 1.438 + if (aItem && !aItem->CanUseAsyncAnimations(aBuilder)) { 1.439 + // AnimationManager or TransitionManager need to know that we refused to 1.440 + // run this animation asynchronously so that they will not throttle the 1.441 + // main thread animation. 1.442 + aFrame->Properties().Set(nsIFrame::RefusedAsyncAnimation(), 1.443 + reinterpret_cast<void*>(intptr_t(true))); 1.444 + 1.445 + // We need to schedule another refresh driver run so that AnimationManager 1.446 + // or TransitionManager get a chance to unthrottle the animation. 1.447 + aFrame->SchedulePaint(); 1.448 + return; 1.449 + } 1.450 + 1.451 + AnimationData data; 1.452 + if (aProperty == eCSSProperty_transform) { 1.453 + nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame); 1.454 + // all data passed directly to the compositor should be in css pixels 1.455 + float scale = nsDeviceContext::AppUnitsPerCSSPixel(); 1.456 + gfxPoint3D offsetToTransformOrigin = 1.457 + nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds); 1.458 + gfxPoint3D offsetToPerspectiveOrigin = 1.459 + nsDisplayTransform::GetDeltaToPerspectiveOrigin(aFrame, scale); 1.460 + nscoord perspective = 0.0; 1.461 + nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent(); 1.462 + if (parentStyleContext) { 1.463 + const nsStyleDisplay* disp = parentStyleContext->StyleDisplay(); 1.464 + if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) { 1.465 + perspective = disp->mChildPerspective.GetCoordValue(); 1.466 + } 1.467 + } 1.468 + nsPoint origin; 1.469 + if (aItem) { 1.470 + origin = aItem->ToReferenceFrame(); 1.471 + } else { 1.472 + // transform display items used a reference frame computed from 1.473 + // their GetTransformRootFrame(). 1.474 + nsIFrame* referenceFrame = 1.475 + nsLayoutUtils::GetReferenceFrame(GetTransformRootFrame(aFrame)); 1.476 + origin = aFrame->GetOffsetToCrossDoc(referenceFrame); 1.477 + } 1.478 + 1.479 + data = TransformData(origin, offsetToTransformOrigin, 1.480 + offsetToPerspectiveOrigin, bounds, perspective, 1.481 + aFrame->PresContext()->AppUnitsPerDevPixel()); 1.482 + } else if (aProperty == eCSSProperty_opacity) { 1.483 + data = null_t(); 1.484 + } 1.485 + 1.486 + if (et) { 1.487 + AddAnimationsForProperty(aFrame, aProperty, et->mPropertyTransitions, 1.488 + aLayer, data, pending); 1.489 + aLayer->SetAnimationGeneration(et->mAnimationGeneration); 1.490 + } 1.491 + 1.492 + if (ea) { 1.493 + AddAnimationsForProperty(aFrame, aProperty, ea->mAnimations, 1.494 + aLayer, data, pending); 1.495 + aLayer->SetAnimationGeneration(ea->mAnimationGeneration); 1.496 + } 1.497 +} 1.498 + 1.499 +nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, 1.500 + Mode aMode, bool aBuildCaret) 1.501 + : mReferenceFrame(aReferenceFrame), 1.502 + mIgnoreScrollFrame(nullptr), 1.503 + mLayerEventRegions(nullptr), 1.504 + mCurrentTableItem(nullptr), 1.505 + mFinalTransparentRegion(nullptr), 1.506 + mCachedOffsetFrame(aReferenceFrame), 1.507 + mCachedReferenceFrame(aReferenceFrame), 1.508 + mCachedOffset(0, 0), 1.509 + mGlassDisplayItem(nullptr), 1.510 + mMode(aMode), 1.511 + mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID), 1.512 + mBuildCaret(aBuildCaret), 1.513 + mIgnoreSuppression(false), 1.514 + mHadToIgnoreSuppression(false), 1.515 + mIsAtRootOfPseudoStackingContext(false), 1.516 + mIncludeAllOutOfFlows(false), 1.517 + mDescendIntoSubdocuments(true), 1.518 + mSelectedFramesOnly(false), 1.519 + mAccurateVisibleRegions(false), 1.520 + mAllowMergingAndFlattening(true), 1.521 + mWillComputePluginGeometry(false), 1.522 + mInTransform(false), 1.523 + mInFixedPos(false), 1.524 + mSyncDecodeImages(false), 1.525 + mIsPaintingToWindow(false), 1.526 + mIsCompositingCheap(false), 1.527 + mContainsPluginItem(false), 1.528 + mContainsBlendMode(false), 1.529 + mAncestorHasTouchEventHandler(false), 1.530 + mHaveScrollableDisplayPort(false) 1.531 +{ 1.532 + MOZ_COUNT_CTOR(nsDisplayListBuilder); 1.533 + PL_InitArenaPool(&mPool, "displayListArena", 1024, 1.534 + std::max(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1); 1.535 + 1.536 + nsPresContext* pc = aReferenceFrame->PresContext(); 1.537 + nsIPresShell *shell = pc->PresShell(); 1.538 + if (pc->IsRenderingOnlySelection()) { 1.539 + nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell)); 1.540 + if (selcon) { 1.541 + selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, 1.542 + getter_AddRefs(mBoundingSelection)); 1.543 + } 1.544 + } 1.545 + 1.546 + nsCSSRendering::BeginFrameTreesLocked(); 1.547 + PR_STATIC_ASSERT(nsDisplayItem::TYPE_MAX < (1 << nsDisplayItem::TYPE_BITS)); 1.548 +} 1.549 + 1.550 +static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) { 1.551 + for (nsIFrame* f = aFrame; f; 1.552 + f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) { 1.553 + if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO) 1.554 + return; 1.555 + f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO); 1.556 + if (f == aStopAtFrame) { 1.557 + // we've reached a frame that we know will be painted, so we can stop. 1.558 + break; 1.559 + } 1.560 + } 1.561 +} 1.562 + 1.563 +void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, 1.564 + nsIFrame* aFrame, 1.565 + const nsRect& aDirtyRect) 1.566 +{ 1.567 + nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect; 1.568 + if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) { 1.569 + NS_ASSERTION(aDirtyFrame == aFrame->GetParent(), "Dirty frame should be viewport frame"); 1.570 + // position: fixed items are reflowed into and only drawn inside the 1.571 + // viewport, or the scroll position clamping scrollport size, if one is 1.572 + // set. 1.573 + nsIPresShell* ps = aFrame->PresContext()->PresShell(); 1.574 + dirtyRectRelativeToDirtyFrame.MoveTo(0, 0); 1.575 + if (ps->IsScrollPositionClampingScrollPortSizeSet()) { 1.576 + dirtyRectRelativeToDirtyFrame.SizeTo(ps->GetScrollPositionClampingScrollPortSize()); 1.577 + } else { 1.578 + dirtyRectRelativeToDirtyFrame.SizeTo(aDirtyFrame->GetSize()); 1.579 + } 1.580 + } 1.581 + 1.582 + nsRect dirty = dirtyRectRelativeToDirtyFrame - aFrame->GetOffsetTo(aDirtyFrame); 1.583 + nsRect overflowRect = aFrame->GetVisualOverflowRect(); 1.584 + 1.585 + if (aFrame->IsTransformed() && 1.586 + nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(), 1.587 + eCSSProperty_transform)) { 1.588 + /** 1.589 + * Add a fuzz factor to the overflow rectangle so that elements only just 1.590 + * out of view are pulled into the display list, so they can be 1.591 + * prerendered if necessary. 1.592 + */ 1.593 + overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32)); 1.594 + } 1.595 + 1.596 + if (!dirty.IntersectRect(dirty, overflowRect)) 1.597 + return; 1.598 + const DisplayItemClip* clip = mClipState.GetClipForContainingBlockDescendants(); 1.599 + OutOfFlowDisplayData* data = clip ? new OutOfFlowDisplayData(*clip, dirty) 1.600 + : new OutOfFlowDisplayData(dirty); 1.601 + aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data); 1.602 + 1.603 + MarkFrameForDisplay(aFrame, aDirtyFrame); 1.604 +} 1.605 + 1.606 +static void UnmarkFrameForDisplay(nsIFrame* aFrame) { 1.607 + nsPresContext* presContext = aFrame->PresContext(); 1.608 + presContext->PropertyTable()-> 1.609 + Delete(aFrame, nsDisplayListBuilder::OutOfFlowDisplayDataProperty()); 1.610 + 1.611 + for (nsIFrame* f = aFrame; f; 1.612 + f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) { 1.613 + if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) 1.614 + return; 1.615 + f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO); 1.616 + } 1.617 +} 1.618 + 1.619 +static bool gPrintApzcTree = false; 1.620 + 1.621 +static bool GetApzcTreePrintPref() { 1.622 + static bool initialized = false; 1.623 + if (!initialized) { 1.624 + Preferences::AddBoolVarCache(&gPrintApzcTree, "apz.printtree", gPrintApzcTree); 1.625 + initialized = true; 1.626 + } 1.627 + return gPrintApzcTree; 1.628 +} 1.629 + 1.630 +static void RecordFrameMetrics(nsIFrame* aForFrame, 1.631 + nsIFrame* aScrollFrame, 1.632 + const nsIFrame* aReferenceFrame, 1.633 + ContainerLayer* aRoot, 1.634 + const nsRect& aVisibleRect, 1.635 + const nsRect& aViewport, 1.636 + nsRect* aDisplayPort, 1.637 + nsRect* aCriticalDisplayPort, 1.638 + ViewID aScrollId, 1.639 + bool aIsRoot, 1.640 + const ContainerLayerParameters& aContainerParameters) { 1.641 + nsPresContext* presContext = aForFrame->PresContext(); 1.642 + int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel(); 1.643 + LayoutDeviceToLayerScale resolution(aContainerParameters.mXScale, aContainerParameters.mYScale); 1.644 + 1.645 + nsIntRect visible = aVisibleRect.ScaleToNearestPixels( 1.646 + resolution.scale, resolution.scale, auPerDevPixel); 1.647 + aRoot->SetVisibleRegion(visible); 1.648 + 1.649 + FrameMetrics metrics; 1.650 + metrics.mViewport = CSSRect::FromAppUnits(aViewport); 1.651 + if (aDisplayPort) { 1.652 + metrics.mDisplayPort = CSSRect::FromAppUnits(*aDisplayPort); 1.653 + if (aCriticalDisplayPort) { 1.654 + metrics.mCriticalDisplayPort = CSSRect::FromAppUnits(*aCriticalDisplayPort); 1.655 + } 1.656 + } 1.657 + 1.658 + nsIScrollableFrame* scrollableFrame = nullptr; 1.659 + if (aScrollFrame) 1.660 + scrollableFrame = aScrollFrame->GetScrollTargetFrame(); 1.661 + 1.662 + metrics.mScrollableRect = CSSRect::FromAppUnits( 1.663 + nsLayoutUtils::CalculateScrollableRectForFrame(scrollableFrame, aForFrame)); 1.664 + 1.665 + if (scrollableFrame) { 1.666 + nsPoint scrollPosition = scrollableFrame->GetScrollPosition(); 1.667 + metrics.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition)); 1.668 + 1.669 + // If the frame was scrolled since the last layers update, and by 1.670 + // something other than the APZ code, we want to tell the APZ to update 1.671 + // its scroll offset. 1.672 + nsIAtom* originOfLastScroll = scrollableFrame->OriginOfLastScroll(); 1.673 + if (originOfLastScroll && originOfLastScroll != nsGkAtoms::apz) { 1.674 + metrics.SetScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration()); 1.675 + } 1.676 + } 1.677 + 1.678 + metrics.SetScrollId(aScrollId); 1.679 + metrics.mIsRoot = aIsRoot; 1.680 + 1.681 + // Only the root scrollable frame for a given presShell should pick up 1.682 + // the presShell's resolution. All the other frames are 1.0. 1.683 + nsIPresShell* presShell = presContext->GetPresShell(); 1.684 + if (aScrollFrame == presShell->GetRootScrollFrame()) { 1.685 + metrics.mResolution = ParentLayerToLayerScale(presShell->GetXResolution(), 1.686 + presShell->GetYResolution()); 1.687 + } else { 1.688 + metrics.mResolution = ParentLayerToLayerScale(1.0f); 1.689 + } 1.690 + 1.691 + // For the cumulateive resolution, multiply the resolutions of all the 1.692 + // presShells back up to the root 1.693 + metrics.mCumulativeResolution = LayoutDeviceToLayerScale(1.0f); 1.694 + nsIPresShell* curPresShell = presShell; 1.695 + while (curPresShell != nullptr) { 1.696 + ParentLayerToLayerScale presShellResolution(curPresShell->GetXResolution(), 1.697 + curPresShell->GetYResolution()); 1.698 + metrics.mCumulativeResolution.scale *= presShellResolution.scale; 1.699 + nsPresContext* parentContext = curPresShell->GetPresContext()->GetParentPresContext(); 1.700 + curPresShell = parentContext ? parentContext->GetPresShell() : nullptr; 1.701 + } 1.702 + 1.703 + metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale( 1.704 + (float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel); 1.705 + 1.706 + // Initially, AsyncPanZoomController should render the content to the screen 1.707 + // at the painted resolution. 1.708 + const LayerToScreenScale layerToScreenScale(1.0f); 1.709 + metrics.SetZoom(metrics.mCumulativeResolution * metrics.mDevPixelsPerCSSPixel 1.710 + * layerToScreenScale); 1.711 + 1.712 + if (presShell) { 1.713 + nsIDocument* document = nullptr; 1.714 + document = presShell->GetDocument(); 1.715 + if (document) { 1.716 + nsCOMPtr<nsPIDOMWindow> innerWin(document->GetInnerWindow()); 1.717 + if (innerWin) { 1.718 + metrics.mMayHaveTouchListeners = innerWin->HasTouchEventListeners(); 1.719 + } 1.720 + } 1.721 + } 1.722 + 1.723 + LayoutDeviceToParentLayerScale layoutToParentLayerScale = 1.724 + // The ScreenToParentLayerScale should be mTransformScale which is not calculated yet, 1.725 + // but we don't yet handle CSS transforms, so we assume it's 1 here. 1.726 + metrics.mCumulativeResolution * LayerToScreenScale(1.0) * ScreenToParentLayerScale(1.0); 1.727 + 1.728 + // Calculate the composition bounds as the size of the scroll frame and 1.729 + // its origin relative to the reference frame. 1.730 + // If aScrollFrame is null, we are in a document without a root scroll frame, 1.731 + // so it's a xul document. In this case, use the size of the viewport frame. 1.732 + nsIFrame* frameForCompositionBoundsCalculation = aScrollFrame ? aScrollFrame : aForFrame; 1.733 + nsRect compositionBounds(frameForCompositionBoundsCalculation->GetOffsetToCrossDoc(aReferenceFrame), 1.734 + frameForCompositionBoundsCalculation->GetSize()); 1.735 + metrics.mCompositionBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(compositionBounds, auPerDevPixel) 1.736 + * layoutToParentLayerScale); 1.737 + 1.738 + 1.739 + // For the root scroll frame of the root content document, the above calculation 1.740 + // will yield the size of the viewport frame as the composition bounds, which 1.741 + // doesn't actually correspond to what is visible when 1.742 + // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of 1.743 + // the prescontext that the viewport frame is reflowed into. In that case if our 1.744 + // document has a widget then the widget's bounds will correspond to what is 1.745 + // visible. If we don't have a widget the root view's bounds correspond to what 1.746 + // would be visible because they don't get modified by setCSSViewport. 1.747 + bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument() 1.748 + && aScrollFrame == presShell->GetRootScrollFrame(); 1.749 + if (isRootContentDocRootScrollFrame) { 1.750 + if (nsIFrame* rootFrame = presShell->GetRootFrame()) { 1.751 + if (nsView* view = rootFrame->GetView()) { 1.752 + nsRect viewBoundsAppUnits = view->GetBounds() + rootFrame->GetOffsetToCrossDoc(aReferenceFrame); 1.753 + ParentLayerIntRect viewBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(viewBoundsAppUnits, auPerDevPixel) 1.754 + * layoutToParentLayerScale); 1.755 + 1.756 + // On Android, we need to do things a bit differently to get things 1.757 + // right (see bug 983208, bug 988882). We use the bounds of the nearest 1.758 + // widget, but clamp the height to the view bounds height. This clamping 1.759 + // is done to get correct results for a page where the page is sized to 1.760 + // the screen and thus the dynamic toolbar never disappears. In such a 1.761 + // case, we want the composition bounds to exclude the toolbar height, 1.762 + // but the widget bounds includes it. We don't currently have a good way 1.763 + // of knowing about the toolbar height, but clamping to the view bounds 1.764 + // height gives the correct answer in the cases we care about. 1.765 + nsIWidget* widget = 1.766 +#ifdef MOZ_WIDGET_ANDROID 1.767 + rootFrame->GetNearestWidget(); 1.768 +#else 1.769 + view->GetWidget(); 1.770 +#endif 1.771 + if (widget) { 1.772 + nsIntRect widgetBounds; 1.773 + widget->GetBounds(widgetBounds); 1.774 + metrics.mCompositionBounds = ViewAs<ParentLayerPixel>(widgetBounds); 1.775 +#ifdef MOZ_WIDGET_ANDROID 1.776 + if (viewBounds.height < metrics.mCompositionBounds.height) { 1.777 + metrics.mCompositionBounds.height = viewBounds.height; 1.778 + } 1.779 +#endif 1.780 + } else { 1.781 + metrics.mCompositionBounds = viewBounds; 1.782 + } 1.783 + } 1.784 + } 1.785 + } 1.786 + 1.787 + // Adjust composition bounds for the size of scroll bars. 1.788 + if (scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) { 1.789 + nsMargin sizes = scrollableFrame->GetActualScrollbarSizes(); 1.790 + // Scrollbars are not subject to scaling, so CSS pixels = layer pixels for them. 1.791 + ParentLayerIntMargin boundMargins = RoundedToInt(CSSMargin::FromAppUnits(sizes) * CSSToParentLayerScale(1.0f)); 1.792 + metrics.mCompositionBounds.Deflate(boundMargins); 1.793 + } 1.794 + 1.795 + metrics.SetRootCompositionSize( 1.796 + nsLayoutUtils::CalculateRootCompositionSize(aScrollFrame ? aScrollFrame : aForFrame, 1.797 + isRootContentDocRootScrollFrame, metrics)); 1.798 + 1.799 + if (GetApzcTreePrintPref()) { 1.800 + if (nsIContent* content = frameForCompositionBoundsCalculation->GetContent()) { 1.801 + nsAutoString contentDescription; 1.802 + content->Describe(contentDescription); 1.803 + metrics.SetContentDescription(NS_LossyConvertUTF16toASCII(contentDescription).get()); 1.804 + } 1.805 + } 1.806 + 1.807 + metrics.mPresShellId = presShell->GetPresShellId(); 1.808 + 1.809 + // If the scroll frame's content is marked 'scrollgrab', record this 1.810 + // in the FrameMetrics so APZ knows to provide the scroll grabbing 1.811 + // behaviour. 1.812 + if (aScrollFrame && nsContentUtils::HasScrollgrab(aScrollFrame->GetContent())) { 1.813 + metrics.mHasScrollgrab = true; 1.814 + } 1.815 + 1.816 + aRoot->SetFrameMetrics(metrics); 1.817 +} 1.818 + 1.819 +nsDisplayListBuilder::~nsDisplayListBuilder() { 1.820 + NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0, 1.821 + "All frames should have been unmarked"); 1.822 + NS_ASSERTION(mPresShellStates.Length() == 0, 1.823 + "All presshells should have been exited"); 1.824 + NS_ASSERTION(!mCurrentTableItem, "No table item should be active"); 1.825 + 1.826 + nsCSSRendering::EndFrameTreesLocked(); 1.827 + 1.828 + for (uint32_t i = 0; i < mDisplayItemClipsToDestroy.Length(); ++i) { 1.829 + mDisplayItemClipsToDestroy[i]->DisplayItemClip::~DisplayItemClip(); 1.830 + } 1.831 + 1.832 + PL_FinishArenaPool(&mPool); 1.833 + MOZ_COUNT_DTOR(nsDisplayListBuilder); 1.834 +} 1.835 + 1.836 +uint32_t 1.837 +nsDisplayListBuilder::GetBackgroundPaintFlags() { 1.838 + uint32_t flags = 0; 1.839 + if (mSyncDecodeImages) { 1.840 + flags |= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES; 1.841 + } 1.842 + if (mIsPaintingToWindow) { 1.843 + flags |= nsCSSRendering::PAINTBG_TO_WINDOW; 1.844 + } 1.845 + return flags; 1.846 +} 1.847 + 1.848 +void 1.849 +nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion, 1.850 + const nsRegion& aRegion) 1.851 +{ 1.852 + if (aRegion.IsEmpty()) 1.853 + return; 1.854 + 1.855 + nsRegion tmp; 1.856 + tmp.Sub(*aVisibleRegion, aRegion); 1.857 + // Don't let *aVisibleRegion get too complex, but don't let it fluff out 1.858 + // to its bounds either, which can be very bad (see bug 516740). 1.859 + // Do let aVisibleRegion get more complex if by doing so we reduce its 1.860 + // area by at least half. 1.861 + if (GetAccurateVisibleRegions() || tmp.GetNumRects() <= 15 || 1.862 + tmp.Area() <= aVisibleRegion->Area()/2) { 1.863 + *aVisibleRegion = tmp; 1.864 + } 1.865 +} 1.866 + 1.867 +nsCaret * 1.868 +nsDisplayListBuilder::GetCaret() { 1.869 + nsRefPtr<nsCaret> caret = CurrentPresShellState()->mPresShell->GetCaret(); 1.870 + return caret; 1.871 +} 1.872 + 1.873 +void 1.874 +nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame, 1.875 + const nsRect& aDirtyRect) { 1.876 + PresShellState* state = mPresShellStates.AppendElement(); 1.877 + if (!state) 1.878 + return; 1.879 + state->mPresShell = aReferenceFrame->PresContext()->PresShell(); 1.880 + state->mCaretFrame = nullptr; 1.881 + state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length(); 1.882 + 1.883 + state->mPresShell->UpdateCanvasBackground(); 1.884 + 1.885 + if (mIsPaintingToWindow) { 1.886 + mReferenceFrame->AddPaintedPresShell(state->mPresShell); 1.887 + 1.888 + state->mPresShell->IncrementPaintCount(); 1.889 + } 1.890 + 1.891 + bool buildCaret = mBuildCaret; 1.892 + if (mIgnoreSuppression || !state->mPresShell->IsPaintingSuppressed()) { 1.893 + if (state->mPresShell->IsPaintingSuppressed()) { 1.894 + mHadToIgnoreSuppression = true; 1.895 + } 1.896 + state->mIsBackgroundOnly = false; 1.897 + } else { 1.898 + state->mIsBackgroundOnly = true; 1.899 + buildCaret = false; 1.900 + } 1.901 + 1.902 + if (!buildCaret) 1.903 + return; 1.904 + 1.905 + nsRefPtr<nsCaret> caret = state->mPresShell->GetCaret(); 1.906 + state->mCaretFrame = caret->GetCaretFrame(); 1.907 + NS_ASSERTION(state->mCaretFrame == caret->GetCaretFrame(), 1.908 + "GetCaretFrame() is unstable"); 1.909 + 1.910 + if (state->mCaretFrame) { 1.911 + // Check if the dirty rect intersects with the caret's dirty rect. 1.912 + nsRect caretRect = 1.913 + caret->GetCaretRect() + state->mCaretFrame->GetOffsetTo(aReferenceFrame); 1.914 + if (caretRect.Intersects(aDirtyRect)) { 1.915 + // Okay, our rects intersect, let's mark the frame and all of its ancestors. 1.916 + mFramesMarkedForDisplay.AppendElement(state->mCaretFrame); 1.917 + MarkFrameForDisplay(state->mCaretFrame, nullptr); 1.918 + } 1.919 + } 1.920 +} 1.921 + 1.922 +void 1.923 +nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame, 1.924 + const nsRect& aDirtyRect) { 1.925 + if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) { 1.926 + // Must have not allocated a state for this presshell, presumably due 1.927 + // to OOM. 1.928 + return; 1.929 + } 1.930 + 1.931 + ResetMarkedFramesForDisplayList(); 1.932 + mPresShellStates.SetLength(mPresShellStates.Length() - 1); 1.933 +} 1.934 + 1.935 +void 1.936 +nsDisplayListBuilder::ResetMarkedFramesForDisplayList() 1.937 +{ 1.938 + // Unmark and pop off the frames marked for display in this pres shell. 1.939 + uint32_t firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay; 1.940 + for (uint32_t i = firstFrameForShell; 1.941 + i < mFramesMarkedForDisplay.Length(); ++i) { 1.942 + UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]); 1.943 + } 1.944 + mFramesMarkedForDisplay.SetLength(firstFrameForShell); 1.945 +} 1.946 + 1.947 +void 1.948 +nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame, 1.949 + const nsFrameList& aFrames, 1.950 + const nsRect& aDirtyRect) { 1.951 + mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength()); 1.952 + for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) { 1.953 + mFramesMarkedForDisplay.AppendElement(e.get()); 1.954 + MarkOutOfFlowFrameForDisplay(aDirtyFrame, e.get(), aDirtyRect); 1.955 + } 1.956 +} 1.957 + 1.958 +void 1.959 +nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect) 1.960 +{ 1.961 + nsAutoTArray<nsIFrame::ChildList,4> childListArray; 1.962 + aDirtyFrame->GetChildLists(&childListArray); 1.963 + nsIFrame::ChildListArrayIterator lists(childListArray); 1.964 + for (; !lists.IsDone(); lists.Next()) { 1.965 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.966 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.967 + nsIFrame *child = childFrames.get(); 1.968 + if (child->Preserves3D()) { 1.969 + mFramesMarkedForDisplay.AppendElement(child); 1.970 + nsRect dirty = aDirtyRect - child->GetOffsetTo(aDirtyFrame); 1.971 + 1.972 + child->Properties().Set(nsDisplayListBuilder::Preserve3DDirtyRectProperty(), 1.973 + new nsRect(dirty)); 1.974 + 1.975 + MarkFrameForDisplay(child, aDirtyFrame); 1.976 + } 1.977 + } 1.978 + } 1.979 +} 1.980 + 1.981 +void* 1.982 +nsDisplayListBuilder::Allocate(size_t aSize) { 1.983 + void *tmp; 1.984 + PL_ARENA_ALLOCATE(tmp, &mPool, aSize); 1.985 + if (!tmp) { 1.986 + NS_RUNTIMEABORT("out of memory"); 1.987 + } 1.988 + return tmp; 1.989 +} 1.990 + 1.991 +const DisplayItemClip* 1.992 +nsDisplayListBuilder::AllocateDisplayItemClip(const DisplayItemClip& aOriginal) 1.993 +{ 1.994 + void* p = Allocate(sizeof(DisplayItemClip)); 1.995 + if (!aOriginal.GetRoundedRectCount()) { 1.996 + memcpy(p, &aOriginal, sizeof(DisplayItemClip)); 1.997 + return static_cast<DisplayItemClip*>(p); 1.998 + } 1.999 + 1.1000 + DisplayItemClip* c = new (p) DisplayItemClip(aOriginal); 1.1001 + mDisplayItemClipsToDestroy.AppendElement(c); 1.1002 + return c; 1.1003 +} 1.1004 + 1.1005 +void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const 1.1006 +{ 1.1007 + aDestination.BorderBackground()->AppendToTop(BorderBackground()); 1.1008 + aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds()); 1.1009 + aDestination.Floats()->AppendToTop(Floats()); 1.1010 + aDestination.Content()->AppendToTop(Content()); 1.1011 + aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants()); 1.1012 + aDestination.Outlines()->AppendToTop(Outlines()); 1.1013 +} 1.1014 + 1.1015 +void 1.1016 +nsDisplayList::FlattenTo(nsTArray<nsDisplayItem*>* aElements) { 1.1017 + nsDisplayItem* item; 1.1018 + while ((item = RemoveBottom()) != nullptr) { 1.1019 + if (item->GetType() == nsDisplayItem::TYPE_WRAP_LIST) { 1.1020 + item->GetSameCoordinateSystemChildren()->FlattenTo(aElements); 1.1021 + item->~nsDisplayItem(); 1.1022 + } else { 1.1023 + aElements->AppendElement(item); 1.1024 + } 1.1025 + } 1.1026 +} 1.1027 + 1.1028 +nsRect 1.1029 +nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const { 1.1030 + nsRect bounds; 1.1031 + for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) { 1.1032 + bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder)); 1.1033 + } 1.1034 + return bounds; 1.1035 +} 1.1036 + 1.1037 +bool 1.1038 +nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder, 1.1039 + nsRegion* aVisibleRegion, 1.1040 + nsIFrame* aDisplayPortFrame) { 1.1041 + PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot"); 1.1042 + nsRegion r; 1.1043 + r.And(*aVisibleRegion, GetBounds(aBuilder)); 1.1044 + return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, 1.1045 + r.GetBounds(), r.GetBounds(), 1.1046 + aDisplayPortFrame); 1.1047 +} 1.1048 + 1.1049 +static nsRegion 1.1050 +TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) 1.1051 +{ 1.1052 + bool snap; 1.1053 + nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap); 1.1054 + if (aBuilder->IsForPluginGeometry()) { 1.1055 + // Treat all leaf chrome items as opaque, unless their frames are opacity:0. 1.1056 + // Since opacity:0 frames generate an nsDisplayOpacity, that item will 1.1057 + // not be treated as opaque here, so opacity:0 chrome content will be 1.1058 + // effectively ignored, as it should be. 1.1059 + // We treat leaf chrome items as opaque to ensure that they cover 1.1060 + // content plugins, for security reasons. 1.1061 + // Non-leaf chrome items don't render contents of their own so shouldn't 1.1062 + // be treated as opaque (and their bounds is just the union of their 1.1063 + // children, which might be a large area their contents don't really cover). 1.1064 + nsIFrame* f = aItem->Frame(); 1.1065 + if (f->PresContext()->IsChrome() && !aItem->GetChildren() && 1.1066 + f->StyleDisplay()->mOpacity != 0.0) { 1.1067 + opaque = aItem->GetBounds(aBuilder, &snap); 1.1068 + } 1.1069 + } 1.1070 + if (opaque.IsEmpty()) { 1.1071 + return opaque; 1.1072 + } 1.1073 + nsRegion opaqueClipped; 1.1074 + nsRegionRectIterator iter(opaque); 1.1075 + for (const nsRect* r = iter.Next(); r; r = iter.Next()) { 1.1076 + opaqueClipped.Or(opaqueClipped, aItem->GetClip().ApproximateIntersectInward(*r)); 1.1077 + } 1.1078 + return opaqueClipped; 1.1079 +} 1.1080 + 1.1081 +/* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem 1.1082 + * is an overlay scrollbar item for the same scroll frame. 1.1083 + */ 1.1084 +static bool 1.1085 +IsScrollLayerItemAndOverlayScrollbarForScrollFrame( 1.1086 + nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem) 1.1087 +{ 1.1088 + if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER && 1.1089 + aPotentialScrollbarItem && 1.1090 + aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER && 1.1091 + LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) { 1.1092 + nsDisplayScrollLayer* scrollItem = 1.1093 + static_cast<nsDisplayScrollLayer*>(aPotentialScrollItem); 1.1094 + nsDisplayOwnLayer* layerItem = 1.1095 + static_cast<nsDisplayOwnLayer*>(aPotentialScrollbarItem); 1.1096 + if ((layerItem->GetFlags() & 1.1097 + (nsDisplayOwnLayer::VERTICAL_SCROLLBAR | 1.1098 + nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) && 1.1099 + layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) { 1.1100 + return true; 1.1101 + } 1.1102 + } 1.1103 + return false; 1.1104 +} 1.1105 + 1.1106 +bool 1.1107 +nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, 1.1108 + nsRegion* aVisibleRegion, 1.1109 + const nsRect& aListVisibleBounds, 1.1110 + const nsRect& aAllowVisibleRegionExpansion, 1.1111 + nsIFrame* aDisplayPortFrame) { 1.1112 +#ifdef DEBUG 1.1113 + nsRegion r; 1.1114 + r.And(*aVisibleRegion, GetBounds(aBuilder)); 1.1115 + NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds), 1.1116 + "bad aListVisibleBounds"); 1.1117 +#endif 1.1118 + 1.1119 + mVisibleRect = aListVisibleBounds; 1.1120 + bool anyVisible = false; 1.1121 + 1.1122 + nsAutoTArray<nsDisplayItem*, 512> elements; 1.1123 + FlattenTo(&elements); 1.1124 + 1.1125 + bool forceTransparentSurface = false; 1.1126 + 1.1127 + for (int32_t i = elements.Length() - 1; i >= 0; --i) { 1.1128 + nsDisplayItem* item = elements[i]; 1.1129 + nsDisplayItem* belowItem = i < 1 ? nullptr : elements[i - 1]; 1.1130 + 1.1131 + nsDisplayList* list = item->GetSameCoordinateSystemChildren(); 1.1132 + if (aBuilder->AllowMergingAndFlattening()) { 1.1133 + if (belowItem && item->TryMerge(aBuilder, belowItem)) { 1.1134 + belowItem->~nsDisplayItem(); 1.1135 + elements.ReplaceElementsAt(i - 1, 1, item); 1.1136 + continue; 1.1137 + } 1.1138 + 1.1139 + // If an overlay scrollbar item is between a scroll layer item and the 1.1140 + // other scroll layer items that we need to merge with just move the 1.1141 + // scrollbar item up, that way it will be on top of the scrolled content 1.1142 + // and we can try to merge all the scroll layer items. 1.1143 + if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(item, belowItem)) { 1.1144 + elements[i] = belowItem; 1.1145 + elements[i-1] = item; 1.1146 + i++; 1.1147 + continue; 1.1148 + } 1.1149 + 1.1150 + if (list && item->ShouldFlattenAway(aBuilder)) { 1.1151 + // The elements on the list >= i no longer serve any use. 1.1152 + elements.SetLength(i); 1.1153 + list->FlattenTo(&elements); 1.1154 + i = elements.Length(); 1.1155 + item->~nsDisplayItem(); 1.1156 + continue; 1.1157 + } 1.1158 + } 1.1159 + 1.1160 + nsRect bounds = item->GetClippedBounds(aBuilder); 1.1161 + 1.1162 + nsRegion itemVisible; 1.1163 + itemVisible.And(*aVisibleRegion, bounds); 1.1164 + item->mVisibleRect = itemVisible.GetBounds(); 1.1165 + 1.1166 + if (item->ComputeVisibility(aBuilder, aVisibleRegion, 1.1167 + aAllowVisibleRegionExpansion.Intersect(bounds))) { 1.1168 + anyVisible = true; 1.1169 + 1.1170 + // If we're in a displayport, we need to make sure that fixed position 1.1171 + // items do not subtract from the visible region, as async scrolling 1.1172 + // may expose these occluded areas. 1.1173 + // If the item is fixed pos in the same document as the displayport 1.1174 + // then don't let it occlude this list. The only other case possible 1.1175 + // is that the fixed pos content is in a child document, in which it 1.1176 + // would scroll with the rest of the content. 1.1177 + bool occlude = true; 1.1178 + if (aDisplayPortFrame && item->IsInFixedPos()) { 1.1179 + if (item->Frame()->PresContext() == aDisplayPortFrame->PresContext()) { 1.1180 + occlude = false; 1.1181 + } 1.1182 + } 1.1183 + 1.1184 + if (occlude) { 1.1185 + nsRegion opaque = TreatAsOpaque(item, aBuilder); 1.1186 + // Subtract opaque item from the visible region 1.1187 + aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque); 1.1188 + } 1.1189 + 1.1190 + if (aBuilder->NeedToForceTransparentSurfaceForItem(item) || 1.1191 + (list && list->NeedsTransparentSurface())) { 1.1192 + forceTransparentSurface = true; 1.1193 + } 1.1194 + } 1.1195 + AppendToBottom(item); 1.1196 + } 1.1197 + 1.1198 + mIsOpaque = !aVisibleRegion->Intersects(mVisibleRect); 1.1199 + mForceTransparentSurface = forceTransparentSurface; 1.1200 +#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) 1.1201 + mDidComputeVisibility = true; 1.1202 +#endif 1.1203 + return anyVisible; 1.1204 +} 1.1205 + 1.1206 +void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, 1.1207 + nsRenderingContext* aCtx, 1.1208 + uint32_t aFlags) const { 1.1209 + PROFILER_LABEL("nsDisplayList", "PaintRoot"); 1.1210 + PaintForFrame(aBuilder, aCtx, aBuilder->RootReferenceFrame(), aFlags); 1.1211 +} 1.1212 + 1.1213 +/** 1.1214 + * We paint by executing a layer manager transaction, constructing a 1.1215 + * single layer representing the display list, and then making it the 1.1216 + * root of the layer manager, drawing into the ThebesLayers. 1.1217 + */ 1.1218 +void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, 1.1219 + nsRenderingContext* aCtx, 1.1220 + nsIFrame* aForFrame, 1.1221 + uint32_t aFlags) const { 1.1222 + NS_ASSERTION(mDidComputeVisibility, 1.1223 + "Must call ComputeVisibility before calling Paint"); 1.1224 + 1.1225 + nsRefPtr<LayerManager> layerManager; 1.1226 + bool widgetTransaction = false; 1.1227 + bool allowRetaining = false; 1.1228 + bool doBeginTransaction = true; 1.1229 + nsView *view = nullptr; 1.1230 + if (aFlags & PAINT_USE_WIDGET_LAYERS) { 1.1231 + nsIFrame* rootReferenceFrame = aBuilder->RootReferenceFrame(); 1.1232 + view = rootReferenceFrame->GetView(); 1.1233 + NS_ASSERTION(rootReferenceFrame == nsLayoutUtils::GetDisplayRootFrame(rootReferenceFrame), 1.1234 + "Reference frame must be a display root for us to use the layer manager"); 1.1235 + nsIWidget* window = rootReferenceFrame->GetNearestWidget(); 1.1236 + if (window) { 1.1237 + layerManager = window->GetLayerManager(&allowRetaining); 1.1238 + if (layerManager) { 1.1239 + doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION); 1.1240 + widgetTransaction = true; 1.1241 + } 1.1242 + } 1.1243 + } 1.1244 + if (!layerManager) { 1.1245 + if (!aCtx) { 1.1246 + NS_WARNING("Nowhere to paint into"); 1.1247 + return; 1.1248 + } 1.1249 + layerManager = new BasicLayerManager(); 1.1250 + } 1.1251 + 1.1252 + // Store the existing layer builder to reinstate it on return. 1.1253 + FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder(); 1.1254 + 1.1255 + FrameLayerBuilder *layerBuilder = new FrameLayerBuilder(); 1.1256 + layerBuilder->Init(aBuilder, layerManager); 1.1257 + 1.1258 + if (aFlags & PAINT_COMPRESSED) { 1.1259 + layerBuilder->SetLayerTreeCompressionMode(); 1.1260 + } 1.1261 + 1.1262 + if (aFlags & PAINT_FLUSH_LAYERS) { 1.1263 + FrameLayerBuilder::InvalidateAllLayers(layerManager); 1.1264 + } 1.1265 + 1.1266 + if (doBeginTransaction) { 1.1267 + if (aCtx) { 1.1268 + layerManager->BeginTransactionWithTarget(aCtx->ThebesContext()); 1.1269 + } else { 1.1270 + layerManager->BeginTransaction(); 1.1271 + } 1.1272 + } 1.1273 + if (widgetTransaction) { 1.1274 + layerBuilder->DidBeginRetainedLayerTransaction(layerManager); 1.1275 + } 1.1276 + 1.1277 + nsPresContext* presContext = aForFrame->PresContext(); 1.1278 + nsIPresShell* presShell = presContext->GetPresShell(); 1.1279 + 1.1280 + NotifySubDocInvalidationFunc computeInvalidFunc = 1.1281 + presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0; 1.1282 + bool computeInvalidRect = (computeInvalidFunc || 1.1283 + (!layerManager->IsCompositingCheap() && layerManager->NeedsWidgetInvalidation())) && 1.1284 + widgetTransaction; 1.1285 + 1.1286 + nsAutoPtr<LayerProperties> props(computeInvalidRect ? 1.1287 + LayerProperties::CloneFrom(layerManager->GetRoot()) : 1.1288 + nullptr); 1.1289 + 1.1290 + ContainerLayerParameters containerParameters 1.1291 + (presShell->GetXResolution(), presShell->GetYResolution()); 1.1292 + nsRefPtr<ContainerLayer> root = layerBuilder-> 1.1293 + BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this, 1.1294 + containerParameters, nullptr); 1.1295 + 1.1296 + nsIDocument* document = nullptr; 1.1297 + if (presShell) { 1.1298 + document = presShell->GetDocument(); 1.1299 + } 1.1300 + 1.1301 + if (widgetTransaction || 1.1302 + // SVG-as-an-image docs don't paint as part of the retained layer tree, 1.1303 + // but they still need the invalidation state bits cleared in order for 1.1304 + // invalidation for CSS/SMIL animation to work properly. 1.1305 + (document && document->IsBeingUsedAsImage())) { 1.1306 + aForFrame->ClearInvalidationStateBits(); 1.1307 + } 1.1308 + 1.1309 + if (!root) { 1.1310 + layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder); 1.1311 + return; 1.1312 + } 1.1313 + // Root is being scaled up by the X/Y resolution. Scale it back down. 1.1314 + root->SetPostScale(1.0f/containerParameters.mXScale, 1.1315 + 1.0f/containerParameters.mYScale); 1.1316 + 1.1317 + ViewID id = FrameMetrics::NULL_SCROLL_ID; 1.1318 + bool isRoot = presContext->IsRootContentDocument(); 1.1319 + 1.1320 + nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); 1.1321 + nsRect displayport, criticalDisplayport; 1.1322 + bool usingDisplayport = false; 1.1323 + bool usingCriticalDisplayport = false; 1.1324 + if (rootScrollFrame) { 1.1325 + nsIContent* content = rootScrollFrame->GetContent(); 1.1326 + if (content) { 1.1327 + usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport); 1.1328 + usingCriticalDisplayport = 1.1329 + nsLayoutUtils::GetCriticalDisplayPort(content, &criticalDisplayport); 1.1330 + 1.1331 + // If this is the root content document, we want it to have a scroll id. 1.1332 + if (isRoot) { 1.1333 + id = nsLayoutUtils::FindOrCreateIDFor(content); 1.1334 + } 1.1335 + } 1.1336 + } 1.1337 + 1.1338 + nsRect viewport(aBuilder->ToReferenceFrame(aForFrame), aForFrame->GetSize()); 1.1339 + 1.1340 + RecordFrameMetrics(aForFrame, rootScrollFrame, 1.1341 + aBuilder->FindReferenceFrameFor(aForFrame), 1.1342 + root, mVisibleRect, viewport, 1.1343 + (usingDisplayport ? &displayport : nullptr), 1.1344 + (usingCriticalDisplayport ? &criticalDisplayport : nullptr), 1.1345 + id, isRoot, containerParameters); 1.1346 + if (usingDisplayport && 1.1347 + !(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) { 1.1348 + // See bug 693938, attachment 567017 1.1349 + NS_WARNING("Transparent content with displayports can be expensive."); 1.1350 + } 1.1351 + 1.1352 + layerManager->SetRoot(root); 1.1353 + layerBuilder->WillEndTransaction(); 1.1354 + bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap()); 1.1355 + LayerManager::EndTransactionFlags flags = LayerManager::END_DEFAULT; 1.1356 + if (layerManager->NeedsWidgetInvalidation()) { 1.1357 + if (aFlags & PAINT_NO_COMPOSITE) { 1.1358 + flags = LayerManager::END_NO_COMPOSITE; 1.1359 + } 1.1360 + } else { 1.1361 + // Client layer managers never composite directly, so 1.1362 + // we don't need to worry about END_NO_COMPOSITE. 1.1363 + if (aBuilder->WillComputePluginGeometry()) { 1.1364 + flags = LayerManager::END_NO_REMOTE_COMPOSITE; 1.1365 + } 1.1366 + } 1.1367 + 1.1368 + layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, 1.1369 + aBuilder, flags); 1.1370 + aBuilder->SetIsCompositingCheap(temp); 1.1371 + layerBuilder->DidEndTransaction(); 1.1372 + 1.1373 + nsIntRegion invalid; 1.1374 + if (props) { 1.1375 + invalid = props->ComputeDifferences(root, computeInvalidFunc); 1.1376 + } else if (widgetTransaction) { 1.1377 + LayerProperties::ClearInvalidations(root); 1.1378 + } 1.1379 + 1.1380 + bool shouldInvalidate = layerManager->NeedsWidgetInvalidation(); 1.1381 + if (view) { 1.1382 + if (props) { 1.1383 + if (!invalid.IsEmpty()) { 1.1384 + nsIntRect bounds = invalid.GetBounds(); 1.1385 + nsRect rect(presContext->DevPixelsToAppUnits(bounds.x), 1.1386 + presContext->DevPixelsToAppUnits(bounds.y), 1.1387 + presContext->DevPixelsToAppUnits(bounds.width), 1.1388 + presContext->DevPixelsToAppUnits(bounds.height)); 1.1389 + if (shouldInvalidate) { 1.1390 + view->GetViewManager()->InvalidateViewNoSuppression(view, rect); 1.1391 + } 1.1392 + presContext->NotifyInvalidation(bounds, 0); 1.1393 + } 1.1394 + } else if (shouldInvalidate) { 1.1395 + view->GetViewManager()->InvalidateView(view); 1.1396 + } 1.1397 + } 1.1398 + 1.1399 + if (aFlags & PAINT_FLUSH_LAYERS) { 1.1400 + FrameLayerBuilder::InvalidateAllLayers(layerManager); 1.1401 + } 1.1402 + 1.1403 + layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder); 1.1404 +} 1.1405 + 1.1406 +uint32_t nsDisplayList::Count() const { 1.1407 + uint32_t count = 0; 1.1408 + for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) { 1.1409 + ++count; 1.1410 + } 1.1411 + return count; 1.1412 +} 1.1413 + 1.1414 +nsDisplayItem* nsDisplayList::RemoveBottom() { 1.1415 + nsDisplayItem* item = mSentinel.mAbove; 1.1416 + if (!item) 1.1417 + return nullptr; 1.1418 + mSentinel.mAbove = item->mAbove; 1.1419 + if (item == mTop) { 1.1420 + // must have been the only item 1.1421 + mTop = &mSentinel; 1.1422 + } 1.1423 + item->mAbove = nullptr; 1.1424 + return item; 1.1425 +} 1.1426 + 1.1427 +void nsDisplayList::DeleteAll() { 1.1428 + nsDisplayItem* item; 1.1429 + while ((item = RemoveBottom()) != nullptr) { 1.1430 + item->~nsDisplayItem(); 1.1431 + } 1.1432 +} 1.1433 + 1.1434 +static bool 1.1435 +GetMouseThrough(const nsIFrame* aFrame) 1.1436 +{ 1.1437 + if (!aFrame->IsBoxFrame()) 1.1438 + return false; 1.1439 + 1.1440 + const nsIFrame* frame = aFrame; 1.1441 + while (frame) { 1.1442 + if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_ALWAYS) { 1.1443 + return true; 1.1444 + } else if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER) { 1.1445 + return false; 1.1446 + } 1.1447 + frame = frame->GetParentBox(); 1.1448 + } 1.1449 + return false; 1.1450 +} 1.1451 + 1.1452 +static bool 1.1453 +IsFrameReceivingPointerEvents(nsIFrame* aFrame) 1.1454 +{ 1.1455 + nsSubDocumentFrame* frame = do_QueryFrame(aFrame); 1.1456 + if (frame && frame->PassPointerEventsToChildren()) { 1.1457 + return true; 1.1458 + } 1.1459 + return NS_STYLE_POINTER_EVENTS_NONE != 1.1460 + aFrame->StyleVisibility()->GetEffectivePointerEvents(aFrame); 1.1461 +} 1.1462 + 1.1463 +// A list of frames, and their z depth. Used for sorting 1.1464 +// the results of hit testing. 1.1465 +struct FramesWithDepth 1.1466 +{ 1.1467 + FramesWithDepth(float aDepth) : 1.1468 + mDepth(aDepth) 1.1469 + {} 1.1470 + 1.1471 + bool operator<(const FramesWithDepth& aOther) const { 1.1472 + if (mDepth != aOther.mDepth) { 1.1473 + // We want to sort so that the shallowest item (highest depth value) is first 1.1474 + return mDepth > aOther.mDepth; 1.1475 + } 1.1476 + return this < &aOther; 1.1477 + } 1.1478 + bool operator==(const FramesWithDepth& aOther) const { 1.1479 + return this == &aOther; 1.1480 + } 1.1481 + 1.1482 + float mDepth; 1.1483 + nsTArray<nsIFrame*> mFrames; 1.1484 +}; 1.1485 + 1.1486 +// Sort the frames by depth and then moves all the contained frames to the destination 1.1487 +void FlushFramesArray(nsTArray<FramesWithDepth>& aSource, nsTArray<nsIFrame*>* aDest) 1.1488 +{ 1.1489 + if (aSource.IsEmpty()) { 1.1490 + return; 1.1491 + } 1.1492 + aSource.Sort(); 1.1493 + uint32_t length = aSource.Length(); 1.1494 + for (uint32_t i = 0; i < length; i++) { 1.1495 + aDest->MoveElementsFrom(aSource[i].mFrames); 1.1496 + } 1.1497 + aSource.Clear(); 1.1498 +} 1.1499 + 1.1500 +void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.1501 + nsDisplayItem::HitTestState* aState, 1.1502 + nsTArray<nsIFrame*> *aOutFrames) const { 1.1503 + int32_t itemBufferStart = aState->mItemBuffer.Length(); 1.1504 + nsDisplayItem* item; 1.1505 + for (item = GetBottom(); item; item = item->GetAbove()) { 1.1506 + aState->mItemBuffer.AppendElement(item); 1.1507 + } 1.1508 + nsAutoTArray<FramesWithDepth, 16> temp; 1.1509 + for (int32_t i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart; --i) { 1.1510 + // Pop element off the end of the buffer. We want to shorten the buffer 1.1511 + // so that recursive calls to HitTest have more buffer space. 1.1512 + item = aState->mItemBuffer[i]; 1.1513 + aState->mItemBuffer.SetLength(i); 1.1514 + 1.1515 + bool snap; 1.1516 + nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect); 1.1517 + if (item->GetClip().MayIntersect(r)) { 1.1518 + nsAutoTArray<nsIFrame*, 16> outFrames; 1.1519 + item->HitTest(aBuilder, aRect, aState, &outFrames); 1.1520 + 1.1521 + // For 3d transforms with preserve-3d we add hit frames into the temp list 1.1522 + // so we can sort them later, otherwise we add them directly to the output list. 1.1523 + nsTArray<nsIFrame*> *writeFrames = aOutFrames; 1.1524 + if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM && 1.1525 + item->Frame()->Preserves3D()) { 1.1526 + if (outFrames.Length()) { 1.1527 + nsDisplayTransform *transform = static_cast<nsDisplayTransform*>(item); 1.1528 + nsPoint point = aRect.TopLeft(); 1.1529 + // A 1x1 rect means a point, otherwise use the center of the rect 1.1530 + if (aRect.width != 1 || aRect.height != 1) { 1.1531 + point = aRect.Center(); 1.1532 + } 1.1533 + temp.AppendElement(FramesWithDepth(transform->GetHitDepthAtPoint(aBuilder, point))); 1.1534 + writeFrames = &temp[temp.Length() - 1].mFrames; 1.1535 + } 1.1536 + } else { 1.1537 + // We may have just finished a run of consecutive preserve-3d transforms, 1.1538 + // so flush these into the destination array before processing our frame list. 1.1539 + FlushFramesArray(temp, aOutFrames); 1.1540 + } 1.1541 + 1.1542 + for (uint32_t j = 0; j < outFrames.Length(); j++) { 1.1543 + nsIFrame *f = outFrames.ElementAt(j); 1.1544 + // Handle the XUL 'mousethrough' feature and 'pointer-events'. 1.1545 + if (!GetMouseThrough(f) && IsFrameReceivingPointerEvents(f)) { 1.1546 + writeFrames->AppendElement(f); 1.1547 + } 1.1548 + } 1.1549 + } 1.1550 + } 1.1551 + // Clear any remaining preserve-3d transforms. 1.1552 + FlushFramesArray(temp, aOutFrames); 1.1553 + NS_ASSERTION(aState->mItemBuffer.Length() == uint32_t(itemBufferStart), 1.1554 + "How did we forget to pop some elements?"); 1.1555 +} 1.1556 + 1.1557 +static void Sort(nsDisplayList* aList, int32_t aCount, nsDisplayList::SortLEQ aCmp, 1.1558 + void* aClosure) { 1.1559 + if (aCount < 2) 1.1560 + return; 1.1561 + 1.1562 + nsDisplayList list1; 1.1563 + nsDisplayList list2; 1.1564 + int i; 1.1565 + int32_t half = aCount/2; 1.1566 + bool sorted = true; 1.1567 + nsDisplayItem* prev = nullptr; 1.1568 + for (i = 0; i < aCount; ++i) { 1.1569 + nsDisplayItem* item = aList->RemoveBottom(); 1.1570 + (i < half ? &list1 : &list2)->AppendToTop(item); 1.1571 + if (sorted && prev && !aCmp(prev, item, aClosure)) { 1.1572 + sorted = false; 1.1573 + } 1.1574 + prev = item; 1.1575 + } 1.1576 + if (sorted) { 1.1577 + aList->AppendToTop(&list1); 1.1578 + aList->AppendToTop(&list2); 1.1579 + return; 1.1580 + } 1.1581 + 1.1582 + Sort(&list1, half, aCmp, aClosure); 1.1583 + Sort(&list2, aCount - half, aCmp, aClosure); 1.1584 + 1.1585 + for (i = 0; i < aCount; ++i) { 1.1586 + if (list1.GetBottom() && 1.1587 + (!list2.GetBottom() || 1.1588 + aCmp(list1.GetBottom(), list2.GetBottom(), aClosure))) { 1.1589 + aList->AppendToTop(list1.RemoveBottom()); 1.1590 + } else { 1.1591 + aList->AppendToTop(list2.RemoveBottom()); 1.1592 + } 1.1593 + } 1.1594 +} 1.1595 + 1.1596 +static nsIContent* FindContentInDocument(nsDisplayItem* aItem, nsIDocument* aDoc) { 1.1597 + nsIFrame* f = aItem->Frame(); 1.1598 + while (f) { 1.1599 + nsPresContext* pc = f->PresContext(); 1.1600 + if (pc->Document() == aDoc) { 1.1601 + return f->GetContent(); 1.1602 + } 1.1603 + f = nsLayoutUtils::GetCrossDocParentFrame(pc->PresShell()->GetRootFrame()); 1.1604 + } 1.1605 + return nullptr; 1.1606 +} 1.1607 + 1.1608 +static bool IsContentLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2, 1.1609 + void* aClosure) { 1.1610 + nsIContent* commonAncestor = static_cast<nsIContent*>(aClosure); 1.1611 + // It's possible that the nsIContent for aItem1 or aItem2 is in a subdocument 1.1612 + // of commonAncestor, because display items for subdocuments have been 1.1613 + // mixed into the same list. Ensure that we're looking at content 1.1614 + // in commonAncestor's document. 1.1615 + nsIDocument* commonAncestorDoc = commonAncestor->OwnerDoc(); 1.1616 + nsIContent* content1 = FindContentInDocument(aItem1, commonAncestorDoc); 1.1617 + nsIContent* content2 = FindContentInDocument(aItem2, commonAncestorDoc); 1.1618 + if (!content1 || !content2) { 1.1619 + NS_ERROR("Document trees are mixed up!"); 1.1620 + // Something weird going on 1.1621 + return true; 1.1622 + } 1.1623 + return nsLayoutUtils::CompareTreePosition(content1, content2, commonAncestor) <= 0; 1.1624 +} 1.1625 + 1.1626 +static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2, 1.1627 + void* aClosure) { 1.1628 + // Note that we can't just take the difference of the two 1.1629 + // z-indices here, because that might overflow a 32-bit int. 1.1630 + return aItem1->ZIndex() <= aItem2->ZIndex(); 1.1631 +} 1.1632 + 1.1633 +void nsDisplayList::SortByZOrder(nsDisplayListBuilder* aBuilder, 1.1634 + nsIContent* aCommonAncestor) { 1.1635 + Sort(aBuilder, IsZOrderLEQ, aCommonAncestor); 1.1636 +} 1.1637 + 1.1638 +void nsDisplayList::SortByContentOrder(nsDisplayListBuilder* aBuilder, 1.1639 + nsIContent* aCommonAncestor) { 1.1640 + Sort(aBuilder, IsContentLEQ, aCommonAncestor); 1.1641 +} 1.1642 + 1.1643 +void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder, 1.1644 + SortLEQ aCmp, void* aClosure) { 1.1645 + ::Sort(this, Count(), aCmp, aClosure); 1.1646 +} 1.1647 + 1.1648 +void 1.1649 +nsDisplayItem::AddInvalidRegionForSyncDecodeBackgroundImages( 1.1650 + nsDisplayListBuilder* aBuilder, 1.1651 + const nsDisplayItemGeometry* aGeometry, 1.1652 + nsRegion* aInvalidRegion) 1.1653 +{ 1.1654 + if (aBuilder->ShouldSyncDecodeImages()) { 1.1655 + if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) { 1.1656 + bool snap; 1.1657 + aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap)); 1.1658 + } 1.1659 + } 1.1660 +} 1.1661 + 1.1662 +/* static */ bool 1.1663 +nsDisplayItem::ForceActiveLayers() 1.1664 +{ 1.1665 + static bool sForce = false; 1.1666 + static bool sForceCached = false; 1.1667 + 1.1668 + if (!sForceCached) { 1.1669 + Preferences::AddBoolVarCache(&sForce, "layers.force-active", false); 1.1670 + sForceCached = true; 1.1671 + } 1.1672 + 1.1673 + return sForce; 1.1674 +} 1.1675 + 1.1676 +/* static */ int32_t 1.1677 +nsDisplayItem::MaxActiveLayers() 1.1678 +{ 1.1679 + static int32_t sMaxLayers = false; 1.1680 + static bool sMaxLayersCached = false; 1.1681 + 1.1682 + if (!sMaxLayersCached) { 1.1683 + Preferences::AddIntVarCache(&sMaxLayers, "layers.max-active", -1); 1.1684 + sMaxLayersCached = true; 1.1685 + } 1.1686 + 1.1687 + return sMaxLayers; 1.1688 +} 1.1689 + 1.1690 +int32_t 1.1691 +nsDisplayItem::ZIndex() const 1.1692 +{ 1.1693 + if (!mFrame->IsPositioned() && !mFrame->IsFlexItem()) 1.1694 + return 0; 1.1695 + 1.1696 + const nsStylePosition* position = mFrame->StylePosition(); 1.1697 + if (position->mZIndex.GetUnit() == eStyleUnit_Integer) 1.1698 + return position->mZIndex.GetIntValue(); 1.1699 + 1.1700 + // sort the auto and 0 elements together 1.1701 + return 0; 1.1702 +} 1.1703 + 1.1704 +bool 1.1705 +nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, 1.1706 + nsRegion* aVisibleRegion) { 1.1707 + nsRect bounds = GetClippedBounds(aBuilder); 1.1708 + 1.1709 + nsRegion itemVisible; 1.1710 + itemVisible.And(*aVisibleRegion, bounds); 1.1711 + mVisibleRect = itemVisible.GetBounds(); 1.1712 + 1.1713 + // When we recompute visibility within layers we don't need to 1.1714 + // expand the visible region for content behind plugins (the plugin 1.1715 + // is not in the layer). 1.1716 + if (!ComputeVisibility(aBuilder, aVisibleRegion, nsRect())) 1.1717 + return false; 1.1718 + 1.1719 + nsRegion opaque = TreatAsOpaque(this, aBuilder); 1.1720 + aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque); 1.1721 + return true; 1.1722 +} 1.1723 + 1.1724 +nsRect 1.1725 +nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder) 1.1726 +{ 1.1727 + bool snap; 1.1728 + nsRect r = GetBounds(aBuilder, &snap); 1.1729 + return GetClip().ApplyNonRoundedIntersection(r); 1.1730 +} 1.1731 + 1.1732 +nsRect 1.1733 +nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) 1.1734 +{ 1.1735 + *aSnap = true; 1.1736 + return mBounds; 1.1737 +} 1.1738 + 1.1739 +void 1.1740 +nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder, 1.1741 + nsRenderingContext* aCtx) 1.1742 +{ 1.1743 + aCtx->SetColor(mColor); 1.1744 + aCtx->FillRect(mVisibleRect); 1.1745 +} 1.1746 + 1.1747 +#ifdef MOZ_DUMP_PAINTING 1.1748 +void 1.1749 +nsDisplaySolidColor::WriteDebugInfo(nsACString& aTo) 1.1750 +{ 1.1751 + aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)", 1.1752 + NS_GET_R(mColor), NS_GET_G(mColor), 1.1753 + NS_GET_B(mColor), NS_GET_A(mColor)); 1.1754 +} 1.1755 +#endif 1.1756 + 1.1757 +static void 1.1758 +RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) 1.1759 +{ 1.1760 + nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame); 1.1761 + 1.1762 + for (nsIFrame* f = aFrame; f; f = f->GetParent()) { 1.1763 + // Bail out if we're in a transformed subtree 1.1764 + if (f->IsTransformed()) 1.1765 + return; 1.1766 + // Bail out if we're not in the displayRoot's document 1.1767 + if (!f->GetParent() && f != displayRoot) 1.1768 + return; 1.1769 + } 1.1770 + 1.1771 + nsRect borderBox(aFrame->GetOffsetTo(displayRoot), aFrame->GetSize()); 1.1772 + aBuilder->RegisterThemeGeometry(aFrame->StyleDisplay()->mAppearance, 1.1773 + borderBox.ToNearestPixels(aFrame->PresContext()->AppUnitsPerDevPixel())); 1.1774 +} 1.1775 + 1.1776 +nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder, 1.1777 + nsIFrame* aFrame, 1.1778 + uint32_t aLayer, 1.1779 + const nsStyleBackground* aBackgroundStyle) 1.1780 + : nsDisplayImageContainer(aBuilder, aFrame) 1.1781 + , mBackgroundStyle(aBackgroundStyle) 1.1782 + , mLayer(aLayer) 1.1783 +{ 1.1784 + MOZ_COUNT_CTOR(nsDisplayBackgroundImage); 1.1785 + 1.1786 + mBounds = GetBoundsInternal(aBuilder); 1.1787 +} 1.1788 + 1.1789 +nsDisplayBackgroundImage::~nsDisplayBackgroundImage() 1.1790 +{ 1.1791 +#ifdef NS_BUILD_REFCNT_LOGGING 1.1792 + MOZ_COUNT_DTOR(nsDisplayBackgroundImage); 1.1793 +#endif 1.1794 +} 1.1795 + 1.1796 +static nsStyleContext* GetBackgroundStyleContext(nsIFrame* aFrame) 1.1797 +{ 1.1798 + nsStyleContext *sc; 1.1799 + if (!nsCSSRendering::FindBackground(aFrame, &sc)) { 1.1800 + // We don't want to bail out if moz-appearance is set on a root 1.1801 + // node. If it has a parent content node, bail because it's not 1.1802 + // a root, other wise keep going in order to let the theme stuff 1.1803 + // draw the background. The canvas really should be drawing the 1.1804 + // bg, but there's no way to hook that up via css. 1.1805 + if (!aFrame->StyleDisplay()->mAppearance) { 1.1806 + return nullptr; 1.1807 + } 1.1808 + 1.1809 + nsIContent* content = aFrame->GetContent(); 1.1810 + if (!content || content->GetParent()) { 1.1811 + return nullptr; 1.1812 + } 1.1813 + 1.1814 + sc = aFrame->StyleContext(); 1.1815 + } 1.1816 + return sc; 1.1817 +} 1.1818 + 1.1819 +/*static*/ bool 1.1820 +nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder, 1.1821 + nsIFrame* aFrame, 1.1822 + nsDisplayList* aList) 1.1823 +{ 1.1824 + nsStyleContext* bgSC = nullptr; 1.1825 + const nsStyleBackground* bg = nullptr; 1.1826 + nsPresContext* presContext = aFrame->PresContext(); 1.1827 + bool isThemed = aFrame->IsThemed(); 1.1828 + if (!isThemed) { 1.1829 + bgSC = GetBackgroundStyleContext(aFrame); 1.1830 + if (bgSC) { 1.1831 + bg = bgSC->StyleBackground(); 1.1832 + } 1.1833 + } 1.1834 + 1.1835 + bool drawBackgroundColor = false; 1.1836 + nscolor color; 1.1837 + if (!nsCSSRendering::IsCanvasFrame(aFrame) && bg) { 1.1838 + bool drawBackgroundImage; 1.1839 + color = 1.1840 + nsCSSRendering::DetermineBackgroundColor(presContext, bgSC, aFrame, 1.1841 + drawBackgroundImage, drawBackgroundColor); 1.1842 + } 1.1843 + 1.1844 + // An auxiliary list is necessary in case we have background blending; if that 1.1845 + // is the case, background items need to be wrapped by a blend container to 1.1846 + // isolate blending to the background 1.1847 + nsDisplayList bgItemList; 1.1848 + // Even if we don't actually have a background color to paint, we may still need 1.1849 + // to create an item for hit testing. 1.1850 + if ((drawBackgroundColor && color != NS_RGBA(0,0,0,0)) || 1.1851 + aBuilder->IsForEventDelivery()) { 1.1852 + bgItemList.AppendNewToTop( 1.1853 + new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame, bg, 1.1854 + drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0))); 1.1855 + } 1.1856 + 1.1857 + if (isThemed) { 1.1858 + nsDisplayThemedBackground* bgItem = 1.1859 + new (aBuilder) nsDisplayThemedBackground(aBuilder, aFrame); 1.1860 + bgItemList.AppendNewToTop(bgItem); 1.1861 + aList->AppendToTop(&bgItemList); 1.1862 + return true; 1.1863 + } 1.1864 + 1.1865 + if (!bg) { 1.1866 + aList->AppendToTop(&bgItemList); 1.1867 + return false; 1.1868 + } 1.1869 + 1.1870 + bool needBlendContainer = false; 1.1871 + 1.1872 + // Passing bg == nullptr in this macro will result in one iteration with 1.1873 + // i = 0. 1.1874 + NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) { 1.1875 + if (bg->mLayers[i].mImage.IsEmpty()) { 1.1876 + continue; 1.1877 + } 1.1878 + 1.1879 + if (bg->mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) { 1.1880 + needBlendContainer = true; 1.1881 + } 1.1882 + 1.1883 + nsDisplayBackgroundImage* bgItem = 1.1884 + new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bg); 1.1885 + bgItemList.AppendNewToTop(bgItem); 1.1886 + } 1.1887 + 1.1888 + if (needBlendContainer) { 1.1889 + bgItemList.AppendNewToTop( 1.1890 + new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, &bgItemList)); 1.1891 + } 1.1892 + 1.1893 + aList->AppendToTop(&bgItemList); 1.1894 + return false; 1.1895 +} 1.1896 + 1.1897 +// Check that the rounded border of aFrame, added to aToReferenceFrame, 1.1898 +// intersects aRect. Assumes that the unrounded border has already 1.1899 +// been checked for intersection. 1.1900 +static bool 1.1901 +RoundedBorderIntersectsRect(nsIFrame* aFrame, 1.1902 + const nsPoint& aFrameToReferenceFrame, 1.1903 + const nsRect& aTestRect) 1.1904 +{ 1.1905 + if (!nsRect(aFrameToReferenceFrame, aFrame->GetSize()).Intersects(aTestRect)) 1.1906 + return false; 1.1907 + 1.1908 + nscoord radii[8]; 1.1909 + return !aFrame->GetBorderRadii(radii) || 1.1910 + nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame, 1.1911 + aFrame->GetSize()), 1.1912 + radii, aTestRect); 1.1913 +} 1.1914 + 1.1915 +// Returns TRUE if aContainedRect is guaranteed to be contained in 1.1916 +// the rounded rect defined by aRoundedRect and aRadii. Complex cases are 1.1917 +// handled conservatively by returning FALSE in some situations where 1.1918 +// a more thorough analysis could return TRUE. 1.1919 +// 1.1920 +// See also RoundedRectIntersectsRect. 1.1921 +static bool RoundedRectContainsRect(const nsRect& aRoundedRect, 1.1922 + const nscoord aRadii[8], 1.1923 + const nsRect& aContainedRect) { 1.1924 + nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect); 1.1925 + return rgn.Contains(aContainedRect); 1.1926 +} 1.1927 + 1.1928 +bool 1.1929 +nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, 1.1930 + const nsRect& aClipRect, 1.1931 + gfxRect* aDestRect) 1.1932 +{ 1.1933 + if (!mBackgroundStyle) 1.1934 + return false; 1.1935 + 1.1936 + if (mBackgroundStyle->mLayers.Length() != 1) 1.1937 + return false; 1.1938 + 1.1939 + nsPresContext* presContext = mFrame->PresContext(); 1.1940 + uint32_t flags = aBuilder->GetBackgroundPaintFlags(); 1.1941 + nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); 1.1942 + const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer]; 1.1943 + 1.1944 + if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED) 1.1945 + return false; 1.1946 + 1.1947 + nsBackgroundLayerState state = 1.1948 + nsCSSRendering::PrepareBackgroundLayer(presContext, 1.1949 + mFrame, 1.1950 + flags, 1.1951 + borderArea, 1.1952 + aClipRect, 1.1953 + *mBackgroundStyle, 1.1954 + layer); 1.1955 + 1.1956 + nsImageRenderer* imageRenderer = &state.mImageRenderer; 1.1957 + // We only care about images here, not gradients. 1.1958 + if (!imageRenderer->IsRasterImage()) 1.1959 + return false; 1.1960 + 1.1961 + int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); 1.1962 + *aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel); 1.1963 + 1.1964 + return true; 1.1965 +} 1.1966 + 1.1967 +bool 1.1968 +nsDisplayBackgroundImage::TryOptimizeToImageLayer(LayerManager* aManager, 1.1969 + nsDisplayListBuilder* aBuilder) 1.1970 +{ 1.1971 + if (!mBackgroundStyle) 1.1972 + return false; 1.1973 + 1.1974 + nsPresContext* presContext = mFrame->PresContext(); 1.1975 + uint32_t flags = aBuilder->GetBackgroundPaintFlags(); 1.1976 + nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); 1.1977 + const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer]; 1.1978 + 1.1979 + if (layer.mClip != NS_STYLE_BG_CLIP_BORDER) { 1.1980 + return false; 1.1981 + } 1.1982 + nscoord radii[8]; 1.1983 + if (mFrame->GetBorderRadii(radii)) { 1.1984 + return false; 1.1985 + } 1.1986 + 1.1987 + nsBackgroundLayerState state = 1.1988 + nsCSSRendering::PrepareBackgroundLayer(presContext, 1.1989 + mFrame, 1.1990 + flags, 1.1991 + borderArea, 1.1992 + borderArea, 1.1993 + *mBackgroundStyle, 1.1994 + layer); 1.1995 + 1.1996 + nsImageRenderer* imageRenderer = &state.mImageRenderer; 1.1997 + // We only care about images here, not gradients. 1.1998 + if (!imageRenderer->IsRasterImage()) 1.1999 + return false; 1.2000 + 1.2001 + nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer(aManager); 1.2002 + // Image is not ready to be made into a layer yet 1.2003 + if (!imageContainer) 1.2004 + return false; 1.2005 + 1.2006 + // We currently can't handle tiled or partial backgrounds. 1.2007 + if (!state.mDestArea.IsEqualEdges(state.mFillArea)) { 1.2008 + return false; 1.2009 + } 1.2010 + 1.2011 + // XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to 1.2012 + // layer pixel boundaries. This should be OK for now. 1.2013 + 1.2014 + int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); 1.2015 + mDestRect = nsLayoutUtils::RectToGfxRect(state.mDestArea, appUnitsPerDevPixel); 1.2016 + mImageContainer = imageContainer; 1.2017 + 1.2018 + // Ok, we can turn this into a layer if needed. 1.2019 + return true; 1.2020 +} 1.2021 + 1.2022 +already_AddRefed<ImageContainer> 1.2023 +nsDisplayBackgroundImage::GetContainer(LayerManager* aManager, 1.2024 + nsDisplayListBuilder *aBuilder) 1.2025 +{ 1.2026 + if (!TryOptimizeToImageLayer(aManager, aBuilder)) { 1.2027 + return nullptr; 1.2028 + } 1.2029 + 1.2030 + nsRefPtr<ImageContainer> container = mImageContainer; 1.2031 + 1.2032 + return container.forget(); 1.2033 +} 1.2034 + 1.2035 +LayerState 1.2036 +nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder, 1.2037 + LayerManager* aManager, 1.2038 + const ContainerLayerParameters& aParameters) 1.2039 +{ 1.2040 + bool animated = false; 1.2041 + if (mBackgroundStyle) { 1.2042 + const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer]; 1.2043 + const nsStyleImage* image = &layer.mImage; 1.2044 + if (image->GetType() == eStyleImageType_Image) { 1.2045 + imgIRequest* imgreq = image->GetImageData(); 1.2046 + nsCOMPtr<imgIContainer> image; 1.2047 + if (NS_SUCCEEDED(imgreq->GetImage(getter_AddRefs(image))) && image) { 1.2048 + if (NS_FAILED(image->GetAnimated(&animated))) { 1.2049 + animated = false; 1.2050 + } 1.2051 + } 1.2052 + } 1.2053 + } 1.2054 + 1.2055 + if (!animated || 1.2056 + !nsLayoutUtils::AnimatedImageLayersEnabled()) { 1.2057 + if (!aManager->IsCompositingCheap() || 1.2058 + !nsLayoutUtils::GPUImageScalingEnabled()) { 1.2059 + return LAYER_NONE; 1.2060 + } 1.2061 + } 1.2062 + 1.2063 + if (!TryOptimizeToImageLayer(aManager, aBuilder)) { 1.2064 + return LAYER_NONE; 1.2065 + } 1.2066 + 1.2067 + if (!animated) { 1.2068 + mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize(); 1.2069 + NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!"); 1.2070 + 1.2071 + gfxRect destRect = mDestRect; 1.2072 + 1.2073 + destRect.width *= aParameters.mXScale; 1.2074 + destRect.height *= aParameters.mYScale; 1.2075 + 1.2076 + // Calculate the scaling factor for the frame. 1.2077 + gfxSize scale = gfxSize(destRect.width / imageSize.width, destRect.height / imageSize.height); 1.2078 + 1.2079 + // If we are not scaling at all, no point in separating this into a layer. 1.2080 + if (scale.width == 1.0f && scale.height == 1.0f) { 1.2081 + return LAYER_NONE; 1.2082 + } 1.2083 + 1.2084 + // If the target size is pretty small, no point in using a layer. 1.2085 + if (destRect.width * destRect.height < 64 * 64) { 1.2086 + return LAYER_NONE; 1.2087 + } 1.2088 + } 1.2089 + 1.2090 + return LAYER_ACTIVE; 1.2091 +} 1.2092 + 1.2093 +already_AddRefed<Layer> 1.2094 +nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder, 1.2095 + LayerManager* aManager, 1.2096 + const ContainerLayerParameters& aParameters) 1.2097 +{ 1.2098 + nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*> 1.2099 + (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this)); 1.2100 + if (!layer) { 1.2101 + layer = aManager->CreateImageLayer(); 1.2102 + if (!layer) 1.2103 + return nullptr; 1.2104 + } 1.2105 + layer->SetContainer(mImageContainer); 1.2106 + ConfigureLayer(layer, aParameters.mOffset); 1.2107 + return layer.forget(); 1.2108 +} 1.2109 + 1.2110 +void 1.2111 +nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) 1.2112 +{ 1.2113 + aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame)); 1.2114 + 1.2115 + mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize(); 1.2116 + NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!"); 1.2117 + 1.2118 + gfxPoint p = mDestRect.TopLeft() + aOffset; 1.2119 + gfx::Matrix transform; 1.2120 + transform.Translate(p.x, p.y); 1.2121 + transform.Scale(mDestRect.width/imageSize.width, 1.2122 + mDestRect.height/imageSize.height); 1.2123 + aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); 1.2124 + aLayer->SetVisibleRegion(nsIntRect(0, 0, imageSize.width, imageSize.height)); 1.2125 +} 1.2126 + 1.2127 +void 1.2128 +nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder, 1.2129 + const nsRect& aRect, 1.2130 + HitTestState* aState, 1.2131 + nsTArray<nsIFrame*> *aOutFrames) 1.2132 +{ 1.2133 + if (RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) { 1.2134 + aOutFrames->AppendElement(mFrame); 1.2135 + } 1.2136 +} 1.2137 + 1.2138 +bool 1.2139 +nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.2140 + nsRegion* aVisibleRegion, 1.2141 + const nsRect& aAllowVisibleRegionExpansion) 1.2142 +{ 1.2143 + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, 1.2144 + aAllowVisibleRegionExpansion)) { 1.2145 + return false; 1.2146 + } 1.2147 + 1.2148 + // Return false if the background was propagated away from this 1.2149 + // frame. We don't want this display item to show up and confuse 1.2150 + // anything. 1.2151 + return mBackgroundStyle; 1.2152 +} 1.2153 + 1.2154 +/* static */ nsRegion 1.2155 +nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem, 1.2156 + nsPresContext* aPresContext, 1.2157 + uint8_t aClip, const nsRect& aRect, 1.2158 + bool* aSnap) 1.2159 +{ 1.2160 + nsRegion result; 1.2161 + if (aRect.IsEmpty()) 1.2162 + return result; 1.2163 + 1.2164 + nsIFrame *frame = aItem->Frame(); 1.2165 + 1.2166 + nscoord radii[8]; 1.2167 + nsRect clipRect; 1.2168 + bool haveRadii; 1.2169 + switch (aClip) { 1.2170 + case NS_STYLE_BG_CLIP_BORDER: 1.2171 + haveRadii = frame->GetBorderRadii(radii); 1.2172 + clipRect = nsRect(aItem->ToReferenceFrame(), frame->GetSize()); 1.2173 + break; 1.2174 + case NS_STYLE_BG_CLIP_PADDING: 1.2175 + haveRadii = frame->GetPaddingBoxBorderRadii(radii); 1.2176 + clipRect = frame->GetPaddingRect() - frame->GetPosition() + aItem->ToReferenceFrame(); 1.2177 + break; 1.2178 + case NS_STYLE_BG_CLIP_CONTENT: 1.2179 + haveRadii = frame->GetContentBoxBorderRadii(radii); 1.2180 + clipRect = frame->GetContentRect() - frame->GetPosition() + aItem->ToReferenceFrame(); 1.2181 + break; 1.2182 + default: 1.2183 + NS_NOTREACHED("Unknown clip type"); 1.2184 + return result; 1.2185 + } 1.2186 + 1.2187 + if (haveRadii) { 1.2188 + *aSnap = false; 1.2189 + result = nsLayoutUtils::RoundedRectIntersectRect(clipRect, radii, aRect); 1.2190 + } else { 1.2191 + result = clipRect.Intersect(aRect); 1.2192 + } 1.2193 + return result; 1.2194 +} 1.2195 + 1.2196 +nsRegion 1.2197 +nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, 1.2198 + bool* aSnap) { 1.2199 + nsRegion result; 1.2200 + *aSnap = false; 1.2201 + 1.2202 + if (!mBackgroundStyle) 1.2203 + return result; 1.2204 + 1.2205 + 1.2206 + *aSnap = true; 1.2207 + 1.2208 + // For policies other than EACH_BOX, don't try to optimize here, since 1.2209 + // this could easily lead to O(N^2) behavior inside InlineBackgroundData, 1.2210 + // which expects frames to be sent to it in content order, not reverse 1.2211 + // content order which we'll produce here. 1.2212 + // Of course, if there's only one frame in the flow, it doesn't matter. 1.2213 + if (mBackgroundStyle->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX || 1.2214 + (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) { 1.2215 + const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer]; 1.2216 + if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL) { 1.2217 + nsPresContext* presContext = mFrame->PresContext(); 1.2218 + result = GetInsideClipRegion(this, presContext, layer.mClip, mBounds, aSnap); 1.2219 + } 1.2220 + } 1.2221 + 1.2222 + return result; 1.2223 +} 1.2224 + 1.2225 +bool 1.2226 +nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { 1.2227 + if (!mBackgroundStyle) { 1.2228 + *aColor = NS_RGBA(0,0,0,0); 1.2229 + return true; 1.2230 + } 1.2231 + return false; 1.2232 +} 1.2233 + 1.2234 +bool 1.2235 +nsDisplayBackgroundImage::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, 1.2236 + nsIFrame* aFrame) 1.2237 +{ 1.2238 + if (!mBackgroundStyle) 1.2239 + return false; 1.2240 + if (!mBackgroundStyle->HasFixedBackground()) 1.2241 + return false; 1.2242 + 1.2243 + // If aFrame is mFrame or an ancestor in this document, and aFrame is 1.2244 + // not the viewport frame, then moving aFrame will move mFrame 1.2245 + // relative to the viewport, so our fixed-pos background will change. 1.2246 + return aFrame->GetParent() && 1.2247 + (aFrame == mFrame || 1.2248 + nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame)); 1.2249 +} 1.2250 + 1.2251 +nsRect 1.2252 +nsDisplayBackgroundImage::GetPositioningArea() 1.2253 +{ 1.2254 + if (!mBackgroundStyle) { 1.2255 + return nsRect(); 1.2256 + } 1.2257 + nsIFrame* attachedToFrame; 1.2258 + return nsCSSRendering::ComputeBackgroundPositioningArea( 1.2259 + mFrame->PresContext(), mFrame, 1.2260 + nsRect(ToReferenceFrame(), mFrame->GetSize()), 1.2261 + *mBackgroundStyle, mBackgroundStyle->mLayers[mLayer], 1.2262 + &attachedToFrame) + ToReferenceFrame(); 1.2263 +} 1.2264 + 1.2265 +bool 1.2266 +nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange() 1.2267 +{ 1.2268 + if (!mBackgroundStyle) 1.2269 + return false; 1.2270 + 1.2271 + nscoord radii[8]; 1.2272 + if (mFrame->GetBorderRadii(radii)) { 1.2273 + // A change in the size of the positioning area might change the position 1.2274 + // of the rounded corners. 1.2275 + return true; 1.2276 + } 1.2277 + 1.2278 + const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer]; 1.2279 + if (layer.RenderingMightDependOnPositioningAreaSizeChange()) { 1.2280 + return true; 1.2281 + } 1.2282 + return false; 1.2283 +} 1.2284 + 1.2285 +static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags) 1.2286 +{ 1.2287 + nsDisplayItem* nextItem = aItem->GetAbove(); 1.2288 + while (nextItem && nextItem->GetType() == nsDisplayItem::TYPE_BACKGROUND) { 1.2289 + nextItem = nextItem->GetAbove(); 1.2290 + } 1.2291 + if (nextItem && 1.2292 + nextItem->Frame() == aItem->Frame() && 1.2293 + nextItem->GetType() == nsDisplayItem::TYPE_BORDER) { 1.2294 + aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER; 1.2295 + } 1.2296 +} 1.2297 + 1.2298 +void 1.2299 +nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder, 1.2300 + nsRenderingContext* aCtx) { 1.2301 + PaintInternal(aBuilder, aCtx, mVisibleRect, nullptr); 1.2302 +} 1.2303 + 1.2304 +void 1.2305 +nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder, 1.2306 + nsRenderingContext* aCtx, const nsRect& aBounds, 1.2307 + nsRect* aClipRect) { 1.2308 + nsPoint offset = ToReferenceFrame(); 1.2309 + uint32_t flags = aBuilder->GetBackgroundPaintFlags(); 1.2310 + CheckForBorderItem(this, flags); 1.2311 + 1.2312 + nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame, 1.2313 + aBounds, 1.2314 + nsRect(offset, mFrame->GetSize()), 1.2315 + flags, aClipRect, mLayer); 1.2316 + 1.2317 +} 1.2318 + 1.2319 +void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.2320 + const nsDisplayItemGeometry* aGeometry, 1.2321 + nsRegion* aInvalidRegion) 1.2322 +{ 1.2323 + if (!mBackgroundStyle) { 1.2324 + return; 1.2325 + } 1.2326 + 1.2327 + const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry); 1.2328 + 1.2329 + bool snap; 1.2330 + nsRect bounds = GetBounds(aBuilder, &snap); 1.2331 + nsRect positioningArea = GetPositioningArea(); 1.2332 + if (positioningArea.TopLeft() != geometry->mPositioningArea.TopLeft() || 1.2333 + (positioningArea.Size() != geometry->mPositioningArea.Size() && 1.2334 + RenderingMightDependOnPositioningAreaSizeChange())) { 1.2335 + // Positioning area changed in a way that could cause everything to change, 1.2336 + // so invalidate everything (both old and new painting areas). 1.2337 + aInvalidRegion->Or(bounds, geometry->mBounds); 1.2338 + 1.2339 + if (positioningArea.Size() != geometry->mPositioningArea.Size()) { 1.2340 + NotifyRenderingChanged(); 1.2341 + } 1.2342 + return; 1.2343 + } 1.2344 + if (aBuilder->ShouldSyncDecodeImages()) { 1.2345 + if (mBackgroundStyle && 1.2346 + !nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(mBackgroundStyle, mLayer)) { 1.2347 + aInvalidRegion->Or(*aInvalidRegion, bounds); 1.2348 + 1.2349 + NotifyRenderingChanged(); 1.2350 + } 1.2351 + } 1.2352 + if (!bounds.IsEqualInterior(geometry->mBounds)) { 1.2353 + // Positioning area is unchanged, so invalidate just the change in the 1.2354 + // painting area. 1.2355 + aInvalidRegion->Xor(bounds, geometry->mBounds); 1.2356 + 1.2357 + NotifyRenderingChanged(); 1.2358 + } 1.2359 +} 1.2360 + 1.2361 +nsRect 1.2362 +nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { 1.2363 + *aSnap = true; 1.2364 + return mBounds; 1.2365 +} 1.2366 + 1.2367 +nsRect 1.2368 +nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder* aBuilder) { 1.2369 + nsPresContext* presContext = mFrame->PresContext(); 1.2370 + 1.2371 + if (!mBackgroundStyle) { 1.2372 + return nsRect(); 1.2373 + } 1.2374 + 1.2375 + nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize()); 1.2376 + nsRect clipRect = borderBox; 1.2377 + if (mFrame->GetType() == nsGkAtoms::canvasFrame) { 1.2378 + nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame); 1.2379 + clipRect = frame->CanvasArea() + ToReferenceFrame(); 1.2380 + } 1.2381 + const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer]; 1.2382 + return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame, 1.2383 + borderBox, clipRect, 1.2384 + *mBackgroundStyle, layer, 1.2385 + aBuilder->GetBackgroundPaintFlags()); 1.2386 +} 1.2387 + 1.2388 +uint32_t 1.2389 +nsDisplayBackgroundImage::GetPerFrameKey() 1.2390 +{ 1.2391 + return (mLayer << nsDisplayItem::TYPE_BITS) | 1.2392 + nsDisplayItem::GetPerFrameKey(); 1.2393 +} 1.2394 + 1.2395 +nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder, 1.2396 + nsIFrame* aFrame) 1.2397 + : nsDisplayItem(aBuilder, aFrame) 1.2398 +{ 1.2399 + MOZ_COUNT_CTOR(nsDisplayThemedBackground); 1.2400 + 1.2401 + const nsStyleDisplay* disp = mFrame->StyleDisplay(); 1.2402 + mAppearance = disp->mAppearance; 1.2403 + mFrame->IsThemed(disp, &mThemeTransparency); 1.2404 + 1.2405 + // Perform necessary RegisterThemeGeometry 1.2406 + switch (disp->mAppearance) { 1.2407 + case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR: 1.2408 + case NS_THEME_TOOLBAR: 1.2409 + case NS_THEME_WINDOW_TITLEBAR: 1.2410 + case NS_THEME_WINDOW_BUTTON_BOX: 1.2411 + case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: 1.2412 + case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED: 1.2413 + RegisterThemeGeometry(aBuilder, aFrame); 1.2414 + break; 1.2415 + case NS_THEME_WIN_BORDERLESS_GLASS: 1.2416 + case NS_THEME_WIN_GLASS: 1.2417 + aBuilder->SetGlassDisplayItem(this); 1.2418 + break; 1.2419 + } 1.2420 + 1.2421 + mBounds = GetBoundsInternal(); 1.2422 +} 1.2423 + 1.2424 +nsDisplayThemedBackground::~nsDisplayThemedBackground() 1.2425 +{ 1.2426 +#ifdef NS_BUILD_REFCNT_LOGGING 1.2427 + MOZ_COUNT_DTOR(nsDisplayThemedBackground); 1.2428 +#endif 1.2429 +} 1.2430 + 1.2431 +#ifdef MOZ_DUMP_PAINTING 1.2432 +void 1.2433 +nsDisplayThemedBackground::WriteDebugInfo(nsACString& aTo) 1.2434 +{ 1.2435 + aTo += nsPrintfCString(" (themed, appearance:%d)", mAppearance); 1.2436 +} 1.2437 +#endif 1.2438 + 1.2439 +void 1.2440 +nsDisplayThemedBackground::HitTest(nsDisplayListBuilder* aBuilder, 1.2441 + const nsRect& aRect, 1.2442 + HitTestState* aState, 1.2443 + nsTArray<nsIFrame*> *aOutFrames) 1.2444 +{ 1.2445 + // Assume that any point in our border rect is a hit. 1.2446 + if (nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect)) { 1.2447 + aOutFrames->AppendElement(mFrame); 1.2448 + } 1.2449 +} 1.2450 + 1.2451 +nsRegion 1.2452 +nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, 1.2453 + bool* aSnap) { 1.2454 + nsRegion result; 1.2455 + *aSnap = false; 1.2456 + 1.2457 + if (mThemeTransparency == nsITheme::eOpaque) { 1.2458 + result = nsRect(ToReferenceFrame(), mFrame->GetSize()); 1.2459 + } 1.2460 + return result; 1.2461 +} 1.2462 + 1.2463 +bool 1.2464 +nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { 1.2465 + if (mAppearance == NS_THEME_WIN_BORDERLESS_GLASS || 1.2466 + mAppearance == NS_THEME_WIN_GLASS) { 1.2467 + *aColor = NS_RGBA(0,0,0,0); 1.2468 + return true; 1.2469 + } 1.2470 + return false; 1.2471 +} 1.2472 + 1.2473 +nsRect 1.2474 +nsDisplayThemedBackground::GetPositioningArea() 1.2475 +{ 1.2476 + return nsRect(ToReferenceFrame(), mFrame->GetSize()); 1.2477 +} 1.2478 + 1.2479 +void 1.2480 +nsDisplayThemedBackground::Paint(nsDisplayListBuilder* aBuilder, 1.2481 + nsRenderingContext* aCtx) 1.2482 +{ 1.2483 + PaintInternal(aBuilder, aCtx, mVisibleRect, nullptr); 1.2484 +} 1.2485 + 1.2486 + 1.2487 +void 1.2488 +nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder* aBuilder, 1.2489 + nsRenderingContext* aCtx, const nsRect& aBounds, 1.2490 + nsRect* aClipRect) 1.2491 +{ 1.2492 + // XXXzw this ignores aClipRect. 1.2493 + nsPresContext* presContext = mFrame->PresContext(); 1.2494 + nsITheme *theme = presContext->GetTheme(); 1.2495 + nsRect borderArea(ToReferenceFrame(), mFrame->GetSize()); 1.2496 + nsRect drawing(borderArea); 1.2497 + theme->GetWidgetOverflow(presContext->DeviceContext(), mFrame, mAppearance, 1.2498 + &drawing); 1.2499 + drawing.IntersectRect(drawing, aBounds); 1.2500 + theme->DrawWidgetBackground(aCtx, mFrame, mAppearance, borderArea, drawing); 1.2501 +} 1.2502 + 1.2503 +bool nsDisplayThemedBackground::IsWindowActive() 1.2504 +{ 1.2505 + EventStates docState = mFrame->GetContent()->OwnerDoc()->GetDocumentState(); 1.2506 + return !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE); 1.2507 +} 1.2508 + 1.2509 +void nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.2510 + const nsDisplayItemGeometry* aGeometry, 1.2511 + nsRegion* aInvalidRegion) 1.2512 +{ 1.2513 + const nsDisplayThemedBackgroundGeometry* geometry = static_cast<const nsDisplayThemedBackgroundGeometry*>(aGeometry); 1.2514 + 1.2515 + bool snap; 1.2516 + nsRect bounds = GetBounds(aBuilder, &snap); 1.2517 + nsRect positioningArea = GetPositioningArea(); 1.2518 + if (!positioningArea.IsEqualInterior(geometry->mPositioningArea)) { 1.2519 + // Invalidate everything (both old and new painting areas). 1.2520 + aInvalidRegion->Or(bounds, geometry->mBounds); 1.2521 + return; 1.2522 + } 1.2523 + if (!bounds.IsEqualInterior(geometry->mBounds)) { 1.2524 + // Positioning area is unchanged, so invalidate just the change in the 1.2525 + // painting area. 1.2526 + aInvalidRegion->Xor(bounds, geometry->mBounds); 1.2527 + } 1.2528 + nsITheme* theme = mFrame->PresContext()->GetTheme(); 1.2529 + if (theme->WidgetAppearanceDependsOnWindowFocus(mAppearance) && 1.2530 + IsWindowActive() != geometry->mWindowIsActive) { 1.2531 + aInvalidRegion->Or(*aInvalidRegion, bounds); 1.2532 + } 1.2533 +} 1.2534 + 1.2535 +nsRect 1.2536 +nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { 1.2537 + *aSnap = true; 1.2538 + return mBounds; 1.2539 +} 1.2540 + 1.2541 +nsRect 1.2542 +nsDisplayThemedBackground::GetBoundsInternal() { 1.2543 + nsPresContext* presContext = mFrame->PresContext(); 1.2544 + 1.2545 + nsRect r(nsPoint(0,0), mFrame->GetSize()); 1.2546 + presContext->GetTheme()-> 1.2547 + GetWidgetOverflow(presContext->DeviceContext(), mFrame, 1.2548 + mFrame->StyleDisplay()->mAppearance, &r); 1.2549 +#ifdef XP_MACOSX 1.2550 + // Bug 748219 1.2551 + r.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel()); 1.2552 +#endif 1.2553 + 1.2554 + return r + ToReferenceFrame(); 1.2555 +} 1.2556 + 1.2557 +void 1.2558 +nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder, 1.2559 + nsRenderingContext* aCtx) 1.2560 +{ 1.2561 + if (mColor == NS_RGBA(0, 0, 0, 0)) { 1.2562 + return; 1.2563 + } 1.2564 + 1.2565 + nsPoint offset = ToReferenceFrame(); 1.2566 + uint32_t flags = aBuilder->GetBackgroundPaintFlags(); 1.2567 + CheckForBorderItem(this, flags); 1.2568 + nsCSSRendering::PaintBackgroundColor(mFrame->PresContext(), *aCtx, mFrame, 1.2569 + mVisibleRect, 1.2570 + nsRect(offset, mFrame->GetSize()), 1.2571 + flags); 1.2572 +} 1.2573 + 1.2574 +nsRegion 1.2575 +nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, 1.2576 + bool* aSnap) 1.2577 +{ 1.2578 + if (NS_GET_A(mColor) != 255) { 1.2579 + return nsRegion(); 1.2580 + } 1.2581 + 1.2582 + if (!mBackgroundStyle) 1.2583 + return nsRegion(); 1.2584 + 1.2585 + *aSnap = true; 1.2586 + 1.2587 + const nsStyleBackground::Layer& bottomLayer = mBackgroundStyle->BottomLayer(); 1.2588 + nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize()); 1.2589 + nsPresContext* presContext = mFrame->PresContext(); 1.2590 + return nsDisplayBackgroundImage::GetInsideClipRegion(this, presContext, bottomLayer.mClip, borderBox, aSnap); 1.2591 +} 1.2592 + 1.2593 +bool 1.2594 +nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) 1.2595 +{ 1.2596 + *aColor = mColor; 1.2597 + 1.2598 + if (!mBackgroundStyle) 1.2599 + return true; 1.2600 + 1.2601 + return (!nsLayoutUtils::HasNonZeroCorner(mFrame->StyleBorder()->mBorderRadius) && 1.2602 + mBackgroundStyle->BottomLayer().mClip == NS_STYLE_BG_CLIP_BORDER); 1.2603 +} 1.2604 + 1.2605 +void 1.2606 +nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder, 1.2607 + const nsRect& aRect, 1.2608 + HitTestState* aState, 1.2609 + nsTArray<nsIFrame*> *aOutFrames) 1.2610 +{ 1.2611 + if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) { 1.2612 + // aRect doesn't intersect our border-radius curve. 1.2613 + return; 1.2614 + } 1.2615 + 1.2616 + aOutFrames->AppendElement(mFrame); 1.2617 +} 1.2618 + 1.2619 +#ifdef MOZ_DUMP_PAINTING 1.2620 +void 1.2621 +nsDisplayBackgroundColor::WriteDebugInfo(nsACString& aTo) 1.2622 +{ 1.2623 + aTo += nsPrintfCString(" (rgba %d,%d,%d,%d)", 1.2624 + NS_GET_R(mColor), NS_GET_G(mColor), 1.2625 + NS_GET_B(mColor), NS_GET_A(mColor)); 1.2626 +} 1.2627 +#endif 1.2628 + 1.2629 +nsRect 1.2630 +nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { 1.2631 + *aSnap = false; 1.2632 + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); 1.2633 +} 1.2634 + 1.2635 +void 1.2636 +nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder, 1.2637 + nsRenderingContext* aCtx) { 1.2638 + // TODO join outlines together 1.2639 + nsPoint offset = ToReferenceFrame(); 1.2640 + nsCSSRendering::PaintOutline(mFrame->PresContext(), *aCtx, mFrame, 1.2641 + mVisibleRect, 1.2642 + nsRect(offset, mFrame->GetSize()), 1.2643 + mFrame->StyleContext()); 1.2644 +} 1.2645 + 1.2646 +bool 1.2647 +nsDisplayOutline::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.2648 + nsRegion* aVisibleRegion, 1.2649 + const nsRect& aAllowVisibleRegionExpansion) { 1.2650 + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, 1.2651 + aAllowVisibleRegionExpansion)) { 1.2652 + return false; 1.2653 + } 1.2654 + 1.2655 + const nsStyleOutline* outline = mFrame->StyleOutline(); 1.2656 + nsRect borderBox(ToReferenceFrame(), mFrame->GetSize()); 1.2657 + if (borderBox.Contains(aVisibleRegion->GetBounds()) && 1.2658 + !nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) { 1.2659 + if (outline->mOutlineOffset >= 0) { 1.2660 + // the visible region is entirely inside the border-rect, and the outline 1.2661 + // isn't rendered inside the border-rect, so the outline is not visible 1.2662 + return false; 1.2663 + } 1.2664 + } 1.2665 + 1.2666 + return true; 1.2667 +} 1.2668 + 1.2669 +void 1.2670 +nsDisplayEventReceiver::HitTest(nsDisplayListBuilder* aBuilder, 1.2671 + const nsRect& aRect, 1.2672 + HitTestState* aState, 1.2673 + nsTArray<nsIFrame*> *aOutFrames) 1.2674 +{ 1.2675 + if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) { 1.2676 + // aRect doesn't intersect our border-radius curve. 1.2677 + return; 1.2678 + } 1.2679 + 1.2680 + aOutFrames->AppendElement(mFrame); 1.2681 +} 1.2682 + 1.2683 +void 1.2684 +nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder, 1.2685 + nsIFrame* aFrame) 1.2686 +{ 1.2687 + NS_ASSERTION(aBuilder->FindReferenceFrameFor(aFrame) == aBuilder->FindReferenceFrameFor(mFrame), 1.2688 + "Reference frame mismatch"); 1.2689 + uint8_t pointerEvents = aFrame->StyleVisibility()->mPointerEvents; 1.2690 + if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) { 1.2691 + return; 1.2692 + } 1.2693 + // XXX handle other pointerEvents values for SVG 1.2694 + // XXX Do something clever here for the common case where the border box 1.2695 + // is obviously entirely inside mHitRegion. 1.2696 + nsRect borderBox(aBuilder->ToReferenceFrame(aFrame), aFrame->GetSize()); 1.2697 + const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder); 1.2698 + bool borderBoxHasRoundedCorners = 1.2699 + nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius); 1.2700 + if (clip) { 1.2701 + borderBox = clip->ApplyNonRoundedIntersection(borderBox); 1.2702 + if (clip->GetRoundedRectCount() > 0) { 1.2703 + borderBoxHasRoundedCorners = true; 1.2704 + } 1.2705 + } 1.2706 + if (borderBoxHasRoundedCorners || 1.2707 + (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) { 1.2708 + mMaybeHitRegion.Or(mMaybeHitRegion, borderBox); 1.2709 + } else { 1.2710 + mHitRegion.Or(mHitRegion, borderBox); 1.2711 + } 1.2712 + if (aBuilder->GetAncestorHasTouchEventHandler()) { 1.2713 + mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox); 1.2714 + } 1.2715 +} 1.2716 + 1.2717 +void 1.2718 +nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder, 1.2719 + nsRenderingContext* aCtx) { 1.2720 + // Note: Because we exist, we know that the caret is visible, so we don't 1.2721 + // need to check for the caret's visibility. 1.2722 + mCaret->PaintCaret(aBuilder, aCtx, mFrame, ToReferenceFrame()); 1.2723 +} 1.2724 + 1.2725 +bool 1.2726 +nsDisplayBorder::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.2727 + nsRegion* aVisibleRegion, 1.2728 + const nsRect& aAllowVisibleRegionExpansion) { 1.2729 + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, 1.2730 + aAllowVisibleRegionExpansion)) { 1.2731 + return false; 1.2732 + } 1.2733 + 1.2734 + nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() + 1.2735 + ToReferenceFrame(); 1.2736 + const nsStyleBorder *styleBorder; 1.2737 + if (paddingRect.Contains(aVisibleRegion->GetBounds()) && 1.2738 + !(styleBorder = mFrame->StyleBorder())->IsBorderImageLoaded() && 1.2739 + !nsLayoutUtils::HasNonZeroCorner(styleBorder->mBorderRadius)) { 1.2740 + // the visible region is entirely inside the content rect, and no part 1.2741 + // of the border is rendered inside the content rect, so we are not 1.2742 + // visible 1.2743 + // Skip this if there's a border-image (which draws a background 1.2744 + // too) or if there is a border-radius (which makes the border draw 1.2745 + // further in). 1.2746 + return false; 1.2747 + } 1.2748 + 1.2749 + return true; 1.2750 +} 1.2751 + 1.2752 +nsDisplayItemGeometry* 1.2753 +nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder) 1.2754 +{ 1.2755 + return new nsDisplayBorderGeometry(this, aBuilder); 1.2756 +} 1.2757 + 1.2758 +void 1.2759 +nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.2760 + const nsDisplayItemGeometry* aGeometry, 1.2761 + nsRegion* aInvalidRegion) 1.2762 +{ 1.2763 + const nsDisplayBorderGeometry* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry); 1.2764 + bool snap; 1.2765 + if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || 1.2766 + !geometry->mContentRect.IsEqualInterior(GetContentRect())) { 1.2767 + // We can probably get away with only invalidating the difference 1.2768 + // between the border and padding rects, but the XUL ui at least 1.2769 + // is apparently painting a background with this? 1.2770 + aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); 1.2771 + } 1.2772 +} 1.2773 + 1.2774 +void 1.2775 +nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder, 1.2776 + nsRenderingContext* aCtx) { 1.2777 + nsPoint offset = ToReferenceFrame(); 1.2778 + nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame, 1.2779 + mVisibleRect, 1.2780 + nsRect(offset, mFrame->GetSize()), 1.2781 + mFrame->StyleContext(), 1.2782 + mFrame->GetSkipSides()); 1.2783 +} 1.2784 + 1.2785 +nsRect 1.2786 +nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) 1.2787 +{ 1.2788 + *aSnap = true; 1.2789 + return CalculateBounds(*mFrame->StyleBorder()); 1.2790 +} 1.2791 + 1.2792 +nsRect 1.2793 +nsDisplayBorder::CalculateBounds(const nsStyleBorder& aStyleBorder) 1.2794 +{ 1.2795 + nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize()); 1.2796 + if (aStyleBorder.IsBorderImageLoaded()) { 1.2797 + borderBounds.Inflate(aStyleBorder.GetImageOutset()); 1.2798 + return borderBounds; 1.2799 + } else { 1.2800 + nsMargin border = aStyleBorder.GetComputedBorder(); 1.2801 + nsRect result; 1.2802 + if (border.top > 0) { 1.2803 + result = nsRect(borderBounds.X(), borderBounds.Y(), borderBounds.Width(), border.top); 1.2804 + } 1.2805 + if (border.right > 0) { 1.2806 + result.UnionRect(result, nsRect(borderBounds.XMost() - border.right, borderBounds.Y(), border.right, borderBounds.Height())); 1.2807 + } 1.2808 + if (border.bottom > 0) { 1.2809 + result.UnionRect(result, nsRect(borderBounds.X(), borderBounds.YMost() - border.bottom, borderBounds.Width(), border.bottom)); 1.2810 + } 1.2811 + if (border.left > 0) { 1.2812 + result.UnionRect(result, nsRect(borderBounds.X(), borderBounds.Y(), border.left, borderBounds.Height())); 1.2813 + } 1.2814 + 1.2815 + return result; 1.2816 + } 1.2817 +} 1.2818 + 1.2819 +// Given a region, compute a conservative approximation to it as a list 1.2820 +// of rectangles that aren't vertically adjacent (i.e., vertically 1.2821 +// adjacent or overlapping rectangles are combined). 1.2822 +// Right now this is only approximate, some vertically overlapping rectangles 1.2823 +// aren't guaranteed to be combined. 1.2824 +static void 1.2825 +ComputeDisjointRectangles(const nsRegion& aRegion, 1.2826 + nsTArray<nsRect>* aRects) { 1.2827 + nscoord accumulationMargin = nsPresContext::CSSPixelsToAppUnits(25); 1.2828 + nsRect accumulated; 1.2829 + nsRegionRectIterator iter(aRegion); 1.2830 + while (true) { 1.2831 + const nsRect* r = iter.Next(); 1.2832 + if (r && !accumulated.IsEmpty() && 1.2833 + accumulated.YMost() >= r->y - accumulationMargin) { 1.2834 + accumulated.UnionRect(accumulated, *r); 1.2835 + continue; 1.2836 + } 1.2837 + 1.2838 + if (!accumulated.IsEmpty()) { 1.2839 + aRects->AppendElement(accumulated); 1.2840 + accumulated.SetEmpty(); 1.2841 + } 1.2842 + 1.2843 + if (!r) 1.2844 + break; 1.2845 + 1.2846 + accumulated = *r; 1.2847 + } 1.2848 +} 1.2849 + 1.2850 +void 1.2851 +nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder, 1.2852 + nsRenderingContext* aCtx) { 1.2853 + nsPoint offset = ToReferenceFrame(); 1.2854 + nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset; 1.2855 + nsPresContext* presContext = mFrame->PresContext(); 1.2856 + nsAutoTArray<nsRect,10> rects; 1.2857 + ComputeDisjointRectangles(mVisibleRegion, &rects); 1.2858 + 1.2859 + PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint"); 1.2860 + for (uint32_t i = 0; i < rects.Length(); ++i) { 1.2861 + aCtx->PushState(); 1.2862 + aCtx->IntersectClip(rects[i]); 1.2863 + nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame, 1.2864 + borderRect, rects[i], mOpacity); 1.2865 + aCtx->PopState(); 1.2866 + } 1.2867 +} 1.2868 + 1.2869 +nsRect 1.2870 +nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { 1.2871 + *aSnap = false; 1.2872 + return mBounds; 1.2873 +} 1.2874 + 1.2875 +nsRect 1.2876 +nsDisplayBoxShadowOuter::GetBoundsInternal() { 1.2877 + return nsLayoutUtils::GetBoxShadowRectForFrame(mFrame, mFrame->GetSize()) + 1.2878 + ToReferenceFrame(); 1.2879 +} 1.2880 + 1.2881 +bool 1.2882 +nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.2883 + nsRegion* aVisibleRegion, 1.2884 + const nsRect& aAllowVisibleRegionExpansion) { 1.2885 + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, 1.2886 + aAllowVisibleRegionExpansion)) { 1.2887 + return false; 1.2888 + } 1.2889 + 1.2890 + // Store the actual visible region 1.2891 + mVisibleRegion.And(*aVisibleRegion, mVisibleRect); 1.2892 + 1.2893 + nsPoint origin = ToReferenceFrame(); 1.2894 + nsRect visibleBounds = aVisibleRegion->GetBounds(); 1.2895 + nsRect frameRect(origin, mFrame->GetSize()); 1.2896 + if (!frameRect.Contains(visibleBounds)) 1.2897 + return true; 1.2898 + 1.2899 + // the visible region is entirely inside the border-rect, and box shadows 1.2900 + // never render within the border-rect (unless there's a border radius). 1.2901 + nscoord twipsRadii[8]; 1.2902 + bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii); 1.2903 + if (!hasBorderRadii) 1.2904 + return false; 1.2905 + 1.2906 + return !RoundedRectContainsRect(frameRect, twipsRadii, visibleBounds); 1.2907 +} 1.2908 + 1.2909 +void 1.2910 +nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.2911 + const nsDisplayItemGeometry* aGeometry, 1.2912 + nsRegion* aInvalidRegion) 1.2913 +{ 1.2914 + const nsDisplayItemGenericGeometry* geometry = 1.2915 + static_cast<const nsDisplayItemGenericGeometry*>(aGeometry); 1.2916 + bool snap; 1.2917 + if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || 1.2918 + !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) { 1.2919 + nsRegion oldShadow, newShadow; 1.2920 + nscoord dontCare[8]; 1.2921 + bool hasBorderRadius = mFrame->GetBorderRadii(dontCare); 1.2922 + if (hasBorderRadius) { 1.2923 + // If we have rounded corners then we need to invalidate the frame area 1.2924 + // too since we paint into it. 1.2925 + oldShadow = geometry->mBounds; 1.2926 + newShadow = GetBounds(aBuilder, &snap); 1.2927 + } else { 1.2928 + oldShadow = oldShadow.Sub(geometry->mBounds, geometry->mBorderRect); 1.2929 + newShadow = newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect()); 1.2930 + } 1.2931 + aInvalidRegion->Or(oldShadow, newShadow); 1.2932 + } 1.2933 +} 1.2934 + 1.2935 + 1.2936 +void 1.2937 +nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder, 1.2938 + nsRenderingContext* aCtx) { 1.2939 + nsPoint offset = ToReferenceFrame(); 1.2940 + nsRect borderRect = nsRect(offset, mFrame->GetSize()); 1.2941 + nsPresContext* presContext = mFrame->PresContext(); 1.2942 + nsAutoTArray<nsRect,10> rects; 1.2943 + ComputeDisjointRectangles(mVisibleRegion, &rects); 1.2944 + 1.2945 + PROFILER_LABEL("nsDisplayBoxShadowInner", "Paint"); 1.2946 + for (uint32_t i = 0; i < rects.Length(); ++i) { 1.2947 + aCtx->PushState(); 1.2948 + aCtx->IntersectClip(rects[i]); 1.2949 + nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame, 1.2950 + borderRect, rects[i]); 1.2951 + aCtx->PopState(); 1.2952 + } 1.2953 +} 1.2954 + 1.2955 +bool 1.2956 +nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.2957 + nsRegion* aVisibleRegion, 1.2958 + const nsRect& aAllowVisibleRegionExpansion) { 1.2959 + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, 1.2960 + aAllowVisibleRegionExpansion)) { 1.2961 + return false; 1.2962 + } 1.2963 + 1.2964 + // Store the actual visible region 1.2965 + mVisibleRegion.And(*aVisibleRegion, mVisibleRect); 1.2966 + return true; 1.2967 +} 1.2968 + 1.2969 +nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, 1.2970 + nsIFrame* aFrame, nsDisplayList* aList) 1.2971 + : nsDisplayItem(aBuilder, aFrame) 1.2972 + , mOverrideZIndex(0) 1.2973 +{ 1.2974 + mList.AppendToTop(aList); 1.2975 + UpdateBounds(aBuilder); 1.2976 + 1.2977 + if (!aFrame || !aFrame->IsTransformed()) { 1.2978 + return; 1.2979 + } 1.2980 + 1.2981 + // If the frame is a preserve-3d parent, then we will create transforms 1.2982 + // inside this list afterwards (see WrapPreserve3DList in nsFrame.cpp). 1.2983 + // In this case we will always be outside of the transform, so share 1.2984 + // our parents reference frame. 1.2985 + if (aFrame->Preserves3DChildren()) { 1.2986 + mReferenceFrame = 1.2987 + aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); 1.2988 + mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); 1.2989 + return; 1.2990 + } 1.2991 + 1.2992 + // If we're a transformed frame, then we need to find out if we're inside 1.2993 + // the nsDisplayTransform or outside of it. Frames inside the transform 1.2994 + // need mReferenceFrame == mFrame, outside needs the next ancestor 1.2995 + // reference frame. 1.2996 + // If we're inside the transform, then the nsDisplayItem constructor 1.2997 + // will have done the right thing. 1.2998 + // If we're outside the transform, then we should have only one child 1.2999 + // (since nsDisplayTransform wraps all actual content), and that child 1.3000 + // will have the correct reference frame set (since nsDisplayTransform 1.3001 + // handles this explictly). 1.3002 + // 1.3003 + // Preserve-3d can cause us to have multiple nsDisplayTransform 1.3004 + // children. 1.3005 + nsDisplayItem *i = mList.GetBottom(); 1.3006 + if (i && (!i->GetAbove() || i->GetType() == TYPE_TRANSFORM) && 1.3007 + i->Frame() == mFrame) { 1.3008 + mReferenceFrame = i->ReferenceFrame(); 1.3009 + mToReferenceFrame = i->ToReferenceFrame(); 1.3010 + } 1.3011 +} 1.3012 + 1.3013 +nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, 1.3014 + nsIFrame* aFrame, nsDisplayItem* aItem) 1.3015 + : nsDisplayItem(aBuilder, aFrame) 1.3016 + , mOverrideZIndex(0) 1.3017 +{ 1.3018 + mList.AppendToTop(aItem); 1.3019 + UpdateBounds(aBuilder); 1.3020 + 1.3021 + if (!aFrame || !aFrame->IsTransformed()) { 1.3022 + return; 1.3023 + } 1.3024 + 1.3025 + if (aFrame->Preserves3DChildren()) { 1.3026 + mReferenceFrame = 1.3027 + aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); 1.3028 + mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); 1.3029 + return; 1.3030 + } 1.3031 + 1.3032 + // See the previous nsDisplayWrapList constructor 1.3033 + if (aItem->Frame() == aFrame) { 1.3034 + mReferenceFrame = aItem->ReferenceFrame(); 1.3035 + mToReferenceFrame = aItem->ToReferenceFrame(); 1.3036 + } 1.3037 +} 1.3038 + 1.3039 +nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, 1.3040 + nsIFrame* aFrame, nsDisplayItem* aItem, 1.3041 + const nsIFrame* aReferenceFrame, 1.3042 + const nsPoint& aToReferenceFrame) 1.3043 + : nsDisplayItem(aBuilder, aFrame, aReferenceFrame, aToReferenceFrame) 1.3044 + , mOverrideZIndex(0) 1.3045 +{ 1.3046 + mList.AppendToTop(aItem); 1.3047 + mBounds = mList.GetBounds(aBuilder); 1.3048 +} 1.3049 + 1.3050 +nsDisplayWrapList::~nsDisplayWrapList() { 1.3051 + mList.DeleteAll(); 1.3052 +} 1.3053 + 1.3054 +void 1.3055 +nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.3056 + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) { 1.3057 + mList.HitTest(aBuilder, aRect, aState, aOutFrames); 1.3058 +} 1.3059 + 1.3060 +nsRect 1.3061 +nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { 1.3062 + *aSnap = false; 1.3063 + return mBounds; 1.3064 +} 1.3065 + 1.3066 +bool 1.3067 +nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.3068 + nsRegion* aVisibleRegion, 1.3069 + const nsRect& aAllowVisibleRegionExpansion) { 1.3070 + // Convert the passed in visible region to our appunits. 1.3071 + nsRegion visibleRegion; 1.3072 + // mVisibleRect has been clipped to GetClippedBounds 1.3073 + visibleRegion.And(*aVisibleRegion, mVisibleRect); 1.3074 + nsRegion originalVisibleRegion = visibleRegion; 1.3075 + 1.3076 + bool retval = 1.3077 + mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, 1.3078 + mVisibleRect, 1.3079 + aAllowVisibleRegionExpansion); 1.3080 + 1.3081 + nsRegion removed; 1.3082 + // removed = originalVisibleRegion - visibleRegion 1.3083 + removed.Sub(originalVisibleRegion, visibleRegion); 1.3084 + // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications 1.3085 + // SubtractFromVisibleRegion does) 1.3086 + aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed); 1.3087 + 1.3088 + return retval; 1.3089 +} 1.3090 + 1.3091 +nsRegion 1.3092 +nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, 1.3093 + bool* aSnap) { 1.3094 + *aSnap = false; 1.3095 + nsRegion result; 1.3096 + if (mList.IsOpaque()) { 1.3097 + // Everything within GetBounds that's visible is opaque. 1.3098 + result = GetBounds(aBuilder, aSnap); 1.3099 + } 1.3100 + return result; 1.3101 +} 1.3102 + 1.3103 +bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { 1.3104 + // We could try to do something but let's conservatively just return false. 1.3105 + return false; 1.3106 +} 1.3107 + 1.3108 +bool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, 1.3109 + nsIFrame* aFrame) { 1.3110 + NS_WARNING("nsDisplayWrapList::IsVaryingRelativeToMovingFrame called unexpectedly"); 1.3111 + // We could try to do something but let's conservatively just return true. 1.3112 + return true; 1.3113 +} 1.3114 + 1.3115 +void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder, 1.3116 + nsRenderingContext* aCtx) { 1.3117 + NS_ERROR("nsDisplayWrapList should have been flattened away for painting"); 1.3118 +} 1.3119 + 1.3120 +/** 1.3121 + * Returns true if all descendant display items can be placed in the same 1.3122 + * ThebesLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE, 1.3123 + * and they all have the expected animated geometry root. 1.3124 + */ 1.3125 +static LayerState 1.3126 +RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder, 1.3127 + LayerManager* aManager, 1.3128 + const ContainerLayerParameters& aParameters, 1.3129 + const nsDisplayList& aList, 1.3130 + nsIFrame* aExpectedAnimatedGeometryRootForChildren) 1.3131 +{ 1.3132 + LayerState result = LAYER_INACTIVE; 1.3133 + for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) { 1.3134 + if (result == LAYER_INACTIVE && 1.3135 + nsLayoutUtils::GetAnimatedGeometryRootFor(i, aBuilder) != 1.3136 + aExpectedAnimatedGeometryRootForChildren) { 1.3137 + result = LAYER_ACTIVE; 1.3138 + } 1.3139 + 1.3140 + LayerState state = i->GetLayerState(aBuilder, aManager, aParameters); 1.3141 + if ((state == LAYER_ACTIVE || state == LAYER_ACTIVE_FORCE) && 1.3142 + state > result) { 1.3143 + result = state; 1.3144 + } 1.3145 + if (state == LAYER_ACTIVE_EMPTY && state > result) { 1.3146 + result = LAYER_ACTIVE_FORCE; 1.3147 + } 1.3148 + if (state == LAYER_NONE) { 1.3149 + nsDisplayList* list = i->GetSameCoordinateSystemChildren(); 1.3150 + if (list) { 1.3151 + LayerState childState = 1.3152 + RequiredLayerStateForChildren(aBuilder, aManager, aParameters, *list, 1.3153 + aExpectedAnimatedGeometryRootForChildren); 1.3154 + if (childState > result) { 1.3155 + result = childState; 1.3156 + } 1.3157 + } 1.3158 + } 1.3159 + } 1.3160 + return result; 1.3161 +} 1.3162 + 1.3163 +nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) 1.3164 +{ 1.3165 + nsRect bounds; 1.3166 + for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) { 1.3167 + bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder)); 1.3168 + } 1.3169 + return bounds; 1.3170 +} 1.3171 + 1.3172 +static nsresult 1.3173 +WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, 1.3174 + nsDisplayList* aList, nsDisplayWrapper* aWrapper) { 1.3175 + if (!aList->GetTop()) 1.3176 + return NS_OK; 1.3177 + nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList); 1.3178 + if (!item) 1.3179 + return NS_ERROR_OUT_OF_MEMORY; 1.3180 + // aList was emptied 1.3181 + aList->AppendToTop(item); 1.3182 + return NS_OK; 1.3183 +} 1.3184 + 1.3185 +static nsresult 1.3186 +WrapEachDisplayItem(nsDisplayListBuilder* aBuilder, 1.3187 + nsDisplayList* aList, nsDisplayWrapper* aWrapper) { 1.3188 + nsDisplayList newList; 1.3189 + nsDisplayItem* item; 1.3190 + while ((item = aList->RemoveBottom())) { 1.3191 + item = aWrapper->WrapItem(aBuilder, item); 1.3192 + if (!item) 1.3193 + return NS_ERROR_OUT_OF_MEMORY; 1.3194 + newList.AppendToTop(item); 1.3195 + } 1.3196 + // aList was emptied 1.3197 + aList->AppendToTop(&newList); 1.3198 + return NS_OK; 1.3199 +} 1.3200 + 1.3201 +nsresult nsDisplayWrapper::WrapLists(nsDisplayListBuilder* aBuilder, 1.3202 + nsIFrame* aFrame, const nsDisplayListSet& aIn, const nsDisplayListSet& aOut) 1.3203 +{ 1.3204 + nsresult rv = WrapListsInPlace(aBuilder, aFrame, aIn); 1.3205 + NS_ENSURE_SUCCESS(rv, rv); 1.3206 + 1.3207 + if (&aOut == &aIn) 1.3208 + return NS_OK; 1.3209 + aOut.BorderBackground()->AppendToTop(aIn.BorderBackground()); 1.3210 + aOut.BlockBorderBackgrounds()->AppendToTop(aIn.BlockBorderBackgrounds()); 1.3211 + aOut.Floats()->AppendToTop(aIn.Floats()); 1.3212 + aOut.Content()->AppendToTop(aIn.Content()); 1.3213 + aOut.PositionedDescendants()->AppendToTop(aIn.PositionedDescendants()); 1.3214 + aOut.Outlines()->AppendToTop(aIn.Outlines()); 1.3215 + return NS_OK; 1.3216 +} 1.3217 + 1.3218 +nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder, 1.3219 + nsIFrame* aFrame, const nsDisplayListSet& aLists) 1.3220 +{ 1.3221 + nsresult rv; 1.3222 + if (WrapBorderBackground()) { 1.3223 + // Our border-backgrounds are in-flow 1.3224 + rv = WrapDisplayList(aBuilder, aFrame, aLists.BorderBackground(), this); 1.3225 + NS_ENSURE_SUCCESS(rv, rv); 1.3226 + } 1.3227 + // Our block border-backgrounds are in-flow 1.3228 + rv = WrapDisplayList(aBuilder, aFrame, aLists.BlockBorderBackgrounds(), this); 1.3229 + NS_ENSURE_SUCCESS(rv, rv); 1.3230 + // The floats are not in flow 1.3231 + rv = WrapEachDisplayItem(aBuilder, aLists.Floats(), this); 1.3232 + NS_ENSURE_SUCCESS(rv, rv); 1.3233 + // Our child content is in flow 1.3234 + rv = WrapDisplayList(aBuilder, aFrame, aLists.Content(), this); 1.3235 + NS_ENSURE_SUCCESS(rv, rv); 1.3236 + // The positioned descendants may not be in-flow 1.3237 + rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this); 1.3238 + NS_ENSURE_SUCCESS(rv, rv); 1.3239 + // The outlines may not be in-flow 1.3240 + return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this); 1.3241 +} 1.3242 + 1.3243 +nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder, 1.3244 + nsIFrame* aFrame, nsDisplayList* aList) 1.3245 + : nsDisplayWrapList(aBuilder, aFrame, aList) { 1.3246 + MOZ_COUNT_CTOR(nsDisplayOpacity); 1.3247 +} 1.3248 + 1.3249 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3250 +nsDisplayOpacity::~nsDisplayOpacity() { 1.3251 + MOZ_COUNT_DTOR(nsDisplayOpacity); 1.3252 +} 1.3253 +#endif 1.3254 + 1.3255 +nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, 1.3256 + bool* aSnap) { 1.3257 + *aSnap = false; 1.3258 + // We are never opaque, if our opacity was < 1 then we wouldn't have 1.3259 + // been created. 1.3260 + return nsRegion(); 1.3261 +} 1.3262 + 1.3263 +// nsDisplayOpacity uses layers for rendering 1.3264 +already_AddRefed<Layer> 1.3265 +nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3266 + LayerManager* aManager, 1.3267 + const ContainerLayerParameters& aContainerParameters) { 1.3268 + if (mFrame->StyleDisplay()->mOpacity == 0 && mFrame->GetContent() && 1.3269 + !nsLayoutUtils::HasAnimations(mFrame->GetContent(), eCSSProperty_opacity)) { 1.3270 + return nullptr; 1.3271 + } 1.3272 + nsRefPtr<Layer> container = aManager->GetLayerBuilder()-> 1.3273 + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, 1.3274 + aContainerParameters, nullptr); 1.3275 + if (!container) 1.3276 + return nullptr; 1.3277 + 1.3278 + container->SetOpacity(mFrame->StyleDisplay()->mOpacity); 1.3279 + nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder, 1.3280 + this, mFrame, 1.3281 + eCSSProperty_opacity); 1.3282 + return container.forget(); 1.3283 +} 1.3284 + 1.3285 +/** 1.3286 + * This doesn't take into account layer scaling --- the layer may be 1.3287 + * rendered at a higher (or lower) resolution, affecting the retained layer 1.3288 + * size --- but this should be good enough. 1.3289 + */ 1.3290 +static bool 1.3291 +IsItemTooSmallForActiveLayer(nsDisplayItem* aItem) 1.3292 +{ 1.3293 + nsIntRect visibleDevPixels = aItem->GetVisibleRect().ToOutsidePixels( 1.3294 + aItem->Frame()->PresContext()->AppUnitsPerDevPixel()); 1.3295 + static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS = 16; 1.3296 + return visibleDevPixels.Size() < 1.3297 + nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS); 1.3298 +} 1.3299 + 1.3300 +bool 1.3301 +nsDisplayOpacity::NeedsActiveLayer() 1.3302 +{ 1.3303 + if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_opacity) && 1.3304 + !IsItemTooSmallForActiveLayer(this)) 1.3305 + return true; 1.3306 + if (mFrame->GetContent()) { 1.3307 + if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(), 1.3308 + eCSSProperty_opacity)) { 1.3309 + return true; 1.3310 + } 1.3311 + } 1.3312 + return false; 1.3313 +} 1.3314 + 1.3315 +bool 1.3316 +nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) 1.3317 +{ 1.3318 + if (NeedsActiveLayer()) 1.3319 + return false; 1.3320 + 1.3321 + nsDisplayItem* child = mList.GetBottom(); 1.3322 + // Only try folding our opacity down if we have a single 1.3323 + // child. We could potentially do this also if we had multiple 1.3324 + // children as long as they don't overlap. 1.3325 + if (!child || child->GetAbove()) { 1.3326 + return false; 1.3327 + } 1.3328 + 1.3329 + return child->ApplyOpacity(aBuilder, mFrame->StyleDisplay()->mOpacity, mClip); 1.3330 +} 1.3331 + 1.3332 +nsDisplayItem::LayerState 1.3333 +nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder, 1.3334 + LayerManager* aManager, 1.3335 + const ContainerLayerParameters& aParameters) { 1.3336 + if (NeedsActiveLayer()) 1.3337 + return LAYER_ACTIVE; 1.3338 + 1.3339 + return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, 1.3340 + nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder)); 1.3341 +} 1.3342 + 1.3343 +bool 1.3344 +nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.3345 + nsRegion* aVisibleRegion, 1.3346 + const nsRect& aAllowVisibleRegionExpansion) { 1.3347 + // Our children are translucent so we should not allow them to subtract 1.3348 + // area from aVisibleRegion. We do need to find out what is visible under 1.3349 + // our children in the temporary compositing buffer, because if our children 1.3350 + // paint our entire bounds opaquely then we don't need an alpha channel in 1.3351 + // the temporary compositing buffer. 1.3352 + nsRect bounds = GetClippedBounds(aBuilder); 1.3353 + nsRegion visibleUnderChildren; 1.3354 + visibleUnderChildren.And(*aVisibleRegion, bounds); 1.3355 + nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion); 1.3356 + return 1.3357 + nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren, 1.3358 + allowExpansion); 1.3359 +} 1.3360 + 1.3361 +bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { 1.3362 + if (aItem->GetType() != TYPE_OPACITY) 1.3363 + return false; 1.3364 + // items for the same content element should be merged into a single 1.3365 + // compositing group 1.3366 + // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity 1.3367 + if (aItem->Frame()->GetContent() != mFrame->GetContent()) 1.3368 + return false; 1.3369 + if (aItem->GetClip() != GetClip()) 1.3370 + return false; 1.3371 + MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem)); 1.3372 + return true; 1.3373 +} 1.3374 + 1.3375 +#ifdef MOZ_DUMP_PAINTING 1.3376 +void 1.3377 +nsDisplayOpacity::WriteDebugInfo(nsACString& aTo) 1.3378 +{ 1.3379 + aTo += nsPrintfCString(" (opacity %f)", mFrame->StyleDisplay()->mOpacity); 1.3380 +} 1.3381 +#endif 1.3382 + 1.3383 +nsDisplayMixBlendMode::nsDisplayMixBlendMode(nsDisplayListBuilder* aBuilder, 1.3384 + nsIFrame* aFrame, nsDisplayList* aList, 1.3385 + uint32_t aFlags) 1.3386 +: nsDisplayWrapList(aBuilder, aFrame, aList) { 1.3387 + MOZ_COUNT_CTOR(nsDisplayMixBlendMode); 1.3388 +} 1.3389 + 1.3390 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3391 +nsDisplayMixBlendMode::~nsDisplayMixBlendMode() { 1.3392 + MOZ_COUNT_DTOR(nsDisplayMixBlendMode); 1.3393 +} 1.3394 +#endif 1.3395 + 1.3396 +nsRegion nsDisplayMixBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, 1.3397 + bool* aSnap) { 1.3398 + *aSnap = false; 1.3399 + // We are never considered opaque 1.3400 + return nsRegion(); 1.3401 +} 1.3402 + 1.3403 +// nsDisplayMixBlendMode uses layers for rendering 1.3404 +already_AddRefed<Layer> 1.3405 +nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3406 + LayerManager* aManager, 1.3407 + const ContainerLayerParameters& aContainerParameters) { 1.3408 + ContainerLayerParameters newContainerParameters = aContainerParameters; 1.3409 + newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; 1.3410 + 1.3411 + nsRefPtr<Layer> container = aManager->GetLayerBuilder()-> 1.3412 + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, 1.3413 + newContainerParameters, nullptr); 1.3414 + if (!container) { 1.3415 + return nullptr; 1.3416 + } 1.3417 + 1.3418 + container->DeprecatedSetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mFrame->StyleDisplay()->mMixBlendMode)); 1.3419 + 1.3420 + return container.forget(); 1.3421 +} 1.3422 + 1.3423 +bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.3424 + nsRegion* aVisibleRegion, 1.3425 + const nsRect& aAllowVisibleRegionExpansion) { 1.3426 + // Our children are need their backdrop so we should not allow them to subtract 1.3427 + // area from aVisibleRegion. We do need to find out what is visible under 1.3428 + // our children in the temporary compositing buffer, because if our children 1.3429 + // paint our entire bounds opaquely then we don't need an alpha channel in 1.3430 + // the temporary compositing buffer. 1.3431 + nsRect bounds = GetClippedBounds(aBuilder); 1.3432 + nsRegion visibleUnderChildren; 1.3433 + visibleUnderChildren.And(*aVisibleRegion, bounds); 1.3434 + nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion); 1.3435 + return 1.3436 + nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren, 1.3437 + allowExpansion); 1.3438 +} 1.3439 + 1.3440 +bool nsDisplayMixBlendMode::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { 1.3441 + if (aItem->GetType() != TYPE_MIX_BLEND_MODE) 1.3442 + return false; 1.3443 + // items for the same content element should be merged into a single 1.3444 + // compositing group 1.3445 + // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity 1.3446 + if (aItem->Frame()->GetContent() != mFrame->GetContent()) 1.3447 + return false; 1.3448 + if (aItem->GetClip() != GetClip()) 1.3449 + return false; 1.3450 + MergeFromTrackingMergedFrames(static_cast<nsDisplayMixBlendMode*>(aItem)); 1.3451 + return true; 1.3452 +} 1.3453 + 1.3454 +nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, 1.3455 + nsIFrame* aFrame, nsDisplayList* aList, 1.3456 + uint32_t aFlags) 1.3457 + : nsDisplayWrapList(aBuilder, aFrame, aList) { 1.3458 + MOZ_COUNT_CTOR(nsDisplayBlendContainer); 1.3459 +} 1.3460 + 1.3461 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3462 +nsDisplayBlendContainer::~nsDisplayBlendContainer() { 1.3463 + MOZ_COUNT_DTOR(nsDisplayBlendContainer); 1.3464 +} 1.3465 +#endif 1.3466 + 1.3467 +// nsDisplayBlendContainer uses layers for rendering 1.3468 +already_AddRefed<Layer> 1.3469 +nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3470 + LayerManager* aManager, 1.3471 + const ContainerLayerParameters& aContainerParameters) { 1.3472 + // turn off anti-aliasing in the parent stacking context because it changes 1.3473 + // how the group is initialized. 1.3474 + ContainerLayerParameters newContainerParameters = aContainerParameters; 1.3475 + newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; 1.3476 + 1.3477 + nsRefPtr<Layer> container = aManager->GetLayerBuilder()-> 1.3478 + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, 1.3479 + newContainerParameters, nullptr); 1.3480 + if (!container) { 1.3481 + return nullptr; 1.3482 + } 1.3483 + 1.3484 + container->SetForceIsolatedGroup(true); 1.3485 + return container.forget(); 1.3486 +} 1.3487 + 1.3488 +bool nsDisplayBlendContainer::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { 1.3489 + if (aItem->GetType() != TYPE_BLEND_CONTAINER) 1.3490 + return false; 1.3491 + // items for the same content element should be merged into a single 1.3492 + // compositing group 1.3493 + // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity 1.3494 + if (aItem->Frame()->GetContent() != mFrame->GetContent()) 1.3495 + return false; 1.3496 + if (aItem->GetClip() != GetClip()) 1.3497 + return false; 1.3498 + MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem)); 1.3499 + return true; 1.3500 +} 1.3501 + 1.3502 +nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, 1.3503 + nsIFrame* aFrame, nsDisplayList* aList, 1.3504 + uint32_t aFlags, ViewID aScrollTarget) 1.3505 + : nsDisplayWrapList(aBuilder, aFrame, aList) 1.3506 + , mFlags(aFlags) 1.3507 + , mScrollTarget(aScrollTarget) { 1.3508 + MOZ_COUNT_CTOR(nsDisplayOwnLayer); 1.3509 +} 1.3510 + 1.3511 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3512 +nsDisplayOwnLayer::~nsDisplayOwnLayer() { 1.3513 + MOZ_COUNT_DTOR(nsDisplayOwnLayer); 1.3514 +} 1.3515 +#endif 1.3516 + 1.3517 +// nsDisplayOpacity uses layers for rendering 1.3518 +already_AddRefed<Layer> 1.3519 +nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3520 + LayerManager* aManager, 1.3521 + const ContainerLayerParameters& aContainerParameters) { 1.3522 + nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()-> 1.3523 + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, 1.3524 + aContainerParameters, nullptr); 1.3525 + if (mFlags & VERTICAL_SCROLLBAR) { 1.3526 + layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL); 1.3527 + } 1.3528 + if (mFlags & HORIZONTAL_SCROLLBAR) { 1.3529 + layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::HORIZONTAL); 1.3530 + } 1.3531 + 1.3532 + if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) { 1.3533 + mFrame->PresContext()->SetNotifySubDocInvalidationData(layer); 1.3534 + } 1.3535 + return layer.forget(); 1.3536 +} 1.3537 + 1.3538 +nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder, 1.3539 + nsIFrame* aFrame, nsDisplayList* aList, 1.3540 + uint32_t aFlags) 1.3541 + : nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags) 1.3542 + , mScrollParentId(aBuilder->GetCurrentScrollParentId()) 1.3543 +{ 1.3544 + MOZ_COUNT_CTOR(nsDisplaySubDocument); 1.3545 +} 1.3546 + 1.3547 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3548 +nsDisplaySubDocument::~nsDisplaySubDocument() { 1.3549 + MOZ_COUNT_DTOR(nsDisplaySubDocument); 1.3550 +} 1.3551 +#endif 1.3552 + 1.3553 +already_AddRefed<Layer> 1.3554 +nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3555 + LayerManager* aManager, 1.3556 + const ContainerLayerParameters& aContainerParameters) { 1.3557 + nsRefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer( 1.3558 + aBuilder, aManager, aContainerParameters); 1.3559 + 1.3560 + if (!(mFlags & GENERATE_SCROLLABLE_LAYER)) { 1.3561 + return layer.forget(); 1.3562 + } 1.3563 + 1.3564 + NS_ASSERTION(layer->AsContainerLayer(), "nsDisplayOwnLayer should have made a ContainerLayer"); 1.3565 + if (ContainerLayer* container = layer->AsContainerLayer()) { 1.3566 + nsPresContext* presContext = mFrame->PresContext(); 1.3567 + nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame(); 1.3568 + bool isRootContentDocument = presContext->IsRootContentDocument(); 1.3569 + 1.3570 + bool usingDisplayport = false; 1.3571 + bool usingCriticalDisplayport = false; 1.3572 + nsRect displayport, criticalDisplayport; 1.3573 + ViewID scrollId = FrameMetrics::NULL_SCROLL_ID; 1.3574 + if (rootScrollFrame) { 1.3575 + nsIContent* content = rootScrollFrame->GetContent(); 1.3576 + if (content) { 1.3577 + usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport); 1.3578 + usingCriticalDisplayport = 1.3579 + nsLayoutUtils::GetCriticalDisplayPort(content, &criticalDisplayport); 1.3580 + 1.3581 + if (isRootContentDocument) { 1.3582 + scrollId = nsLayoutUtils::FindOrCreateIDFor(content); 1.3583 + } else { 1.3584 + nsLayoutUtils::FindIDFor(content, &scrollId); 1.3585 + } 1.3586 + } 1.3587 + } 1.3588 + 1.3589 + nsRect viewport = mFrame->GetRect() - 1.3590 + mFrame->GetPosition() + 1.3591 + mFrame->GetOffsetToCrossDoc(ReferenceFrame()); 1.3592 + 1.3593 + container->SetScrollHandoffParentId(mScrollParentId); 1.3594 + RecordFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(), 1.3595 + container, mList.GetVisibleRect(), viewport, 1.3596 + (usingDisplayport ? &displayport : nullptr), 1.3597 + (usingCriticalDisplayport ? &criticalDisplayport : nullptr), 1.3598 + scrollId, isRootContentDocument, aContainerParameters); 1.3599 + } 1.3600 + 1.3601 + return layer.forget(); 1.3602 +} 1.3603 + 1.3604 +nsRect 1.3605 +nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) 1.3606 +{ 1.3607 + bool usingDisplayPort = 1.3608 + nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext()); 1.3609 + 1.3610 + if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) { 1.3611 + *aSnap = false; 1.3612 + return mFrame->GetRect() + aBuilder->ToReferenceFrame(mFrame); 1.3613 + } 1.3614 + 1.3615 + return nsDisplayOwnLayer::GetBounds(aBuilder, aSnap); 1.3616 +} 1.3617 + 1.3618 +bool 1.3619 +nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.3620 + nsRegion* aVisibleRegion, 1.3621 + const nsRect& aAllowVisibleRegionExpansion) 1.3622 +{ 1.3623 + nsRect displayport; 1.3624 + bool usingDisplayPort = 1.3625 + nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext(), &displayport); 1.3626 + 1.3627 + if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) { 1.3628 + return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion, 1.3629 + aAllowVisibleRegionExpansion); 1.3630 + } 1.3631 + 1.3632 + nsRegion childVisibleRegion; 1.3633 + // The visible region for the children may be much bigger than the hole we 1.3634 + // are viewing the children from, so that the compositor process has enough 1.3635 + // content to asynchronously pan while content is being refreshed. 1.3636 + childVisibleRegion = displayport + mFrame->GetOffsetToCrossDoc(ReferenceFrame()); 1.3637 + 1.3638 + nsRect boundedRect = 1.3639 + childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder)); 1.3640 + nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion); 1.3641 + bool visible = mList.ComputeVisibilityForSublist( 1.3642 + aBuilder, &childVisibleRegion, boundedRect, allowExpansion, 1.3643 + usingDisplayPort ? mFrame : nullptr); 1.3644 + // We don't allow this computation to influence aVisibleRegion, on the 1.3645 + // assumption that the layer can be asynchronously scrolled so we'll 1.3646 + // definitely need all the content under it. 1.3647 + 1.3648 + return visible; 1.3649 +} 1.3650 + 1.3651 +bool 1.3652 +nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) 1.3653 +{ 1.3654 + bool usingDisplayPort = 1.3655 + nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext()); 1.3656 + 1.3657 + if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) { 1.3658 + return true; 1.3659 + } 1.3660 + 1.3661 + return nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(aBuilder); 1.3662 +} 1.3663 + 1.3664 +nsRegion 1.3665 +nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) 1.3666 +{ 1.3667 + bool usingDisplayPort = 1.3668 + nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext()); 1.3669 + 1.3670 + if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) { 1.3671 + *aSnap = false; 1.3672 + return nsRegion(); 1.3673 + } 1.3674 + 1.3675 + return nsDisplayOwnLayer::GetOpaqueRegion(aBuilder, aSnap); 1.3676 +} 1.3677 + 1.3678 +nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder* aBuilder, 1.3679 + nsIFrame* aFrame, nsDisplayList* aList, 1.3680 + uint32_t aFlags) 1.3681 + : nsDisplaySubDocument(aBuilder, aFrame, aList, aFlags) { 1.3682 + MOZ_COUNT_CTOR(nsDisplayResolution); 1.3683 +} 1.3684 + 1.3685 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3686 +nsDisplayResolution::~nsDisplayResolution() { 1.3687 + MOZ_COUNT_DTOR(nsDisplayResolution); 1.3688 +} 1.3689 +#endif 1.3690 + 1.3691 +already_AddRefed<Layer> 1.3692 +nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3693 + LayerManager* aManager, 1.3694 + const ContainerLayerParameters& aContainerParameters) { 1.3695 + nsIPresShell* presShell = mFrame->PresContext()->PresShell(); 1.3696 + ContainerLayerParameters containerParameters( 1.3697 + presShell->GetXResolution(), presShell->GetYResolution(), nsIntPoint(), 1.3698 + aContainerParameters); 1.3699 + 1.3700 + nsRefPtr<Layer> layer = nsDisplaySubDocument::BuildLayer( 1.3701 + aBuilder, aManager, containerParameters); 1.3702 + layer->SetPostScale(1.0f / presShell->GetXResolution(), 1.3703 + 1.0f / presShell->GetYResolution()); 1.3704 + return layer.forget(); 1.3705 +} 1.3706 + 1.3707 +nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, 1.3708 + nsIFrame* aFrame, 1.3709 + nsDisplayList* aList) 1.3710 + : nsDisplayOwnLayer(aBuilder, aFrame, aList) 1.3711 +{ 1.3712 + MOZ_COUNT_CTOR(nsDisplayStickyPosition); 1.3713 +} 1.3714 + 1.3715 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3716 +nsDisplayStickyPosition::~nsDisplayStickyPosition() { 1.3717 + MOZ_COUNT_DTOR(nsDisplayStickyPosition); 1.3718 +} 1.3719 +#endif 1.3720 + 1.3721 +already_AddRefed<Layer> 1.3722 +nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3723 + LayerManager* aManager, 1.3724 + const ContainerLayerParameters& aContainerParameters) { 1.3725 + nsRefPtr<Layer> layer = 1.3726 + nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters); 1.3727 + 1.3728 + StickyScrollContainer* stickyScrollContainer = StickyScrollContainer:: 1.3729 + GetStickyScrollContainerForFrame(mFrame); 1.3730 + if (!stickyScrollContainer) { 1.3731 + return layer.forget(); 1.3732 + } 1.3733 + 1.3734 + nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame()); 1.3735 + nsPresContext* presContext = scrollFrame->PresContext(); 1.3736 + 1.3737 + // Sticky position frames whose scroll frame is the root scroll frame are 1.3738 + // reflowed into the scroll-port size if one has been set. 1.3739 + nsSize scrollFrameSize = scrollFrame->GetSize(); 1.3740 + if (scrollFrame == presContext->PresShell()->GetRootScrollFrame() && 1.3741 + presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) { 1.3742 + scrollFrameSize = presContext->PresShell()-> 1.3743 + GetScrollPositionClampingScrollPortSize(); 1.3744 + } 1.3745 + 1.3746 + nsLayoutUtils::SetFixedPositionLayerData(layer, scrollFrame, 1.3747 + nsRect(scrollFrame->GetOffsetToCrossDoc(ReferenceFrame()), scrollFrameSize), 1.3748 + mFrame, presContext, aContainerParameters); 1.3749 + 1.3750 + ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor( 1.3751 + stickyScrollContainer->ScrollFrame()->GetScrolledFrame()->GetContent()); 1.3752 + 1.3753 + float factor = presContext->AppUnitsPerDevPixel(); 1.3754 + nsRect outer; 1.3755 + nsRect inner; 1.3756 + stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner); 1.3757 + LayerRect stickyOuter(NSAppUnitsToFloatPixels(outer.x, factor) * 1.3758 + aContainerParameters.mXScale, 1.3759 + NSAppUnitsToFloatPixels(outer.y, factor) * 1.3760 + aContainerParameters.mYScale, 1.3761 + NSAppUnitsToFloatPixels(outer.width, factor) * 1.3762 + aContainerParameters.mXScale, 1.3763 + NSAppUnitsToFloatPixels(outer.height, factor) * 1.3764 + aContainerParameters.mYScale); 1.3765 + LayerRect stickyInner(NSAppUnitsToFloatPixels(inner.x, factor) * 1.3766 + aContainerParameters.mXScale, 1.3767 + NSAppUnitsToFloatPixels(inner.y, factor) * 1.3768 + aContainerParameters.mYScale, 1.3769 + NSAppUnitsToFloatPixels(inner.width, factor) * 1.3770 + aContainerParameters.mXScale, 1.3771 + NSAppUnitsToFloatPixels(inner.height, factor) * 1.3772 + aContainerParameters.mYScale); 1.3773 + layer->SetStickyPositionData(scrollId, stickyOuter, stickyInner); 1.3774 + 1.3775 + return layer.forget(); 1.3776 +} 1.3777 + 1.3778 +bool nsDisplayStickyPosition::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { 1.3779 + if (aItem->GetType() != TYPE_STICKY_POSITION) 1.3780 + return false; 1.3781 + // Items with the same fixed position frame can be merged. 1.3782 + nsDisplayStickyPosition* other = static_cast<nsDisplayStickyPosition*>(aItem); 1.3783 + if (other->mFrame != mFrame) 1.3784 + return false; 1.3785 + if (aItem->GetClip() != GetClip()) 1.3786 + return false; 1.3787 + MergeFromTrackingMergedFrames(other); 1.3788 + return true; 1.3789 +} 1.3790 + 1.3791 +nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, 1.3792 + nsDisplayList* aList, 1.3793 + nsIFrame* aForFrame, 1.3794 + nsIFrame* aScrolledFrame, 1.3795 + nsIFrame* aScrollFrame) 1.3796 + : nsDisplayWrapList(aBuilder, aForFrame, aList) 1.3797 + , mScrollFrame(aScrollFrame) 1.3798 + , mScrolledFrame(aScrolledFrame) 1.3799 + , mScrollParentId(aBuilder->GetCurrentScrollParentId()) 1.3800 +{ 1.3801 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3802 + MOZ_COUNT_CTOR(nsDisplayScrollLayer); 1.3803 +#endif 1.3804 + 1.3805 + NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(), 1.3806 + "Need a child frame with content"); 1.3807 +} 1.3808 + 1.3809 +nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, 1.3810 + nsDisplayItem* aItem, 1.3811 + nsIFrame* aForFrame, 1.3812 + nsIFrame* aScrolledFrame, 1.3813 + nsIFrame* aScrollFrame) 1.3814 + : nsDisplayWrapList(aBuilder, aForFrame, aItem) 1.3815 + , mScrollFrame(aScrollFrame) 1.3816 + , mScrolledFrame(aScrolledFrame) 1.3817 + , mScrollParentId(aBuilder->GetCurrentScrollParentId()) 1.3818 +{ 1.3819 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3820 + MOZ_COUNT_CTOR(nsDisplayScrollLayer); 1.3821 +#endif 1.3822 + 1.3823 + NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(), 1.3824 + "Need a child frame with content"); 1.3825 +} 1.3826 + 1.3827 +nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, 1.3828 + nsIFrame* aForFrame, 1.3829 + nsIFrame* aScrolledFrame, 1.3830 + nsIFrame* aScrollFrame) 1.3831 + : nsDisplayWrapList(aBuilder, aForFrame) 1.3832 + , mScrollFrame(aScrollFrame) 1.3833 + , mScrolledFrame(aScrolledFrame) 1.3834 + , mScrollParentId(aBuilder->GetCurrentScrollParentId()) 1.3835 +{ 1.3836 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3837 + MOZ_COUNT_CTOR(nsDisplayScrollLayer); 1.3838 +#endif 1.3839 + 1.3840 + NS_ASSERTION(mScrolledFrame && mScrolledFrame->GetContent(), 1.3841 + "Need a child frame with content"); 1.3842 +} 1.3843 + 1.3844 +#ifdef NS_BUILD_REFCNT_LOGGING 1.3845 +nsDisplayScrollLayer::~nsDisplayScrollLayer() 1.3846 +{ 1.3847 + MOZ_COUNT_DTOR(nsDisplayScrollLayer); 1.3848 +} 1.3849 +#endif 1.3850 + 1.3851 +nsRect 1.3852 +nsDisplayScrollLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) 1.3853 +{ 1.3854 + nsIScrollableFrame* sf = do_QueryFrame(mScrollFrame); 1.3855 + if (sf) { 1.3856 + *aSnap = false; 1.3857 + return sf->GetScrollPortRect() + aBuilder->ToReferenceFrame(mScrollFrame); 1.3858 + } 1.3859 + return nsDisplayWrapList::GetBounds(aBuilder, aSnap); 1.3860 +} 1.3861 + 1.3862 +already_AddRefed<Layer> 1.3863 +nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder, 1.3864 + LayerManager* aManager, 1.3865 + const ContainerLayerParameters& aContainerParameters) { 1.3866 + nsRefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()-> 1.3867 + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, 1.3868 + aContainerParameters, nullptr); 1.3869 + 1.3870 + // Get the already set unique ID for scrolling this content remotely. 1.3871 + // Or, if not set, generate a new ID. 1.3872 + nsIContent* content = mScrolledFrame->GetContent(); 1.3873 + ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(content); 1.3874 + 1.3875 + nsRect viewport = mScrollFrame->GetRect() - 1.3876 + mScrollFrame->GetPosition() + 1.3877 + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame()); 1.3878 + 1.3879 + bool usingDisplayport = false; 1.3880 + bool usingCriticalDisplayport = false; 1.3881 + nsRect displayport, criticalDisplayport; 1.3882 + if (content) { 1.3883 + usingDisplayport = nsLayoutUtils::GetDisplayPort(content, &displayport); 1.3884 + usingCriticalDisplayport = 1.3885 + nsLayoutUtils::GetCriticalDisplayPort(content, &criticalDisplayport); 1.3886 + } 1.3887 + layer->SetScrollHandoffParentId(mScrollParentId); 1.3888 + RecordFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), layer, 1.3889 + mList.GetVisibleRect(), viewport, 1.3890 + (usingDisplayport ? &displayport : nullptr), 1.3891 + (usingCriticalDisplayport ? &criticalDisplayport : nullptr), 1.3892 + scrollId, false, aContainerParameters); 1.3893 + 1.3894 + return layer.forget(); 1.3895 +} 1.3896 + 1.3897 +bool 1.3898 +nsDisplayScrollLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) 1.3899 +{ 1.3900 + if (nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), nullptr)) { 1.3901 + return true; 1.3902 + } 1.3903 + 1.3904 + return nsDisplayWrapList::ShouldBuildLayerEvenIfInvisible(aBuilder); 1.3905 +} 1.3906 + 1.3907 +bool 1.3908 +nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.3909 + nsRegion* aVisibleRegion, 1.3910 + const nsRect& aAllowVisibleRegionExpansion) 1.3911 +{ 1.3912 + nsRect displayport; 1.3913 + bool usingDisplayPort = 1.3914 + nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport); 1.3915 + nsRegion childVisibleRegion; 1.3916 + if (usingDisplayPort) { 1.3917 + // The visible region for the children may be much bigger than the hole we 1.3918 + // are viewing the children from, so that the compositor process has enough 1.3919 + // content to asynchronously pan while content is being refreshed. 1.3920 + childVisibleRegion = displayport + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame()); 1.3921 + } else { 1.3922 + bool snap; 1.3923 + childVisibleRegion = GetBounds(aBuilder, &snap); 1.3924 + } 1.3925 + 1.3926 + nsRect boundedRect = 1.3927 + childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder)); 1.3928 + nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion); 1.3929 + bool visible = mList.ComputeVisibilityForSublist( 1.3930 + aBuilder, &childVisibleRegion, boundedRect, allowExpansion, 1.3931 + usingDisplayPort ? mScrollFrame : nullptr); 1.3932 + // We don't allow this computation to influence aVisibleRegion, on the 1.3933 + // assumption that the layer can be asynchronously scrolled so we'll 1.3934 + // definitely need all the content under it. 1.3935 + 1.3936 + return visible; 1.3937 +} 1.3938 + 1.3939 +LayerState 1.3940 +nsDisplayScrollLayer::GetLayerState(nsDisplayListBuilder* aBuilder, 1.3941 + LayerManager* aManager, 1.3942 + const ContainerLayerParameters& aParameters) 1.3943 +{ 1.3944 + // Force this as a layer so we can scroll asynchronously. 1.3945 + // This causes incorrect rendering for rounded clips! 1.3946 + return LAYER_ACTIVE_FORCE; 1.3947 +} 1.3948 + 1.3949 +// Check if we are going to clip an abs pos item that we don't contain. 1.3950 +// Root scroll frames clip all their descendants, so we don't need to worry 1.3951 +// about them. 1.3952 +bool 1.3953 +WouldCauseIncorrectClippingOnAbsPosItem(nsDisplayListBuilder* aBuilder, 1.3954 + nsDisplayScrollLayer* aItem) 1.3955 +{ 1.3956 + nsIFrame* scrollFrame = aItem->GetScrollFrame(); 1.3957 + nsIPresShell* presShell = scrollFrame->PresContext()->PresShell(); 1.3958 + if (scrollFrame == presShell->GetRootScrollFrame()) { 1.3959 + return false; 1.3960 + } 1.3961 + nsIFrame* scrolledFrame = aItem->GetScrolledFrame(); 1.3962 + nsIFrame* frame = aItem->Frame(); 1.3963 + if (frame == scrolledFrame || !frame->IsAbsolutelyPositioned() || 1.3964 + nsLayoutUtils::IsAncestorFrameCrossDoc(scrollFrame, frame, presShell->GetRootFrame())) { 1.3965 + return false; 1.3966 + } 1.3967 + if (!aItem->GetClip().IsRectAffectedByClip(aItem->GetChildren()->GetBounds(aBuilder))) { 1.3968 + return false; 1.3969 + } 1.3970 + return true; 1.3971 +} 1.3972 + 1.3973 +bool 1.3974 +nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder* aBuilder, 1.3975 + nsDisplayItem* aItem) 1.3976 +{ 1.3977 + if (aItem->GetType() != TYPE_SCROLL_LAYER) { 1.3978 + return false; 1.3979 + } 1.3980 + nsDisplayScrollLayer* other = static_cast<nsDisplayScrollLayer*>(aItem); 1.3981 + if (other->mScrolledFrame != this->mScrolledFrame) { 1.3982 + return false; 1.3983 + } 1.3984 + if (aItem->GetClip() != GetClip()) { 1.3985 + return false; 1.3986 + } 1.3987 + 1.3988 + if (WouldCauseIncorrectClippingOnAbsPosItem(aBuilder, this) || 1.3989 + WouldCauseIncorrectClippingOnAbsPosItem(aBuilder, other)) { 1.3990 + return false; 1.3991 + } 1.3992 + 1.3993 + NS_ASSERTION(other->mReferenceFrame == mReferenceFrame, 1.3994 + "Must have the same reference frame!"); 1.3995 + 1.3996 + FrameProperties props = mScrolledFrame->Properties(); 1.3997 + props.Set(nsIFrame::ScrollLayerCount(), 1.3998 + reinterpret_cast<void*>(GetScrollLayerCount() - 1)); 1.3999 + 1.4000 + // Swap frames with the other item before doing MergeFrom. 1.4001 + // XXX - This ensures that the frame associated with a scroll layer after 1.4002 + // merging is the first, rather than the last. This tends to change less, 1.4003 + // ensuring we're more likely to retain the associated gfx layer. 1.4004 + // See Bug 729534 and Bug 731641. 1.4005 + nsIFrame* tmp = mFrame; 1.4006 + mFrame = other->mFrame; 1.4007 + other->mFrame = tmp; 1.4008 + MergeFromTrackingMergedFrames(other); 1.4009 + return true; 1.4010 +} 1.4011 + 1.4012 +void 1.4013 +PropagateClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip, 1.4014 + nsDisplayList* aList) 1.4015 +{ 1.4016 + for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) { 1.4017 + DisplayItemClip clip(i->GetClip()); 1.4018 + clip.IntersectWith(aClip); 1.4019 + i->SetClip(aBuilder, clip); 1.4020 + nsDisplayList* list = i->GetSameCoordinateSystemChildren(); 1.4021 + if (list) { 1.4022 + PropagateClip(aBuilder, aClip, list); 1.4023 + } 1.4024 + } 1.4025 +} 1.4026 + 1.4027 +bool 1.4028 +nsDisplayScrollLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) 1.4029 +{ 1.4030 + bool badAbsPosClip = WouldCauseIncorrectClippingOnAbsPosItem(aBuilder, this); 1.4031 + if (GetScrollLayerCount() > 1 || badAbsPosClip) { 1.4032 + // Propagate our clip to our children. The clip for the scroll frame is 1.4033 + // on this item, but not our child items so that they can draw non-visible 1.4034 + // parts of the display port. But if we are flattening we failed and can't 1.4035 + // draw the extra content, so it needs to be clipped. 1.4036 + // But don't induce our clip on abs pos frames that we shouldn't be clipping. 1.4037 + if (!badAbsPosClip) { 1.4038 + PropagateClip(aBuilder, GetClip(), &mList); 1.4039 + } 1.4040 + return true; 1.4041 + } 1.4042 + if (mFrame != mScrolledFrame) { 1.4043 + mMergedFrames.AppendElement(mFrame); 1.4044 + mFrame = mScrolledFrame; 1.4045 + } 1.4046 + return false; 1.4047 +} 1.4048 + 1.4049 +intptr_t 1.4050 +nsDisplayScrollLayer::GetScrollLayerCount() 1.4051 +{ 1.4052 + FrameProperties props = mScrolledFrame->Properties(); 1.4053 +#ifdef DEBUG 1.4054 + bool hasCount = false; 1.4055 + intptr_t result = reinterpret_cast<intptr_t>( 1.4056 + props.Get(nsIFrame::ScrollLayerCount(), &hasCount)); 1.4057 + // If this aborts, then the property was either not added before scroll 1.4058 + // layers were created or the property was deleted to early. If the latter, 1.4059 + // make sure that nsDisplayScrollInfoLayer is on the bottom of the list so 1.4060 + // that it is processed last. 1.4061 + NS_ABORT_IF_FALSE(hasCount, "nsDisplayScrollLayer should always be defined"); 1.4062 + return result; 1.4063 +#else 1.4064 + return reinterpret_cast<intptr_t>(props.Get(nsIFrame::ScrollLayerCount())); 1.4065 +#endif 1.4066 +} 1.4067 + 1.4068 +#ifdef MOZ_DUMP_PAINTING 1.4069 +void 1.4070 +nsDisplayScrollLayer::WriteDebugInfo(nsACString& aTo) 1.4071 +{ 1.4072 + aTo += nsPrintfCString(" (scrollframe %p scrolledframe %p)", 1.4073 + mScrollFrame, mScrolledFrame); 1.4074 +} 1.4075 +#endif 1.4076 + 1.4077 +nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer( 1.4078 + nsDisplayListBuilder* aBuilder, 1.4079 + nsIFrame* aScrolledFrame, 1.4080 + nsIFrame* aScrollFrame) 1.4081 + : nsDisplayScrollLayer(aBuilder, aScrollFrame, aScrolledFrame, aScrollFrame) 1.4082 +{ 1.4083 +#ifdef NS_BUILD_REFCNT_LOGGING 1.4084 + MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer); 1.4085 +#endif 1.4086 +} 1.4087 + 1.4088 +nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer() 1.4089 +{ 1.4090 + FrameProperties props = mScrolledFrame->Properties(); 1.4091 + props.Remove(nsIFrame::ScrollLayerCount()); 1.4092 + MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer); 1.4093 +} 1.4094 + 1.4095 +nsRect 1.4096 +nsDisplayScrollInfoLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) 1.4097 +{ 1.4098 + return nsDisplayWrapList::GetBounds(aBuilder, aSnap); 1.4099 +} 1.4100 + 1.4101 +LayerState 1.4102 +nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder, 1.4103 + LayerManager* aManager, 1.4104 + const ContainerLayerParameters& aParameters) 1.4105 +{ 1.4106 + return LAYER_ACTIVE_EMPTY; 1.4107 +} 1.4108 + 1.4109 +bool 1.4110 +nsDisplayScrollInfoLayer::TryMerge(nsDisplayListBuilder* aBuilder, 1.4111 + nsDisplayItem* aItem) 1.4112 +{ 1.4113 + return false; 1.4114 +} 1.4115 + 1.4116 +bool 1.4117 +nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) 1.4118 +{ 1.4119 + // Layer metadata for a particular scroll frame needs to be unique. Only 1.4120 + // one nsDisplayScrollLayer (with rendered content) or one 1.4121 + // nsDisplayScrollInfoLayer (with only the metadata) should survive the 1.4122 + // visibility computation. 1.4123 + return GetScrollLayerCount() == 1; 1.4124 +} 1.4125 + 1.4126 +nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder, 1.4127 + nsIFrame* aFrame, nsDisplayList* aList, 1.4128 + int32_t aAPD, int32_t aParentAPD, 1.4129 + uint32_t aFlags) 1.4130 + : nsDisplaySubDocument(aBuilder, aFrame, aList, aFlags) 1.4131 + , mAPD(aAPD), mParentAPD(aParentAPD) { 1.4132 + MOZ_COUNT_CTOR(nsDisplayZoom); 1.4133 +} 1.4134 + 1.4135 +#ifdef NS_BUILD_REFCNT_LOGGING 1.4136 +nsDisplayZoom::~nsDisplayZoom() { 1.4137 + MOZ_COUNT_DTOR(nsDisplayZoom); 1.4138 +} 1.4139 +#endif 1.4140 + 1.4141 +nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) 1.4142 +{ 1.4143 + nsRect bounds = nsDisplaySubDocument::GetBounds(aBuilder, aSnap); 1.4144 + *aSnap = false; 1.4145 + return bounds.ConvertAppUnitsRoundOut(mAPD, mParentAPD); 1.4146 +} 1.4147 + 1.4148 +void nsDisplayZoom::HitTest(nsDisplayListBuilder *aBuilder, 1.4149 + const nsRect& aRect, 1.4150 + HitTestState *aState, 1.4151 + nsTArray<nsIFrame*> *aOutFrames) 1.4152 +{ 1.4153 + nsRect rect; 1.4154 + // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1 1.4155 + // rect as well instead of possibly rounding the width or height to zero. 1.4156 + if (aRect.width == 1 && aRect.height == 1) { 1.4157 + rect.MoveTo(aRect.TopLeft().ConvertAppUnits(mParentAPD, mAPD)); 1.4158 + rect.width = rect.height = 1; 1.4159 + } else { 1.4160 + rect = aRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD); 1.4161 + } 1.4162 + mList.HitTest(aBuilder, rect, aState, aOutFrames); 1.4163 +} 1.4164 + 1.4165 +void nsDisplayZoom::Paint(nsDisplayListBuilder* aBuilder, 1.4166 + nsRenderingContext* aCtx) 1.4167 +{ 1.4168 + mList.PaintForFrame(aBuilder, aCtx, mFrame, nsDisplayList::PAINT_DEFAULT); 1.4169 +} 1.4170 + 1.4171 +bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder, 1.4172 + nsRegion *aVisibleRegion, 1.4173 + const nsRect& aAllowVisibleRegionExpansion) 1.4174 +{ 1.4175 + // Convert the passed in visible region to our appunits. 1.4176 + nsRegion visibleRegion; 1.4177 + // mVisibleRect has been clipped to GetClippedBounds 1.4178 + visibleRegion.And(*aVisibleRegion, mVisibleRect); 1.4179 + visibleRegion = visibleRegion.ConvertAppUnitsRoundOut(mParentAPD, mAPD); 1.4180 + nsRegion originalVisibleRegion = visibleRegion; 1.4181 + 1.4182 + nsRect transformedVisibleRect = 1.4183 + mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD); 1.4184 + nsRect allowExpansion = 1.4185 + aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD); 1.4186 + bool retval; 1.4187 + // If we are to generate a scrollable layer we call 1.4188 + // nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments 1.4189 + // for ComputeVisibility, it does all it's calculations in the child APD. 1.4190 + bool usingDisplayPort = 1.4191 + nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext()); 1.4192 + if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) { 1.4193 + retval = 1.4194 + mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, 1.4195 + transformedVisibleRect, 1.4196 + allowExpansion); 1.4197 + } else { 1.4198 + retval = 1.4199 + nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion, 1.4200 + allowExpansion); 1.4201 + } 1.4202 + 1.4203 + nsRegion removed; 1.4204 + // removed = originalVisibleRegion - visibleRegion 1.4205 + removed.Sub(originalVisibleRegion, visibleRegion); 1.4206 + // Convert removed region to parent appunits. 1.4207 + removed = removed.ConvertAppUnitsRoundIn(mAPD, mParentAPD); 1.4208 + // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications 1.4209 + // SubtractFromVisibleRegion does) 1.4210 + aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed); 1.4211 + 1.4212 + return retval; 1.4213 +} 1.4214 + 1.4215 +/////////////////////////////////////////////////// 1.4216 +// nsDisplayTransform Implementation 1.4217 +// 1.4218 + 1.4219 +// Write #define UNIFIED_CONTINUATIONS here to have the transform property try 1.4220 +// to transform content with continuations as one unified block instead of 1.4221 +// several smaller ones. This is currently disabled because it doesn't work 1.4222 +// correctly, since when the frames are initially being reflowed, their 1.4223 +// continuations all compute their bounding rects independently of each other 1.4224 +// and consequently get the wrong value. Write #define DEBUG_HIT here to have 1.4225 +// the nsDisplayTransform class dump out a bunch of information about hit 1.4226 +// detection. 1.4227 +#undef UNIFIED_CONTINUATIONS 1.4228 +#undef DEBUG_HIT 1.4229 + 1.4230 +/* Returns the bounds of a frame as defined for transforms. If 1.4231 + * UNIFIED_CONTINUATIONS is not defined, this is simply the frame's bounding 1.4232 + * rectangle, translated to the origin. Otherwise, returns the smallest 1.4233 + * rectangle containing a frame and all of its continuations. For example, if 1.4234 + * there is a <span> element with several continuations split over several 1.4235 + * lines, this function will return the rectangle containing all of those 1.4236 + * continuations. This rectangle is relative to the origin of the frame's local 1.4237 + * coordinate space. 1.4238 + */ 1.4239 +#ifndef UNIFIED_CONTINUATIONS 1.4240 + 1.4241 +nsRect 1.4242 +nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame) 1.4243 +{ 1.4244 + NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!"); 1.4245 + 1.4246 + if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { 1.4247 + // TODO: SVG needs to define what percentage translations resolve against. 1.4248 + return nsRect(); 1.4249 + } 1.4250 + 1.4251 + return nsRect(nsPoint(0, 0), aFrame->GetSize()); 1.4252 +} 1.4253 + 1.4254 +#else 1.4255 + 1.4256 +nsRect 1.4257 +nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame) 1.4258 +{ 1.4259 + NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!"); 1.4260 + 1.4261 + nsRect result; 1.4262 + 1.4263 + if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { 1.4264 + // TODO: SVG needs to define what percentage translations resolve against. 1.4265 + return result; 1.4266 + } 1.4267 + 1.4268 + /* Iterate through the continuation list, unioning together all the 1.4269 + * bounding rects. 1.4270 + */ 1.4271 + for (const nsIFrame *currFrame = aFrame->FirstContinuation(); 1.4272 + currFrame != nullptr; 1.4273 + currFrame = currFrame->GetNextContinuation()) 1.4274 + { 1.4275 + /* Get the frame rect in local coordinates, then translate back to the 1.4276 + * original coordinates. 1.4277 + */ 1.4278 + result.UnionRect(result, nsRect(currFrame->GetOffsetTo(aFrame), 1.4279 + currFrame->GetSize())); 1.4280 + } 1.4281 + 1.4282 + return result; 1.4283 +} 1.4284 + 1.4285 +#endif 1.4286 + 1.4287 +nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, 1.4288 + nsDisplayList *aList, ComputeTransformFunction aTransformGetter, 1.4289 + uint32_t aIndex) 1.4290 + : nsDisplayItem(aBuilder, aFrame) 1.4291 + , mStoredList(aBuilder, aFrame, aList) 1.4292 + , mTransformGetter(aTransformGetter) 1.4293 + , mIndex(aIndex) 1.4294 +{ 1.4295 + MOZ_COUNT_CTOR(nsDisplayTransform); 1.4296 + NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); 1.4297 + NS_ABORT_IF_FALSE(!aFrame->IsTransformed(), "Can't specify a transform getter for a transformed frame!"); 1.4298 + mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); 1.4299 +} 1.4300 + 1.4301 +nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, 1.4302 + nsDisplayList *aList, uint32_t aIndex) 1.4303 + : nsDisplayItem(aBuilder, aFrame) 1.4304 + , mStoredList(aBuilder, aFrame, aList) 1.4305 + , mTransformGetter(nullptr) 1.4306 + , mIndex(aIndex) 1.4307 +{ 1.4308 + MOZ_COUNT_CTOR(nsDisplayTransform); 1.4309 + NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); 1.4310 + mReferenceFrame = 1.4311 + aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); 1.4312 + mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); 1.4313 + mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); 1.4314 +} 1.4315 + 1.4316 +nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, 1.4317 + nsDisplayItem *aItem, uint32_t aIndex) 1.4318 + : nsDisplayItem(aBuilder, aFrame) 1.4319 + , mStoredList(aBuilder, aFrame, aItem) 1.4320 + , mTransformGetter(nullptr) 1.4321 + , mIndex(aIndex) 1.4322 +{ 1.4323 + MOZ_COUNT_CTOR(nsDisplayTransform); 1.4324 + NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); 1.4325 + mReferenceFrame = 1.4326 + aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); 1.4327 + mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); 1.4328 + mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); 1.4329 +} 1.4330 + 1.4331 +/* Returns the delta specified by the -moz-transform-origin property. 1.4332 + * This is a positive delta, meaning that it indicates the direction to move 1.4333 + * to get from (0, 0) of the frame to the transform origin. This function is 1.4334 + * called off the main thread. 1.4335 + */ 1.4336 +/* static */ gfxPoint3D 1.4337 +nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame, 1.4338 + float aAppUnitsPerPixel, 1.4339 + const nsRect* aBoundsOverride) 1.4340 +{ 1.4341 + NS_PRECONDITION(aFrame, "Can't get delta for a null frame!"); 1.4342 + NS_PRECONDITION(aFrame->IsTransformed() || aFrame->StyleDisplay()->BackfaceIsHidden(), 1.4343 + "Shouldn't get a delta for an untransformed frame!"); 1.4344 + 1.4345 + if (!aFrame->IsTransformed()) { 1.4346 + return gfxPoint3D(); 1.4347 + } 1.4348 + 1.4349 + /* For both of the coordinates, if the value of -moz-transform is a 1.4350 + * percentage, it's relative to the size of the frame. Otherwise, if it's 1.4351 + * a distance, it's already computed for us! 1.4352 + */ 1.4353 + const nsStyleDisplay* display = aFrame->StyleDisplay(); 1.4354 + nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride : 1.4355 + nsDisplayTransform::GetFrameBoundsForTransform(aFrame)); 1.4356 + 1.4357 + /* Allows us to access named variables by index. */ 1.4358 + float coords[3]; 1.4359 + const nscoord* dimensions[2] = 1.4360 + {&boundingRect.width, &boundingRect.height}; 1.4361 + 1.4362 + for (uint8_t index = 0; index < 2; ++index) { 1.4363 + /* If the -moz-transform-origin specifies a percentage, take the percentage 1.4364 + * of the size of the box. 1.4365 + */ 1.4366 + const nsStyleCoord &coord = display->mTransformOrigin[index]; 1.4367 + if (coord.GetUnit() == eStyleUnit_Calc) { 1.4368 + const nsStyleCoord::Calc *calc = coord.GetCalcValue(); 1.4369 + coords[index] = 1.4370 + NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) * 1.4371 + calc->mPercent + 1.4372 + NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel); 1.4373 + } else if (coord.GetUnit() == eStyleUnit_Percent) { 1.4374 + coords[index] = 1.4375 + NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) * 1.4376 + coord.GetPercentValue(); 1.4377 + } else { 1.4378 + NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit"); 1.4379 + coords[index] = 1.4380 + NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel); 1.4381 + } 1.4382 + if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) && 1.4383 + coord.GetUnit() != eStyleUnit_Percent) { 1.4384 + // <length> values represent offsets from the origin of the SVG element's 1.4385 + // user space, not the top left of its bounds, so we must adjust for that: 1.4386 + nscoord offset = 1.4387 + (index == 0) ? aFrame->GetPosition().x : aFrame->GetPosition().y; 1.4388 + coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel); 1.4389 + } 1.4390 + } 1.4391 + 1.4392 + coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(), 1.4393 + aAppUnitsPerPixel); 1.4394 + /* Adjust based on the origin of the rectangle. */ 1.4395 + coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel); 1.4396 + coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel); 1.4397 + 1.4398 + return gfxPoint3D(coords[0], coords[1], coords[2]); 1.4399 +} 1.4400 + 1.4401 +/* Returns the delta specified by the -moz-perspective-origin property. 1.4402 + * This is a positive delta, meaning that it indicates the direction to move 1.4403 + * to get from (0, 0) of the frame to the perspective origin. This function is 1.4404 + * called off the main thread. 1.4405 + */ 1.4406 +/* static */ gfxPoint3D 1.4407 +nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame, 1.4408 + float aAppUnitsPerPixel) 1.4409 +{ 1.4410 + NS_PRECONDITION(aFrame, "Can't get delta for a null frame!"); 1.4411 + NS_PRECONDITION(aFrame->IsTransformed() || aFrame->StyleDisplay()->BackfaceIsHidden(), 1.4412 + "Shouldn't get a delta for an untransformed frame!"); 1.4413 + 1.4414 + if (!aFrame->IsTransformed()) { 1.4415 + return gfxPoint3D(); 1.4416 + } 1.4417 + 1.4418 + /* For both of the coordinates, if the value of -moz-perspective-origin is a 1.4419 + * percentage, it's relative to the size of the frame. Otherwise, if it's 1.4420 + * a distance, it's already computed for us! 1.4421 + */ 1.4422 + 1.4423 + //TODO: Should this be using our bounds or the parent's bounds? 1.4424 + // How do we handle aBoundsOverride in the latter case? 1.4425 + nsIFrame* parent = aFrame->GetParentStyleContextFrame(); 1.4426 + if (!parent) { 1.4427 + return gfxPoint3D(); 1.4428 + } 1.4429 + const nsStyleDisplay* display = parent->StyleDisplay(); 1.4430 + nsRect boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(parent); 1.4431 + 1.4432 + /* Allows us to access named variables by index. */ 1.4433 + gfxPoint3D result; 1.4434 + result.z = 0.0f; 1.4435 + gfxFloat* coords[2] = {&result.x, &result.y}; 1.4436 + const nscoord* dimensions[2] = 1.4437 + {&boundingRect.width, &boundingRect.height}; 1.4438 + 1.4439 + for (uint8_t index = 0; index < 2; ++index) { 1.4440 + /* If the -moz-transform-origin specifies a percentage, take the percentage 1.4441 + * of the size of the box. 1.4442 + */ 1.4443 + const nsStyleCoord &coord = display->mPerspectiveOrigin[index]; 1.4444 + if (coord.GetUnit() == eStyleUnit_Calc) { 1.4445 + const nsStyleCoord::Calc *calc = coord.GetCalcValue(); 1.4446 + *coords[index] = 1.4447 + NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) * 1.4448 + calc->mPercent + 1.4449 + NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel); 1.4450 + } else if (coord.GetUnit() == eStyleUnit_Percent) { 1.4451 + *coords[index] = 1.4452 + NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) * 1.4453 + coord.GetPercentValue(); 1.4454 + } else { 1.4455 + NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit"); 1.4456 + *coords[index] = 1.4457 + NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel); 1.4458 + } 1.4459 + } 1.4460 + 1.4461 + nsPoint parentOffset = aFrame->GetOffsetTo(parent); 1.4462 + gfxPoint3D gfxOffset( 1.4463 + NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel), 1.4464 + NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel), 1.4465 + 0.0f); 1.4466 + 1.4467 + return result - gfxOffset; 1.4468 +} 1.4469 + 1.4470 +nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame* aFrame, 1.4471 + float aAppUnitsPerPixel, 1.4472 + const nsRect* aBoundsOverride) 1.4473 + : mFrame(aFrame) 1.4474 + , mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform) 1.4475 + , mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride)) 1.4476 + , mToPerspectiveOrigin(GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel)) 1.4477 + , mChildPerspective(0) 1.4478 +{ 1.4479 + const nsStyleDisplay* parentDisp = nullptr; 1.4480 + nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent(); 1.4481 + if (parentStyleContext) { 1.4482 + parentDisp = parentStyleContext->StyleDisplay(); 1.4483 + } 1.4484 + if (parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord) { 1.4485 + mChildPerspective = parentDisp->mChildPerspective.GetCoordValue(); 1.4486 + } 1.4487 +} 1.4488 + 1.4489 +/* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that 1.4490 + * translates from local coordinate space to transform coordinate space, then 1.4491 + * hands it back. 1.4492 + */ 1.4493 +gfx3DMatrix 1.4494 +nsDisplayTransform::GetResultingTransformMatrix(const FrameTransformProperties& aProperties, 1.4495 + const nsPoint& aOrigin, 1.4496 + float aAppUnitsPerPixel, 1.4497 + const nsRect* aBoundsOverride, 1.4498 + nsIFrame** aOutAncestor) 1.4499 +{ 1.4500 + return GetResultingTransformMatrixInternal(aProperties, aOrigin, aAppUnitsPerPixel, 1.4501 + aBoundsOverride, aOutAncestor); 1.4502 +} 1.4503 + 1.4504 +gfx3DMatrix 1.4505 +nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame, 1.4506 + const nsPoint& aOrigin, 1.4507 + float aAppUnitsPerPixel, 1.4508 + const nsRect* aBoundsOverride, 1.4509 + nsIFrame** aOutAncestor) 1.4510 +{ 1.4511 + FrameTransformProperties props(aFrame, 1.4512 + aAppUnitsPerPixel, 1.4513 + aBoundsOverride); 1.4514 + 1.4515 + return GetResultingTransformMatrixInternal(props, aOrigin, aAppUnitsPerPixel, 1.4516 + aBoundsOverride, aOutAncestor); 1.4517 +} 1.4518 + 1.4519 +gfx3DMatrix 1.4520 +nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties, 1.4521 + const nsPoint& aOrigin, 1.4522 + float aAppUnitsPerPixel, 1.4523 + const nsRect* aBoundsOverride, 1.4524 + nsIFrame** aOutAncestor) 1.4525 +{ 1.4526 + const nsIFrame *frame = aProperties.mFrame; 1.4527 + 1.4528 + if (aOutAncestor) { 1.4529 + *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(frame); 1.4530 + } 1.4531 + 1.4532 + /* Account for the -moz-transform-origin property by translating the 1.4533 + * coordinate space to the new origin. 1.4534 + */ 1.4535 + gfxPoint3D newOrigin = 1.4536 + gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel), 1.4537 + NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel), 1.4538 + 0.0f); 1.4539 + 1.4540 + /* Get the underlying transform matrix. This requires us to get the 1.4541 + * bounds of the frame. 1.4542 + */ 1.4543 + nsRect bounds = (aBoundsOverride ? *aBoundsOverride : 1.4544 + nsDisplayTransform::GetFrameBoundsForTransform(frame)); 1.4545 + 1.4546 + /* Get the matrix, then change its basis to factor in the origin. */ 1.4547 + bool dummy; 1.4548 + gfx3DMatrix result; 1.4549 + // Call IsSVGTransformed() regardless of the value of 1.4550 + // disp->mSpecifiedTransform, since we still need any transformFromSVGParent. 1.4551 + mozilla::gfx::Matrix svgTransform, transformFromSVGParent; 1.4552 + bool hasSVGTransforms = 1.4553 + frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent); 1.4554 + /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */ 1.4555 + if (aProperties.mTransformList) { 1.4556 + result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead, 1.4557 + frame ? frame->StyleContext() : nullptr, 1.4558 + frame ? frame->PresContext() : nullptr, 1.4559 + dummy, bounds, aAppUnitsPerPixel); 1.4560 + } else if (hasSVGTransforms) { 1.4561 + // Correct the translation components for zoom: 1.4562 + float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() / 1.4563 + aAppUnitsPerPixel; 1.4564 + svgTransform._31 *= pixelsPerCSSPx; 1.4565 + svgTransform._32 *= pixelsPerCSSPx; 1.4566 + result = gfx3DMatrix::From2D(ThebesMatrix(svgTransform)); 1.4567 + } 1.4568 + 1.4569 + if (hasSVGTransforms && !transformFromSVGParent.IsIdentity()) { 1.4570 + // Correct the translation components for zoom: 1.4571 + float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() / 1.4572 + aAppUnitsPerPixel; 1.4573 + transformFromSVGParent._31 *= pixelsPerCSSPx; 1.4574 + transformFromSVGParent._32 *= pixelsPerCSSPx; 1.4575 + result = result * gfx3DMatrix::From2D(ThebesMatrix(transformFromSVGParent)); 1.4576 + } 1.4577 + 1.4578 + if (aProperties.mChildPerspective > 0.0) { 1.4579 + gfx3DMatrix perspective; 1.4580 + perspective._34 = 1.4581 + -1.0 / NSAppUnitsToFloatPixels(aProperties.mChildPerspective, aAppUnitsPerPixel); 1.4582 + /* At the point when perspective is applied, we have been translated to the transform origin. 1.4583 + * The translation to the perspective origin is the difference between these values. 1.4584 + */ 1.4585 + result = result * nsLayoutUtils::ChangeMatrixBasis(aProperties.mToPerspectiveOrigin - aProperties.mToTransformOrigin, perspective); 1.4586 + } 1.4587 + 1.4588 + gfxPoint3D rounded(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x), 1.4589 + hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y), 1.4590 + 0); 1.4591 + 1.4592 + if (frame && frame->Preserves3D()) { 1.4593 + // Include the transform set on our parent 1.4594 + NS_ASSERTION(frame->GetParent() && 1.4595 + frame->GetParent()->IsTransformed() && 1.4596 + frame->GetParent()->Preserves3DChildren(), 1.4597 + "Preserve3D mismatch!"); 1.4598 + FrameTransformProperties props(frame->GetParent(), 1.4599 + aAppUnitsPerPixel, 1.4600 + nullptr); 1.4601 + gfx3DMatrix parent = 1.4602 + GetResultingTransformMatrixInternal(props, 1.4603 + aOrigin - frame->GetPosition(), 1.4604 + aAppUnitsPerPixel, nullptr, aOutAncestor); 1.4605 + return nsLayoutUtils::ChangeMatrixBasis(rounded + aProperties.mToTransformOrigin, result) * parent; 1.4606 + } 1.4607 + 1.4608 + return nsLayoutUtils::ChangeMatrixBasis 1.4609 + (rounded + aProperties.mToTransformOrigin, result); 1.4610 +} 1.4611 + 1.4612 +bool 1.4613 +nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) 1.4614 +{ 1.4615 + if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_opacity)) { 1.4616 + return true; 1.4617 + } 1.4618 + 1.4619 + if (nsLayoutUtils::IsAnimationLoggingEnabled()) { 1.4620 + nsCString message; 1.4621 + message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for opacity animation"); 1.4622 + CommonElementAnimationData::LogAsyncAnimationFailure(message, 1.4623 + Frame()->GetContent()); 1.4624 + } 1.4625 + return false; 1.4626 +} 1.4627 + 1.4628 +bool 1.4629 +nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) 1.4630 +{ 1.4631 + return ShouldPrerenderTransformedContent(aBuilder, 1.4632 + Frame(), 1.4633 + nsLayoutUtils::IsAnimationLoggingEnabled()); 1.4634 +} 1.4635 + 1.4636 +/* static */ bool 1.4637 +nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder, 1.4638 + nsIFrame* aFrame, 1.4639 + bool aLogAnimations) 1.4640 +{ 1.4641 + // Elements whose transform has been modified recently, or which 1.4642 + // have a compositor-animated transform, can be prerendered. An element 1.4643 + // might have only just had its transform animated in which case 1.4644 + // the ActiveLayerManager may not have been notified yet. 1.4645 + if (!ActiveLayerTracker::IsStyleAnimated(aFrame, eCSSProperty_transform) && 1.4646 + (!aFrame->GetContent() || 1.4647 + !nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(), 1.4648 + eCSSProperty_transform))) { 1.4649 + if (aLogAnimations) { 1.4650 + nsCString message; 1.4651 + message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation"); 1.4652 + CommonElementAnimationData::LogAsyncAnimationFailure(message, 1.4653 + aFrame->GetContent()); 1.4654 + } 1.4655 + return false; 1.4656 + } 1.4657 + 1.4658 + nsSize refSize = aBuilder->RootReferenceFrame()->GetSize(); 1.4659 + // Only prerender if the transformed frame's size (in the reference 1.4660 + // frames coordinate space) is <= the reference frame size (~viewport), 1.4661 + // allowing a 1/8th fuzz factor for shadows, borders, etc. 1.4662 + refSize += nsSize(refSize.width / 8, refSize.height / 8); 1.4663 + nsRect frameRect = aFrame->GetVisualOverflowRectRelativeToSelf(); 1.4664 + 1.4665 + frameRect = 1.4666 + nsLayoutUtils::TransformFrameRectToAncestor(aFrame, frameRect, 1.4667 + aBuilder->RootReferenceFrame()); 1.4668 + 1.4669 + if (frameRect.Size() <= refSize) { 1.4670 + return true; 1.4671 + } 1.4672 + 1.4673 + if (aLogAnimations) { 1.4674 + nsCString message; 1.4675 + message.AppendLiteral("Performance warning: Async animation disabled because frame size ("); 1.4676 + message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameRect.width)); 1.4677 + message.AppendLiteral(", "); 1.4678 + message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameRect.height)); 1.4679 + message.AppendLiteral(") is bigger than the viewport ("); 1.4680 + message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.width)); 1.4681 + message.AppendLiteral(", "); 1.4682 + message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.height)); 1.4683 + message.AppendLiteral(")"); 1.4684 + CommonElementAnimationData::LogAsyncAnimationFailure(message, 1.4685 + aFrame->GetContent()); 1.4686 + } 1.4687 + return false; 1.4688 +} 1.4689 + 1.4690 +/* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */ 1.4691 +static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix) 1.4692 +{ 1.4693 + if (aMatrix.IsSingular()) { 1.4694 + return false; 1.4695 + } 1.4696 + if (aFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN && 1.4697 + aMatrix.IsBackfaceVisible()) { 1.4698 + return false; 1.4699 + } 1.4700 + return true; 1.4701 +} 1.4702 + 1.4703 +const gfx3DMatrix& 1.4704 +nsDisplayTransform::GetTransform() 1.4705 +{ 1.4706 + if (mTransform.IsIdentity()) { 1.4707 + float scale = mFrame->PresContext()->AppUnitsPerDevPixel(); 1.4708 + gfxPoint3D newOrigin = 1.4709 + gfxPoint3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale), 1.4710 + NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale), 1.4711 + 0.0f); 1.4712 + if (mTransformGetter) { 1.4713 + mTransform = mTransformGetter(mFrame, scale); 1.4714 + mTransform = nsLayoutUtils::ChangeMatrixBasis(newOrigin, mTransform); 1.4715 + } else { 1.4716 + mTransform = 1.4717 + GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale); 1.4718 + 1.4719 + /** 1.4720 + * Shift the coorindates to be relative to our reference frame instead of relative to this frame. 1.4721 + * When we have preserve-3d, our reference frame is already guaranteed to be an ancestor of the 1.4722 + * preserve-3d chain, so we only need to do this once. 1.4723 + */ 1.4724 + bool hasSVGTransforms = mFrame->IsSVGTransformed(); 1.4725 + gfxPoint3D rounded(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x), 1.4726 + hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y), 1.4727 + 0); 1.4728 + mTransform.Translate(rounded); 1.4729 + } 1.4730 + } 1.4731 + return mTransform; 1.4732 +} 1.4733 + 1.4734 +bool 1.4735 +nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) 1.4736 +{ 1.4737 + return ShouldPrerenderTransformedContent(aBuilder, mFrame, false); 1.4738 +} 1.4739 + 1.4740 +already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder, 1.4741 + LayerManager *aManager, 1.4742 + const ContainerLayerParameters& aContainerParameters) 1.4743 +{ 1.4744 + const gfx3DMatrix& newTransformMatrix = GetTransform(); 1.4745 + 1.4746 + if (mFrame->StyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN && 1.4747 + newTransformMatrix.IsBackfaceVisible()) { 1.4748 + return nullptr; 1.4749 + } 1.4750 + 1.4751 + uint32_t flags = ShouldPrerenderTransformedContent(aBuilder, mFrame, false) ? 1.4752 + FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0; 1.4753 + nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()-> 1.4754 + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetChildren(), 1.4755 + aContainerParameters, &newTransformMatrix, flags); 1.4756 + 1.4757 + if (!container) { 1.4758 + return nullptr; 1.4759 + } 1.4760 + 1.4761 + // Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags, 1.4762 + // so we never need to explicitely unset this flag. 1.4763 + if (mFrame->Preserves3D() || mFrame->Preserves3DChildren()) { 1.4764 + container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D); 1.4765 + } else { 1.4766 + container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_PRESERVE_3D); 1.4767 + } 1.4768 + 1.4769 + nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder, 1.4770 + this, mFrame, 1.4771 + eCSSProperty_transform); 1.4772 + if (ShouldPrerenderTransformedContent(aBuilder, mFrame, false)) { 1.4773 + container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(), 1.4774 + /*the value is irrelevant*/nullptr); 1.4775 + container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM); 1.4776 + } else { 1.4777 + container->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey()); 1.4778 + container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_MAY_CHANGE_TRANSFORM); 1.4779 + } 1.4780 + return container.forget(); 1.4781 +} 1.4782 + 1.4783 +nsDisplayItem::LayerState 1.4784 +nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder, 1.4785 + LayerManager* aManager, 1.4786 + const ContainerLayerParameters& aParameters) { 1.4787 + // If the transform is 3d, or the layer takes part in preserve-3d sorting 1.4788 + // then we *always* want this to be an active layer. 1.4789 + if (!GetTransform().Is2D() || mFrame->Preserves3D()) { 1.4790 + return LAYER_ACTIVE_FORCE; 1.4791 + } 1.4792 + // Here we check if the *post-transform* bounds of this item are big enough 1.4793 + // to justify an active layer. 1.4794 + if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_transform) && 1.4795 + !IsItemTooSmallForActiveLayer(this)) 1.4796 + return LAYER_ACTIVE; 1.4797 + if (mFrame->GetContent()) { 1.4798 + if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(), 1.4799 + eCSSProperty_transform)) { 1.4800 + return LAYER_ACTIVE; 1.4801 + } 1.4802 + } 1.4803 + 1.4804 + const nsStyleDisplay* disp = mFrame->StyleDisplay(); 1.4805 + if ((disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM)) { 1.4806 + return LAYER_ACTIVE; 1.4807 + } 1.4808 + 1.4809 + // Expect the child display items to have this frame as their animated 1.4810 + // geometry root (since it will be their reference frame). If they have a 1.4811 + // different animated geometry root, we'll make this an active layer so the 1.4812 + // animation can be accelerated. 1.4813 + return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, 1.4814 + *mStoredList.GetChildren(), Frame()); 1.4815 +} 1.4816 + 1.4817 +bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder, 1.4818 + nsRegion *aVisibleRegion, 1.4819 + const nsRect& aAllowVisibleRegionExpansion) 1.4820 +{ 1.4821 + /* As we do this, we need to be sure to 1.4822 + * untransform the visible rect, since we want everything that's painting to 1.4823 + * think that it's painting in its original rectangular coordinate space. 1.4824 + * If we can't untransform, take the entire overflow rect */ 1.4825 + nsRect untransformedVisibleRect; 1.4826 + if (ShouldPrerenderTransformedContent(aBuilder, mFrame) || 1.4827 + !UntransformVisibleRect(aBuilder, &untransformedVisibleRect)) 1.4828 + { 1.4829 + untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf(); 1.4830 + } 1.4831 + nsRegion untransformedVisible = untransformedVisibleRect; 1.4832 + // Call RecomputeVisiblity instead of ComputeVisibility since 1.4833 + // nsDisplayItem::ComputeVisibility should only be called from 1.4834 + // nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item) 1.4835 + mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible); 1.4836 + return true; 1.4837 +} 1.4838 + 1.4839 +#ifdef DEBUG_HIT 1.4840 +#include <time.h> 1.4841 +#endif 1.4842 + 1.4843 +/* HitTest does some fun stuff with matrix transforms to obtain the answer. */ 1.4844 +void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder, 1.4845 + const nsRect& aRect, 1.4846 + HitTestState *aState, 1.4847 + nsTArray<nsIFrame*> *aOutFrames) 1.4848 +{ 1.4849 + /* Here's how this works: 1.4850 + * 1. Get the matrix. If it's singular, abort (clearly we didn't hit 1.4851 + * anything). 1.4852 + * 2. Invert the matrix. 1.4853 + * 3. Use it to transform the rect into the correct space. 1.4854 + * 4. Pass that rect down through to the list's version of HitTest. 1.4855 + */ 1.4856 + // GetTransform always operates in dev pixels. 1.4857 + float factor = mFrame->PresContext()->AppUnitsPerDevPixel(); 1.4858 + gfx3DMatrix matrix = GetTransform(); 1.4859 + 1.4860 + if (!IsFrameVisible(mFrame, matrix)) { 1.4861 + return; 1.4862 + } 1.4863 + 1.4864 + /* We want to go from transformed-space to regular space. 1.4865 + * Thus we have to invert the matrix, which normally does 1.4866 + * the reverse operation (e.g. regular->transformed) 1.4867 + */ 1.4868 + bool snap; 1.4869 + nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap); 1.4870 + gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor), 1.4871 + NSAppUnitsToFloatPixels(childBounds.y, factor), 1.4872 + NSAppUnitsToFloatPixels(childBounds.width, factor), 1.4873 + NSAppUnitsToFloatPixels(childBounds.height, factor)); 1.4874 + 1.4875 + /* Now, apply the transform and pass it down the channel. */ 1.4876 + nsRect resultingRect; 1.4877 + if (aRect.width == 1 && aRect.height == 1) { 1.4878 + // Magic width/height indicating we're hit testing a point, not a rect 1.4879 + gfxPoint point; 1.4880 + if (!matrix.UntransformPoint(gfxPoint(NSAppUnitsToFloatPixels(aRect.x, factor), 1.4881 + NSAppUnitsToFloatPixels(aRect.y, factor)), 1.4882 + childGfxBounds, 1.4883 + &point)) { 1.4884 + return; 1.4885 + } 1.4886 + 1.4887 + resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point.x), factor), 1.4888 + NSFloatPixelsToAppUnits(float(point.y), factor), 1.4889 + 1, 1); 1.4890 + 1.4891 + } else { 1.4892 + gfxRect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor), 1.4893 + NSAppUnitsToFloatPixels(aRect.y, factor), 1.4894 + NSAppUnitsToFloatPixels(aRect.width, factor), 1.4895 + NSAppUnitsToFloatPixels(aRect.height, factor)); 1.4896 + 1.4897 + gfxRect rect = matrix.UntransformBounds(originalRect, childGfxBounds); 1.4898 + 1.4899 + resultingRect = nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor), 1.4900 + NSFloatPixelsToAppUnits(float(rect.Y()), factor), 1.4901 + NSFloatPixelsToAppUnits(float(rect.Width()), factor), 1.4902 + NSFloatPixelsToAppUnits(float(rect.Height()), factor)); 1.4903 + } 1.4904 + 1.4905 + if (resultingRect.IsEmpty()) { 1.4906 + return; 1.4907 + } 1.4908 + 1.4909 + 1.4910 +#ifdef DEBUG_HIT 1.4911 + printf("Frame: %p\n", dynamic_cast<void *>(mFrame)); 1.4912 + printf(" Untransformed point: (%f, %f)\n", resultingRect.X(), resultingRect.Y()); 1.4913 + uint32_t originalFrameCount = aOutFrames.Length(); 1.4914 +#endif 1.4915 + 1.4916 + mStoredList.HitTest(aBuilder, resultingRect, aState, aOutFrames); 1.4917 + 1.4918 +#ifdef DEBUG_HIT 1.4919 + if (originalFrameCount != aOutFrames.Length()) 1.4920 + printf(" Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()), 1.4921 + dynamic_cast<void *>(aOutFrames.ElementAt(0))); 1.4922 + printf("=== end of hit test ===\n"); 1.4923 +#endif 1.4924 + 1.4925 +} 1.4926 + 1.4927 +float 1.4928 +nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint) 1.4929 +{ 1.4930 + // GetTransform always operates in dev pixels. 1.4931 + float factor = mFrame->PresContext()->AppUnitsPerDevPixel(); 1.4932 + gfx3DMatrix matrix = GetTransform(); 1.4933 + 1.4934 + NS_ASSERTION(IsFrameVisible(mFrame, matrix), "We can't have hit a frame that isn't visible!"); 1.4935 + 1.4936 + bool snap; 1.4937 + nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap); 1.4938 + gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor), 1.4939 + NSAppUnitsToFloatPixels(childBounds.y, factor), 1.4940 + NSAppUnitsToFloatPixels(childBounds.width, factor), 1.4941 + NSAppUnitsToFloatPixels(childBounds.height, factor)); 1.4942 + 1.4943 + gfxPoint point; 1.4944 + DebugOnly<bool> result = matrix.UntransformPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor), 1.4945 + NSAppUnitsToFloatPixels(aPoint.y, factor)), 1.4946 + childGfxBounds, 1.4947 + &point); 1.4948 + NS_ASSERTION(result, "Why are we trying to get the depth for a point we didn't hit?"); 1.4949 + 1.4950 + gfxPoint3D transformed = matrix.Transform3D(gfxPoint3D(point.x, point.y, 0)); 1.4951 + return transformed.z; 1.4952 +} 1.4953 + 1.4954 +/* The bounding rectangle for the object is the overflow rectangle translated 1.4955 + * by the reference point. 1.4956 + */ 1.4957 +nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder, bool* aSnap) 1.4958 +{ 1.4959 + nsRect untransformedBounds = 1.4960 + ShouldPrerenderTransformedContent(aBuilder, mFrame) ? 1.4961 + mFrame->GetVisualOverflowRectRelativeToSelf() : 1.4962 + mStoredList.GetBounds(aBuilder, aSnap); 1.4963 + *aSnap = false; 1.4964 + // GetTransform always operates in dev pixels. 1.4965 + float factor = mFrame->PresContext()->AppUnitsPerDevPixel(); 1.4966 + return nsLayoutUtils::MatrixTransformRect(untransformedBounds, 1.4967 + GetTransform(), 1.4968 + factor); 1.4969 +} 1.4970 + 1.4971 +/* The transform is opaque iff the transform consists solely of scales and 1.4972 + * translations and if the underlying content is opaque. Thus if the transform 1.4973 + * is of the form 1.4974 + * 1.4975 + * |a c e| 1.4976 + * |b d f| 1.4977 + * |0 0 1| 1.4978 + * 1.4979 + * We need b and c to be zero. 1.4980 + * 1.4981 + * We also need to check whether the underlying opaque content completely fills 1.4982 + * our visible rect. We use UntransformRect which expands to the axis-aligned 1.4983 + * bounding rect, but that's OK since if 1.4984 + * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it 1.4985 + * certainly contains the actual (non-axis-aligned) untransformed rect. 1.4986 + */ 1.4987 +nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder, 1.4988 + bool* aSnap) 1.4989 +{ 1.4990 + *aSnap = false; 1.4991 + nsRect untransformedVisible; 1.4992 + // If we're going to prerender all our content, pretend like we 1.4993 + // don't have opqaue content so that everything under us is rendered 1.4994 + // as well. That will increase graphics memory usage if our frame 1.4995 + // covers the entire window, but it allows our transform to be 1.4996 + // updated extremely cheaply, without invalidating any other 1.4997 + // content. 1.4998 + if (ShouldPrerenderTransformedContent(aBuilder, mFrame) || 1.4999 + !UntransformVisibleRect(aBuilder, &untransformedVisible)) { 1.5000 + return nsRegion(); 1.5001 + } 1.5002 + 1.5003 + const gfx3DMatrix& matrix = GetTransform(); 1.5004 + 1.5005 + nsRegion result; 1.5006 + gfxMatrix matrix2d; 1.5007 + bool tmpSnap; 1.5008 + if (matrix.Is2D(&matrix2d) && 1.5009 + matrix2d.PreservesAxisAlignedRectangles() && 1.5010 + mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) { 1.5011 + result = mVisibleRect; 1.5012 + } 1.5013 + return result; 1.5014 +} 1.5015 + 1.5016 +/* The transform is uniform if it fills the entire bounding rect and the 1.5017 + * wrapped list is uniform. See GetOpaqueRegion for discussion of why this 1.5018 + * works. 1.5019 + */ 1.5020 +bool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor) 1.5021 +{ 1.5022 + nsRect untransformedVisible; 1.5023 + if (!UntransformVisibleRect(aBuilder, &untransformedVisible)) { 1.5024 + return false; 1.5025 + } 1.5026 + const gfx3DMatrix& matrix = GetTransform(); 1.5027 + 1.5028 + gfxMatrix matrix2d; 1.5029 + return matrix.Is2D(&matrix2d) && 1.5030 + matrix2d.PreservesAxisAlignedRectangles() && 1.5031 + mStoredList.GetVisibleRect().Contains(untransformedVisible) && 1.5032 + mStoredList.IsUniform(aBuilder, aColor); 1.5033 +} 1.5034 + 1.5035 +/* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that 1.5036 + * share the same underlying content. Otherwise, doing so results in graphical 1.5037 + * glitches. 1.5038 + */ 1.5039 +#ifndef UNIFIED_CONTINUATIONS 1.5040 + 1.5041 +bool 1.5042 +nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder, 1.5043 + nsDisplayItem *aItem) 1.5044 +{ 1.5045 + return false; 1.5046 +} 1.5047 + 1.5048 +#else 1.5049 + 1.5050 +bool 1.5051 +nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder, 1.5052 + nsDisplayItem *aItem) 1.5053 +{ 1.5054 + NS_PRECONDITION(aItem, "Why did you try merging with a null item?"); 1.5055 + NS_PRECONDITION(aBuilder, "Why did you try merging with a null builder?"); 1.5056 + 1.5057 + /* Make sure that we're dealing with two transforms. */ 1.5058 + if (aItem->GetType() != TYPE_TRANSFORM) 1.5059 + return false; 1.5060 + 1.5061 + /* Check to see that both frames are part of the same content. */ 1.5062 + if (aItem->Frame()->GetContent() != mFrame->GetContent()) 1.5063 + return false; 1.5064 + 1.5065 + if (aItem->GetClip() != GetClip()) 1.5066 + return false; 1.5067 + 1.5068 + /* Now, move everything over to this frame and signal that 1.5069 + * we merged things! 1.5070 + */ 1.5071 + mStoredList.MergeFrom(&static_cast<nsDisplayTransform*>(aItem)->mStoredList); 1.5072 + return true; 1.5073 +} 1.5074 + 1.5075 +#endif 1.5076 + 1.5077 +/* TransformRect takes in as parameters a rectangle (in app space) and returns 1.5078 + * the smallest rectangle (in app space) containing the transformed image of 1.5079 + * that rectangle. That is, it takes the four corners of the rectangle, 1.5080 + * transforms them according to the matrix associated with the specified frame, 1.5081 + * then returns the smallest rectangle containing the four transformed points. 1.5082 + * 1.5083 + * @param aUntransformedBounds The rectangle (in app units) to transform. 1.5084 + * @param aFrame The frame whose transformation should be applied. 1.5085 + * @param aOrigin The delta from the frame origin to the coordinate space origin 1.5086 + * @param aBoundsOverride (optional) Force the frame bounds to be the 1.5087 + * specified bounds. 1.5088 + * @return The smallest rectangle containing the image of the transformed 1.5089 + * rectangle. 1.5090 + */ 1.5091 +nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds, 1.5092 + const nsIFrame* aFrame, 1.5093 + const nsPoint &aOrigin, 1.5094 + const nsRect* aBoundsOverride) 1.5095 +{ 1.5096 + NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!"); 1.5097 + 1.5098 + float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); 1.5099 + return nsLayoutUtils::MatrixTransformRect 1.5100 + (aUntransformedBounds, 1.5101 + GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride), 1.5102 + factor); 1.5103 +} 1.5104 + 1.5105 +nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds, 1.5106 + const nsIFrame* aFrame, 1.5107 + const nsPoint &aOrigin, 1.5108 + const nsRect* aBoundsOverride) 1.5109 +{ 1.5110 + NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!"); 1.5111 + 1.5112 + float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); 1.5113 + return nsLayoutUtils::MatrixTransformRectOut 1.5114 + (aUntransformedBounds, 1.5115 + GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride), 1.5116 + factor); 1.5117 +} 1.5118 + 1.5119 +bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds, 1.5120 + const nsRect &aChildBounds, 1.5121 + const nsIFrame* aFrame, 1.5122 + const nsPoint &aOrigin, 1.5123 + nsRect *aOutRect) 1.5124 +{ 1.5125 + NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!"); 1.5126 + 1.5127 + float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); 1.5128 + 1.5129 + gfx3DMatrix transform = GetResultingTransformMatrix(aFrame, aOrigin, factor, nullptr); 1.5130 + if (transform.IsSingular()) { 1.5131 + return false; 1.5132 + } 1.5133 + 1.5134 + gfxRect result(NSAppUnitsToFloatPixels(aTransformedBounds.x, factor), 1.5135 + NSAppUnitsToFloatPixels(aTransformedBounds.y, factor), 1.5136 + NSAppUnitsToFloatPixels(aTransformedBounds.width, factor), 1.5137 + NSAppUnitsToFloatPixels(aTransformedBounds.height, factor)); 1.5138 + 1.5139 + gfxRect childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds.x, factor), 1.5140 + NSAppUnitsToFloatPixels(aChildBounds.y, factor), 1.5141 + NSAppUnitsToFloatPixels(aChildBounds.width, factor), 1.5142 + NSAppUnitsToFloatPixels(aChildBounds.height, factor)); 1.5143 + 1.5144 + result = transform.UntransformBounds(result, childGfxBounds); 1.5145 + *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor); 1.5146 + return true; 1.5147 +} 1.5148 + 1.5149 +bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder* aBuilder, 1.5150 + nsRect *aOutRect) 1.5151 +{ 1.5152 + const gfx3DMatrix& matrix = GetTransform(); 1.5153 + if (matrix.IsSingular()) 1.5154 + return false; 1.5155 + 1.5156 + // GetTransform always operates in dev pixels. 1.5157 + float factor = mFrame->PresContext()->AppUnitsPerDevPixel(); 1.5158 + gfxRect result(NSAppUnitsToFloatPixels(mVisibleRect.x, factor), 1.5159 + NSAppUnitsToFloatPixels(mVisibleRect.y, factor), 1.5160 + NSAppUnitsToFloatPixels(mVisibleRect.width, factor), 1.5161 + NSAppUnitsToFloatPixels(mVisibleRect.height, factor)); 1.5162 + 1.5163 + bool snap; 1.5164 + nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap); 1.5165 + gfxRect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor), 1.5166 + NSAppUnitsToFloatPixels(childBounds.y, factor), 1.5167 + NSAppUnitsToFloatPixels(childBounds.width, factor), 1.5168 + NSAppUnitsToFloatPixels(childBounds.height, factor)); 1.5169 + 1.5170 + /* We want to untransform the matrix, so invert the transformation first! */ 1.5171 + result = matrix.UntransformBounds(result, childGfxBounds); 1.5172 + 1.5173 + *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor); 1.5174 + 1.5175 + return true; 1.5176 +} 1.5177 + 1.5178 +nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder, 1.5179 + nsIFrame* aFrame, nsDisplayList* aList) 1.5180 + : nsDisplayWrapList(aBuilder, aFrame, aList), 1.5181 + mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf()) 1.5182 +{ 1.5183 + MOZ_COUNT_CTOR(nsDisplaySVGEffects); 1.5184 +} 1.5185 + 1.5186 +#ifdef NS_BUILD_REFCNT_LOGGING 1.5187 +nsDisplaySVGEffects::~nsDisplaySVGEffects() 1.5188 +{ 1.5189 + MOZ_COUNT_DTOR(nsDisplaySVGEffects); 1.5190 +} 1.5191 +#endif 1.5192 + 1.5193 +nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, 1.5194 + bool* aSnap) 1.5195 +{ 1.5196 + *aSnap = false; 1.5197 + return nsRegion(); 1.5198 +} 1.5199 + 1.5200 +void 1.5201 +nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.5202 + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) 1.5203 +{ 1.5204 + nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2); 1.5205 + if (nsSVGIntegrationUtils::HitTestFrameForEffects(mFrame, 1.5206 + rectCenter - ToReferenceFrame())) { 1.5207 + mList.HitTest(aBuilder, aRect, aState, aOutFrames); 1.5208 + } 1.5209 +} 1.5210 + 1.5211 +void 1.5212 +nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder* aBuilder, 1.5213 + nsRenderingContext* aCtx, 1.5214 + LayerManager* aManager) 1.5215 +{ 1.5216 + nsSVGIntegrationUtils::PaintFramesWithEffects(aCtx, mFrame, 1.5217 + mVisibleRect, 1.5218 + aBuilder, aManager); 1.5219 +} 1.5220 + 1.5221 +LayerState 1.5222 +nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder* aBuilder, 1.5223 + LayerManager* aManager, 1.5224 + const ContainerLayerParameters& aParameters) 1.5225 +{ 1.5226 + return LAYER_SVG_EFFECTS; 1.5227 +} 1.5228 + 1.5229 +already_AddRefed<Layer> 1.5230 +nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder* aBuilder, 1.5231 + LayerManager* aManager, 1.5232 + const ContainerLayerParameters& aContainerParameters) 1.5233 +{ 1.5234 + const nsIContent* content = mFrame->GetContent(); 1.5235 + bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT); 1.5236 + if (hasSVGLayout) { 1.5237 + nsISVGChildFrame *svgChildFrame = do_QueryFrame(mFrame); 1.5238 + if (!svgChildFrame || !mFrame->GetContent()->IsSVG()) { 1.5239 + NS_ASSERTION(false, "why?"); 1.5240 + return nullptr; 1.5241 + } 1.5242 + if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) { 1.5243 + return nullptr; // The SVG spec says not to draw filters for this 1.5244 + } 1.5245 + } 1.5246 + 1.5247 + float opacity = mFrame->StyleDisplay()->mOpacity; 1.5248 + if (opacity == 0.0f) 1.5249 + return nullptr; 1.5250 + 1.5251 + nsIFrame* firstFrame = 1.5252 + nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame); 1.5253 + nsSVGEffects::EffectProperties effectProperties = 1.5254 + nsSVGEffects::GetEffectProperties(firstFrame); 1.5255 + 1.5256 + bool isOK = effectProperties.HasNoFilterOrHasValidFilter(); 1.5257 + effectProperties.GetClipPathFrame(&isOK); 1.5258 + effectProperties.GetMaskFrame(&isOK); 1.5259 + 1.5260 + if (!isOK) { 1.5261 + return nullptr; 1.5262 + } 1.5263 + 1.5264 + ContainerLayerParameters newContainerParameters = aContainerParameters; 1.5265 + if (effectProperties.HasValidFilter()) { 1.5266 + newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; 1.5267 + } 1.5268 + 1.5269 + nsRefPtr<ContainerLayer> container = aManager->GetLayerBuilder()-> 1.5270 + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, 1.5271 + newContainerParameters, nullptr); 1.5272 + 1.5273 + return container.forget(); 1.5274 +} 1.5275 + 1.5276 +bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder, 1.5277 + nsRegion* aVisibleRegion, 1.5278 + const nsRect& aAllowVisibleRegionExpansion) { 1.5279 + nsPoint offset = ToReferenceFrame(); 1.5280 + nsRect dirtyRect = 1.5281 + nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame, 1.5282 + mVisibleRect - offset) + 1.5283 + offset; 1.5284 + 1.5285 + // Our children may be made translucent or arbitrarily deformed so we should 1.5286 + // not allow them to subtract area from aVisibleRegion. 1.5287 + nsRegion childrenVisible(dirtyRect); 1.5288 + nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder)); 1.5289 + mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect()); 1.5290 + return true; 1.5291 +} 1.5292 + 1.5293 +bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) 1.5294 +{ 1.5295 + if (aItem->GetType() != TYPE_SVG_EFFECTS) 1.5296 + return false; 1.5297 + // items for the same content element should be merged into a single 1.5298 + // compositing group 1.5299 + // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects 1.5300 + if (aItem->Frame()->GetContent() != mFrame->GetContent()) 1.5301 + return false; 1.5302 + if (aItem->GetClip() != GetClip()) 1.5303 + return false; 1.5304 + nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem); 1.5305 + MergeFromTrackingMergedFrames(other); 1.5306 + mEffectsBounds.UnionRect(mEffectsBounds, 1.5307 + other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame)); 1.5308 + return true; 1.5309 +} 1.5310 + 1.5311 +#ifdef MOZ_DUMP_PAINTING 1.5312 +void 1.5313 +nsDisplaySVGEffects::PrintEffects(nsACString& aTo) 1.5314 +{ 1.5315 + nsIFrame* firstFrame = 1.5316 + nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame); 1.5317 + nsSVGEffects::EffectProperties effectProperties = 1.5318 + nsSVGEffects::GetEffectProperties(firstFrame); 1.5319 + bool isOK = true; 1.5320 + nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK); 1.5321 + bool first = true; 1.5322 + aTo += " effects=("; 1.5323 + if (mFrame->StyleDisplay()->mOpacity != 1.0f) { 1.5324 + first = false; 1.5325 + aTo += nsPrintfCString("opacity(%f)", mFrame->StyleDisplay()->mOpacity); 1.5326 + } 1.5327 + if (clipPathFrame) { 1.5328 + if (!first) { 1.5329 + aTo += ", "; 1.5330 + } 1.5331 + aTo += nsPrintfCString("clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial"); 1.5332 + first = false; 1.5333 + } 1.5334 + if (effectProperties.HasValidFilter()) { 1.5335 + if (!first) { 1.5336 + aTo += ", "; 1.5337 + } 1.5338 + aTo += "filter"; 1.5339 + first = false; 1.5340 + } 1.5341 + if (effectProperties.GetMaskFrame(&isOK)) { 1.5342 + if (!first) { 1.5343 + aTo += ", "; 1.5344 + } 1.5345 + aTo += "mask"; 1.5346 + } 1.5347 + aTo += ")"; 1.5348 +} 1.5349 +#endif 1.5350 +