2006-01-26 05:29:17 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
2006-04-18 03:16:46 +04:00
|
|
|
* vim: set ts=2 sw=2 et tw=78:
|
2012-05-21 15:12:37 +04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2006-01-26 05:29:17 +03:00
|
|
|
*/
|
|
|
|
|
2006-03-30 09:56:38 +04:00
|
|
|
/*
|
|
|
|
* structures that represent things to be painted (ordered in z-order),
|
|
|
|
* used during painting and hit testing
|
|
|
|
*/
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
#include "nsDisplayList.h"
|
|
|
|
|
2014-08-06 09:19:27 +04:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <algorithm>
|
2016-08-12 07:51:10 +03:00
|
|
|
#include <limits>
|
2014-08-06 09:19:27 +04:00
|
|
|
|
2014-10-19 16:22:22 +04:00
|
|
|
#include "gfxUtils.h"
|
2014-08-06 09:19:27 +04:00
|
|
|
#include "mozilla/dom/TabChild.h"
|
2016-09-04 10:34:21 +03:00
|
|
|
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
2014-10-19 16:22:22 +04:00
|
|
|
#include "mozilla/gfx/2D.h"
|
2014-08-06 09:19:27 +04:00
|
|
|
#include "mozilla/layers/PLayerTransaction.h"
|
2006-01-26 05:29:17 +03:00
|
|
|
#include "nsCSSRendering.h"
|
2011-04-08 05:04:40 +04:00
|
|
|
#include "nsRenderingContext.h"
|
2006-01-26 05:29:17 +03:00
|
|
|
#include "nsISelectionController.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsRegion.h"
|
2008-07-17 10:30:25 +04:00
|
|
|
#include "nsStyleStructInlines.h"
|
2008-09-13 13:42:11 +04:00
|
|
|
#include "nsStyleTransformMatrix.h"
|
|
|
|
#include "gfxMatrix.h"
|
2014-06-25 19:12:32 +04:00
|
|
|
#include "gfxPrefs.h"
|
2008-09-11 04:24:16 +04:00
|
|
|
#include "nsSVGIntegrationUtils.h"
|
2014-08-30 20:22:31 +04:00
|
|
|
#include "nsSVGUtils.h"
|
2009-07-22 04:44:57 +04:00
|
|
|
#include "nsLayoutUtils.h"
|
2010-07-16 01:08:12 +04:00
|
|
|
#include "nsIScrollableFrame.h"
|
2014-02-04 10:14:07 +04:00
|
|
|
#include "nsIFrameInlines.h"
|
2010-07-24 13:35:29 +04:00
|
|
|
#include "nsThemeConstants.h"
|
2016-11-24 08:11:30 +03:00
|
|
|
#include "BorderConsts.h"
|
2012-08-29 09:47:18 +04:00
|
|
|
#include "LayerTreeInvalidation.h"
|
2006-02-16 02:21:12 +03:00
|
|
|
|
2009-04-08 19:19:51 +04:00
|
|
|
#include "imgIContainer.h"
|
2010-03-01 10:56:19 +03:00
|
|
|
#include "BasicLayers.h"
|
2010-11-30 17:59:46 +03:00
|
|
|
#include "nsBoxFrame.h"
|
2013-08-13 11:56:57 +04:00
|
|
|
#include "nsSubDocumentFrame.h"
|
2011-11-17 07:44:16 +04:00
|
|
|
#include "nsSVGEffects.h"
|
2012-07-20 22:12:29 +04:00
|
|
|
#include "nsSVGElement.h"
|
2011-11-17 07:44:16 +04:00
|
|
|
#include "nsSVGClipPathFrame.h"
|
2013-03-18 18:25:50 +04:00
|
|
|
#include "GeckoProfiler.h"
|
2013-01-05 07:12:24 +04:00
|
|
|
#include "nsViewManager.h"
|
2012-08-19 23:33:25 +04:00
|
|
|
#include "ImageLayers.h"
|
|
|
|
#include "ImageContainer.h"
|
2012-12-13 05:15:55 +04:00
|
|
|
#include "nsCanvasFrame.h"
|
2013-09-13 05:56:57 +04:00
|
|
|
#include "StickyScrollContainer.h"
|
2016-03-04 11:54:25 +03:00
|
|
|
#include "mozilla/AnimationPerformanceWarning.h"
|
2015-12-04 02:32:53 +03:00
|
|
|
#include "mozilla/AnimationUtils.h"
|
2015-12-04 02:34:17 +03:00
|
|
|
#include "mozilla/EffectCompositor.h"
|
2016-10-05 08:42:56 +03:00
|
|
|
#include "mozilla/EffectSet.h"
|
2014-04-03 08:18:36 +04:00
|
|
|
#include "mozilla/EventStates.h"
|
2013-08-30 21:22:33 +04:00
|
|
|
#include "mozilla/LookAndFeel.h"
|
2016-08-17 22:28:45 +03:00
|
|
|
#include "mozilla/OperatorNewExtensions.h"
|
2015-04-21 04:22:09 +03:00
|
|
|
#include "mozilla/PendingAnimationTracker.h"
|
2013-09-16 05:06:52 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2016-10-12 10:58:04 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
2014-08-25 19:09:39 +04:00
|
|
|
#include "mozilla/UniquePtr.h"
|
2016-08-23 07:09:32 +03:00
|
|
|
#include "mozilla/Unused.h"
|
2016-11-30 06:14:29 +03:00
|
|
|
#include "mozilla/ViewportFrame.h"
|
2016-10-12 10:58:04 +03:00
|
|
|
#include "mozilla/gfx/gfxVars.h"
|
2013-09-04 15:30:57 +04:00
|
|
|
#include "ActiveLayerTracker.h"
|
2013-09-23 23:09:48 +04:00
|
|
|
#include "nsContentUtils.h"
|
2014-01-27 02:07:08 +04:00
|
|
|
#include "nsPrintfCString.h"
|
2014-04-03 02:46:38 +04:00
|
|
|
#include "UnitTransforms.h"
|
2014-05-22 06:36:26 +04:00
|
|
|
#include "LayersLogging.h"
|
2014-08-06 09:19:25 +04:00
|
|
|
#include "FrameLayerBuilder.h"
|
2015-03-07 01:26:59 +03:00
|
|
|
#include "mozilla/EventStateManager.h"
|
2016-02-24 10:01:12 +03:00
|
|
|
#include "mozilla/RestyleManager.h"
|
2014-08-06 09:19:27 +04:00
|
|
|
#include "nsCaret.h"
|
|
|
|
#include "nsISelection.h"
|
2015-05-27 11:37:44 +03:00
|
|
|
#include "nsDOMTokenList.h"
|
2015-06-23 04:48:18 +03:00
|
|
|
#include "mozilla/RuleNodeCacheConditions.h"
|
2015-06-30 21:49:03 +03:00
|
|
|
#include "nsCSSProps.h"
|
2015-10-17 09:50:09 +03:00
|
|
|
#include "nsPluginFrame.h"
|
2015-12-22 18:54:19 +03:00
|
|
|
#include "DisplayItemScrollClip.h"
|
2016-10-11 08:12:00 +03:00
|
|
|
#include "nsSVGMaskFrame.h"
|
2012-04-12 04:17:44 +04:00
|
|
|
|
2014-12-22 03:35:41 +03:00
|
|
|
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
|
|
|
|
// GetTickCount().
|
|
|
|
#ifdef GetCurrentTime
|
|
|
|
#undef GetCurrentTime
|
|
|
|
#endif
|
|
|
|
|
2010-05-21 07:20:48 +04:00
|
|
|
using namespace mozilla;
|
2010-03-01 10:56:19 +03:00
|
|
|
using namespace mozilla::layers;
|
2012-12-12 02:49:57 +04:00
|
|
|
using namespace mozilla::dom;
|
2014-05-29 01:43:39 +04:00
|
|
|
using namespace mozilla::layout;
|
2014-08-01 16:31:48 +04:00
|
|
|
using namespace mozilla::gfx;
|
|
|
|
|
2011-01-13 20:45:14 +03:00
|
|
|
typedef FrameMetrics::ViewID ViewID;
|
2015-04-28 21:55:42 +03:00
|
|
|
typedef nsStyleTransformMatrix::TransformReferenceBox TransformReferenceBox;
|
2009-04-08 19:19:51 +04:00
|
|
|
|
2014-07-23 01:01:50 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
static bool
|
|
|
|
SpammyLayoutWarningsEnabled()
|
|
|
|
{
|
|
|
|
static bool sValue = false;
|
|
|
|
static bool sValueInitialized = false;
|
|
|
|
|
|
|
|
if (!sValueInitialized) {
|
|
|
|
Preferences::GetBool("layout.spammy_warnings.enabled", &sValue);
|
|
|
|
sValueInitialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sValue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-11-25 01:53:51 +03:00
|
|
|
void*
|
2016-08-17 22:28:45 +03:00
|
|
|
AnimatedGeometryRoot::operator new(size_t aSize, nsDisplayListBuilder* aBuilder)
|
2015-11-25 01:53:51 +03:00
|
|
|
{
|
|
|
|
return aBuilder->Allocate(aSize);
|
|
|
|
}
|
|
|
|
|
2015-04-23 19:18:12 +03:00
|
|
|
static inline CSSAngle
|
|
|
|
MakeCSSAngle(const nsCSSValue& aValue)
|
|
|
|
{
|
|
|
|
return CSSAngle(aValue.GetAngleValue(), aValue.GetUnit());
|
|
|
|
}
|
|
|
|
|
2012-07-31 21:28:21 +04:00
|
|
|
static void AddTransformFunctions(nsCSSValueList* aList,
|
|
|
|
nsStyleContext* aContext,
|
|
|
|
nsPresContext* aPresContext,
|
2015-04-28 21:55:42 +03:00
|
|
|
TransformReferenceBox& aRefBox,
|
2012-07-31 21:28:21 +04:00
|
|
|
InfallibleTArray<TransformFunction>& aFunctions)
|
|
|
|
{
|
|
|
|
if (aList->mValue.GetUnit() == eCSSUnit_None) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) {
|
|
|
|
const nsCSSValue& currElem = curr->mValue;
|
|
|
|
NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
|
|
|
|
"Stream should consist solely of functions!");
|
|
|
|
nsCSSValue::Array* array = currElem.GetArrayValue();
|
2015-06-23 04:48:18 +03:00
|
|
|
RuleNodeCacheConditions conditions;
|
2012-07-31 21:28:21 +04:00
|
|
|
switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
|
|
|
|
case eCSSKeyword_rotatex:
|
|
|
|
{
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle theta = MakeCSSAngle(array->Item(1));
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(RotationX(theta));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_rotatey:
|
|
|
|
{
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle theta = MakeCSSAngle(array->Item(1));
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(RotationY(theta));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_rotatez:
|
|
|
|
{
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle theta = MakeCSSAngle(array->Item(1));
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(RotationZ(theta));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_rotate:
|
|
|
|
{
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle theta = MakeCSSAngle(array->Item(1));
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(Rotation(theta));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_rotate3d:
|
|
|
|
{
|
|
|
|
double x = array->Item(1).GetFloatValue();
|
|
|
|
double y = array->Item(2).GetFloatValue();
|
|
|
|
double z = array->Item(3).GetFloatValue();
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle theta = MakeCSSAngle(array->Item(4));
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(Rotation3D(x, y, z, theta));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_scalex:
|
|
|
|
{
|
|
|
|
double x = array->Item(1).GetFloatValue();
|
|
|
|
aFunctions.AppendElement(Scale(x, 1, 1));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_scaley:
|
|
|
|
{
|
|
|
|
double y = array->Item(1).GetFloatValue();
|
|
|
|
aFunctions.AppendElement(Scale(1, y, 1));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_scalez:
|
|
|
|
{
|
|
|
|
double z = array->Item(1).GetFloatValue();
|
|
|
|
aFunctions.AppendElement(Scale(1, 1, z));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_scale:
|
|
|
|
{
|
|
|
|
double x = array->Item(1).GetFloatValue();
|
|
|
|
// scale(x) is shorthand for scale(x, x);
|
|
|
|
double y = array->Count() == 2 ? x : array->Item(2).GetFloatValue();
|
|
|
|
aFunctions.AppendElement(Scale(x, y, 1));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_scale3d:
|
|
|
|
{
|
|
|
|
double x = array->Item(1).GetFloatValue();
|
|
|
|
double y = array->Item(2).GetFloatValue();
|
|
|
|
double z = array->Item(3).GetFloatValue();
|
|
|
|
aFunctions.AppendElement(Scale(x, y, z));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_translatex:
|
|
|
|
{
|
|
|
|
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(1), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
&aRefBox, &TransformReferenceBox::Width);
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(Translation(x, 0, 0));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_translatey:
|
|
|
|
{
|
|
|
|
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(1), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
&aRefBox, &TransformReferenceBox::Height);
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(Translation(0, y, 0));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_translatez:
|
|
|
|
{
|
|
|
|
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(1), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
nullptr);
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(Translation(0, 0, z));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_translate:
|
|
|
|
{
|
|
|
|
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(1), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
&aRefBox, &TransformReferenceBox::Width);
|
2012-07-31 21:28:21 +04:00
|
|
|
// translate(x) is shorthand for translate(x, 0)
|
|
|
|
double y = 0;
|
|
|
|
if (array->Count() == 3) {
|
|
|
|
y = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(2), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
&aRefBox, &TransformReferenceBox::Height);
|
2012-07-31 21:28:21 +04:00
|
|
|
}
|
|
|
|
aFunctions.AppendElement(Translation(x, y, 0));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_translate3d:
|
|
|
|
{
|
|
|
|
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(1), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
&aRefBox, &TransformReferenceBox::Width);
|
2012-07-31 21:28:21 +04:00
|
|
|
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(2), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
&aRefBox, &TransformReferenceBox::Height);
|
2012-07-31 21:28:21 +04:00
|
|
|
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
2015-06-23 04:48:18 +03:00
|
|
|
array->Item(3), aContext, aPresContext, conditions,
|
2015-04-28 21:55:42 +03:00
|
|
|
nullptr);
|
2012-07-31 21:28:21 +04:00
|
|
|
|
|
|
|
aFunctions.AppendElement(Translation(x, y, z));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_skewx:
|
|
|
|
{
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle x = MakeCSSAngle(array->Item(1));
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(SkewX(x));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_skewy:
|
|
|
|
{
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle y = MakeCSSAngle(array->Item(1));
|
2012-07-31 21:28:21 +04:00
|
|
|
aFunctions.AppendElement(SkewY(y));
|
|
|
|
break;
|
|
|
|
}
|
2013-05-21 14:22:44 +04:00
|
|
|
case eCSSKeyword_skew:
|
|
|
|
{
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle x = MakeCSSAngle(array->Item(1));
|
2013-05-21 14:22:44 +04:00
|
|
|
// skew(x) is shorthand for skew(x, 0)
|
2015-04-23 19:18:12 +03:00
|
|
|
CSSAngle y(0.0f, eCSSUnit_Degree);
|
2013-05-21 14:22:44 +04:00
|
|
|
if (array->Count() == 3) {
|
2015-04-23 19:18:12 +03:00
|
|
|
y = MakeCSSAngle(array->Item(2));
|
2013-05-21 14:22:44 +04:00
|
|
|
}
|
|
|
|
aFunctions.AppendElement(Skew(x, y));
|
|
|
|
break;
|
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
case eCSSKeyword_matrix:
|
|
|
|
{
|
2014-01-27 19:28:33 +04:00
|
|
|
gfx::Matrix4x4 matrix;
|
2012-07-31 21:28:21 +04:00
|
|
|
matrix._11 = array->Item(1).GetFloatValue();
|
|
|
|
matrix._12 = array->Item(2).GetFloatValue();
|
|
|
|
matrix._13 = 0;
|
2013-06-03 00:35:17 +04:00
|
|
|
matrix._14 = 0;
|
2013-05-31 22:06:56 +04:00
|
|
|
matrix._21 = array->Item(3).GetFloatValue();
|
|
|
|
matrix._22 = array->Item(4).GetFloatValue();
|
2012-07-31 21:28:21 +04:00
|
|
|
matrix._23 = 0;
|
2013-06-03 00:35:17 +04:00
|
|
|
matrix._24 = 0;
|
2012-07-31 21:28:21 +04:00
|
|
|
matrix._31 = 0;
|
|
|
|
matrix._32 = 0;
|
|
|
|
matrix._33 = 1;
|
|
|
|
matrix._34 = 0;
|
2013-06-03 00:35:17 +04:00
|
|
|
matrix._41 = array->Item(5).GetFloatValue();
|
|
|
|
matrix._42 = array->Item(6).GetFloatValue();
|
2012-07-31 21:28:21 +04:00
|
|
|
matrix._43 = 0;
|
|
|
|
matrix._44 = 1;
|
|
|
|
aFunctions.AppendElement(TransformMatrix(matrix));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case eCSSKeyword_matrix3d:
|
|
|
|
{
|
2014-01-27 19:28:33 +04:00
|
|
|
gfx::Matrix4x4 matrix;
|
2012-07-31 21:28:21 +04:00
|
|
|
matrix._11 = array->Item(1).GetFloatValue();
|
|
|
|
matrix._12 = array->Item(2).GetFloatValue();
|
|
|
|
matrix._13 = array->Item(3).GetFloatValue();
|
|
|
|
matrix._14 = array->Item(4).GetFloatValue();
|
|
|
|
matrix._21 = array->Item(5).GetFloatValue();
|
|
|
|
matrix._22 = array->Item(6).GetFloatValue();
|
|
|
|
matrix._23 = array->Item(7).GetFloatValue();
|
|
|
|
matrix._24 = array->Item(8).GetFloatValue();
|
|
|
|
matrix._31 = array->Item(9).GetFloatValue();
|
|
|
|
matrix._32 = array->Item(10).GetFloatValue();
|
|
|
|
matrix._33 = array->Item(11).GetFloatValue();
|
|
|
|
matrix._34 = array->Item(12).GetFloatValue();
|
|
|
|
matrix._41 = array->Item(13).GetFloatValue();
|
|
|
|
matrix._42 = array->Item(14).GetFloatValue();
|
|
|
|
matrix._43 = array->Item(15).GetFloatValue();
|
|
|
|
matrix._44 = array->Item(16).GetFloatValue();
|
|
|
|
aFunctions.AppendElement(TransformMatrix(matrix));
|
|
|
|
break;
|
|
|
|
}
|
2012-12-12 01:12:43 +04:00
|
|
|
case eCSSKeyword_interpolatematrix:
|
|
|
|
{
|
2016-02-02 03:45:09 +03:00
|
|
|
bool dummy;
|
2015-07-11 03:05:47 +03:00
|
|
|
Matrix4x4 matrix;
|
2012-12-12 01:12:43 +04:00
|
|
|
nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array,
|
|
|
|
aContext,
|
|
|
|
aPresContext,
|
2015-06-23 04:48:18 +03:00
|
|
|
conditions,
|
2016-02-02 03:45:09 +03:00
|
|
|
aRefBox,
|
|
|
|
&dummy);
|
2015-07-11 03:05:47 +03:00
|
|
|
aFunctions.AppendElement(TransformMatrix(matrix));
|
2012-12-12 01:12:43 +04:00
|
|
|
break;
|
|
|
|
}
|
2016-11-16 14:32:33 +03:00
|
|
|
case eCSSKeyword_accumulatematrix:
|
|
|
|
{
|
|
|
|
bool dummy;
|
|
|
|
Matrix4x4 matrix;
|
|
|
|
nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, array,
|
|
|
|
aContext,
|
|
|
|
aPresContext,
|
|
|
|
conditions,
|
|
|
|
aRefBox,
|
|
|
|
&dummy);
|
|
|
|
aFunctions.AppendElement(TransformMatrix(matrix));
|
|
|
|
break;
|
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
case eCSSKeyword_perspective:
|
|
|
|
{
|
|
|
|
aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue()));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
NS_ERROR("Function not handled yet!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static TimingFunction
|
2016-02-09 13:00:59 +03:00
|
|
|
ToTimingFunction(const Maybe<ComputedTimingFunction>& aCTF)
|
2012-07-31 21:28:21 +04:00
|
|
|
{
|
2016-01-26 23:14:00 +03:00
|
|
|
if (aCTF.isNothing()) {
|
|
|
|
return TimingFunction(null_t());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aCTF->HasSpline()) {
|
|
|
|
const nsSMILKeySpline* spline = aCTF->GetFunction();
|
2012-07-31 21:28:21 +04:00
|
|
|
return TimingFunction(CubicBezierFunction(spline->X1(), spline->Y1(),
|
|
|
|
spline->X2(), spline->Y2()));
|
|
|
|
}
|
|
|
|
|
2016-01-26 23:14:00 +03:00
|
|
|
uint32_t type = aCTF->GetType() == nsTimingFunction::Type::StepStart ? 1 : 2;
|
|
|
|
return TimingFunction(StepFunction(aCTF->GetSteps(), type));
|
2012-07-31 21:28:21 +04:00
|
|
|
}
|
|
|
|
|
2016-12-04 02:07:40 +03:00
|
|
|
static void
|
|
|
|
SetAnimatable(nsCSSPropertyID aProperty,
|
|
|
|
const StyleAnimationValue& aAnimationValue,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
const TransformReferenceBox& aRefBox,
|
|
|
|
layers::Animatable& aAnimatable)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aFrame);
|
|
|
|
|
|
|
|
switch (aProperty) {
|
|
|
|
case eCSSProperty_opacity:
|
|
|
|
if (!aAnimationValue.IsNull()) {
|
|
|
|
aAnimatable = aAnimationValue.GetFloatValue();
|
|
|
|
} else {
|
|
|
|
aAnimatable = 0.0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case eCSSProperty_transform:
|
|
|
|
aAnimatable = InfallibleTArray<TransformFunction>();
|
|
|
|
if (!aAnimationValue.IsNull()) {
|
|
|
|
nsCSSValueSharedList* list =
|
|
|
|
aAnimationValue.GetCSSValueSharedListValue();
|
|
|
|
TransformReferenceBox refBox(aFrame);
|
|
|
|
AddTransformFunctions(list->mHead,
|
|
|
|
aFrame->StyleContext(),
|
|
|
|
aFrame->PresContext(),
|
|
|
|
refBox,
|
|
|
|
aAnimatable.get_ArrayOfTransformFunction());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Unsupported property");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
SetBaseAnimationStyle(nsCSSPropertyID aProperty,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
const TransformReferenceBox& aRefBox,
|
|
|
|
layers::BaseAnimationStyle& aBaseStyle)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aFrame);
|
|
|
|
|
2016-12-10 03:16:33 +03:00
|
|
|
StyleAnimationValue baseValue =
|
|
|
|
EffectCompositor::GetBaseStyle(aProperty, aFrame);
|
2016-12-04 02:07:40 +03:00
|
|
|
MOZ_ASSERT(!baseValue.IsNull(),
|
|
|
|
"The base value should be already there");
|
|
|
|
|
|
|
|
layers::Animatable animatable;
|
|
|
|
SetAnimatable(aProperty, baseValue, aFrame, aRefBox, animatable);
|
|
|
|
aBaseStyle = animatable;
|
|
|
|
}
|
|
|
|
|
2012-07-31 21:28:21 +04:00
|
|
|
static void
|
2015-03-20 07:10:00 +03:00
|
|
|
AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
|
2015-04-21 04:22:10 +03:00
|
|
|
dom::Animation* aAnimation, Layer* aLayer,
|
2014-04-03 09:57:28 +04:00
|
|
|
AnimationData& aData, bool aPending)
|
2012-07-31 21:28:21 +04:00
|
|
|
{
|
2014-08-10 11:06:49 +04:00
|
|
|
MOZ_ASSERT(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
|
2015-04-21 04:22:10 +03:00
|
|
|
MOZ_ASSERT(aAnimation->GetEffect(),
|
|
|
|
"Should not be adding an animation without an effect");
|
2015-04-28 06:49:12 +03:00
|
|
|
MOZ_ASSERT(!aAnimation->GetCurrentOrPendingStartTime().IsNull() ||
|
2016-12-02 09:34:13 +03:00
|
|
|
!aAnimation->IsPlaying() ||
|
2015-04-28 10:25:07 +03:00
|
|
|
(aAnimation->GetTimeline() &&
|
|
|
|
aAnimation->GetTimeline()->TracksWallclockTime()),
|
2016-12-02 09:34:13 +03:00
|
|
|
"If the animation has an unresolved start time it should either"
|
|
|
|
" be static (so we don't need a start time) or else have a"
|
|
|
|
" timeline capable of converting TimeStamps (so we can calculate"
|
|
|
|
" one later");
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2014-08-10 11:06:49 +04:00
|
|
|
layers::Animation* animation =
|
2014-04-03 09:57:28 +04:00
|
|
|
aPending ?
|
|
|
|
aLayer->AddAnimationForNextTransaction() :
|
|
|
|
aLayer->AddAnimation();
|
2012-08-20 17:35:42 +04:00
|
|
|
|
2016-01-13 20:41:00 +03:00
|
|
|
const TimingParams& timing = aAnimation->GetEffect()->SpecifiedTiming();
|
2016-05-24 23:51:57 +03:00
|
|
|
|
|
|
|
// If we are starting a new transition that replaces an existing transition
|
|
|
|
// running on the compositor, it is possible that the animation on the
|
|
|
|
// compositor will have advanced ahead of the main thread. If we use as
|
|
|
|
// the starting point of the new transition, the current value of the
|
|
|
|
// replaced transition as calculated on the main thread using the refresh
|
|
|
|
// driver time, the new transition will jump when it starts. Instead, we
|
|
|
|
// re-calculate the starting point of the new transition by applying the
|
|
|
|
// current TimeStamp to the parameters of the replaced transition.
|
|
|
|
//
|
|
|
|
// We need to do this here, rather than when we generate the new transition,
|
|
|
|
// since after generating the new transition other requestAnimationFrame
|
|
|
|
// callbacks may run that introduce further lag between the main thread and
|
|
|
|
// the compositor.
|
|
|
|
if (aAnimation->AsCSSTransition() &&
|
2016-07-28 06:20:13 +03:00
|
|
|
aAnimation->GetEffect() &&
|
|
|
|
aAnimation->GetEffect()->AsTransition()) {
|
|
|
|
// We update startValue from the replaced transition only if the effect is
|
|
|
|
// an ElementPropertyTransition.
|
2016-05-24 23:51:57 +03:00
|
|
|
aAnimation->GetEffect()->AsTransition()->
|
|
|
|
UpdateStartValueFromReplacedTransition();
|
|
|
|
}
|
|
|
|
|
2016-01-10 20:41:00 +03:00
|
|
|
const ComputedTiming computedTiming =
|
|
|
|
aAnimation->GetEffect()->GetComputedTiming();
|
2015-04-21 04:22:10 +03:00
|
|
|
Nullable<TimeDuration> startTime = aAnimation->GetCurrentOrPendingStartTime();
|
2015-02-03 08:08:37 +03:00
|
|
|
animation->startTime() = startTime.IsNull()
|
|
|
|
? TimeStamp()
|
2016-10-14 13:14:01 +03:00
|
|
|
: aAnimation->GetTimeline()->
|
|
|
|
ToTimeStamp(startTime.Value());
|
2016-12-02 09:34:13 +03:00
|
|
|
animation->holdTime() = aAnimation->GetCurrentTime().Value();
|
|
|
|
|
2016-10-14 13:14:01 +03:00
|
|
|
animation->delay() = timing.mDelay;
|
2016-12-02 09:34:13 +03:00
|
|
|
animation->endDelay() = timing.mEndDelay;
|
2016-01-13 20:36:00 +03:00
|
|
|
animation->duration() = computedTiming.mDuration;
|
2015-12-27 20:51:00 +03:00
|
|
|
animation->iterations() = computedTiming.mIterations;
|
2016-03-02 10:23:34 +03:00
|
|
|
animation->iterationStart() = computedTiming.mIterationStart;
|
2016-08-27 10:50:29 +03:00
|
|
|
animation->direction() = static_cast<uint8_t>(timing.mDirection);
|
2016-10-26 11:19:38 +03:00
|
|
|
animation->fillMode() = static_cast<uint8_t>(computedTiming.mFill);
|
2015-03-20 07:10:00 +03:00
|
|
|
animation->property() = aProperty.mProperty;
|
2015-07-06 20:05:00 +03:00
|
|
|
animation->playbackRate() = aAnimation->PlaybackRate();
|
2014-03-05 08:13:21 +04:00
|
|
|
animation->data() = aData;
|
2016-01-26 23:19:00 +03:00
|
|
|
animation->easingFunction() = ToTimingFunction(timing.mFunction);
|
2016-09-13 05:48:44 +03:00
|
|
|
animation->iterationComposite() =
|
|
|
|
static_cast<uint8_t>(aAnimation->GetEffect()->
|
|
|
|
AsKeyframeEffect()->IterationComposite());
|
2016-12-02 09:34:13 +03:00
|
|
|
animation->isNotPlaying() = !aAnimation->IsPlaying();
|
2012-08-20 17:35:42 +04:00
|
|
|
|
2016-12-04 02:07:40 +03:00
|
|
|
TransformReferenceBox refBox(aFrame);
|
|
|
|
|
|
|
|
// If the animation is additive or accumulates, we need to pass its base value
|
|
|
|
// to the compositor.
|
|
|
|
if (aAnimation->GetEffect()->AsKeyframeEffect()->
|
|
|
|
NeedsBaseStyle(aProperty.mProperty)) {
|
|
|
|
SetBaseAnimationStyle(aProperty.mProperty,
|
|
|
|
aFrame, refBox,
|
|
|
|
animation->baseStyle());
|
|
|
|
} else {
|
|
|
|
animation->baseStyle() = null_t();
|
|
|
|
}
|
|
|
|
|
2015-03-20 07:10:00 +03:00
|
|
|
for (uint32_t segIdx = 0; segIdx < aProperty.mSegments.Length(); segIdx++) {
|
|
|
|
const AnimationPropertySegment& segment = aProperty.mSegments[segIdx];
|
2012-07-31 21:28:22 +04:00
|
|
|
|
2015-03-20 07:10:00 +03:00
|
|
|
AnimationSegment* animSegment = animation->segments().AppendElement();
|
2016-12-04 02:07:40 +03:00
|
|
|
SetAnimatable(aProperty.mProperty,
|
|
|
|
segment.mFromValue,
|
|
|
|
aFrame, refBox,
|
|
|
|
animSegment->startState());
|
|
|
|
SetAnimatable(aProperty.mProperty,
|
|
|
|
segment.mToValue,
|
|
|
|
aFrame, refBox,
|
|
|
|
animSegment->endState());
|
2015-03-20 07:10:00 +03:00
|
|
|
|
|
|
|
animSegment->startPortion() = segment.mFromKey;
|
|
|
|
animSegment->endPortion() = segment.mToKey;
|
2016-12-04 02:07:40 +03:00
|
|
|
animSegment->startComposite() =
|
|
|
|
static_cast<uint8_t>(segment.mFromComposite);
|
|
|
|
animSegment->endComposite() =
|
|
|
|
static_cast<uint8_t>(segment.mToComposite);
|
2016-01-29 16:44:00 +03:00
|
|
|
animSegment->sampleFn() = ToTimingFunction(segment.mTimingFunction);
|
2012-07-31 21:28:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-03 09:57:28 +04:00
|
|
|
static void
|
2016-08-10 02:28:19 +03:00
|
|
|
AddAnimationsForProperty(nsIFrame* aFrame, nsCSSPropertyID aProperty,
|
2016-03-09 06:55:39 +03:00
|
|
|
nsTArray<RefPtr<dom::Animation>>& aAnimations,
|
2014-04-03 09:57:28 +04:00
|
|
|
Layer* aLayer, AnimationData& aData,
|
2015-03-20 07:10:00 +03:00
|
|
|
bool aPending)
|
|
|
|
{
|
2015-04-01 01:05:54 +03:00
|
|
|
MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
|
|
|
|
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
|
|
|
|
"inconsistent property flags");
|
|
|
|
|
2016-10-05 08:42:56 +03:00
|
|
|
DebugOnly<EffectSet*> effects = EffectSet::GetEffectSet(aFrame);
|
|
|
|
MOZ_ASSERT(effects);
|
|
|
|
|
2015-04-01 01:05:55 +03:00
|
|
|
// Add from first to last (since last overrides)
|
2015-04-21 04:22:10 +03:00
|
|
|
for (size_t animIdx = 0; animIdx < aAnimations.Length(); animIdx++) {
|
|
|
|
dom::Animation* anim = aAnimations[animIdx];
|
2016-12-02 09:34:13 +03:00
|
|
|
if (!anim->IsRelevant()) {
|
2015-03-20 07:10:00 +03:00
|
|
|
continue;
|
|
|
|
}
|
2016-07-25 11:56:34 +03:00
|
|
|
|
|
|
|
dom::KeyframeEffectReadOnly* keyframeEffect =
|
|
|
|
anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
|
|
|
|
MOZ_ASSERT(keyframeEffect,
|
|
|
|
"A playing animation should have a keyframe effect");
|
2015-03-20 07:10:00 +03:00
|
|
|
const AnimationProperty* property =
|
2016-10-13 10:54:25 +03:00
|
|
|
keyframeEffect->GetEffectiveAnimationOfProperty(aProperty);
|
2015-03-20 07:10:00 +03:00
|
|
|
if (!property) {
|
2015-03-18 17:35:30 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-10-05 08:42:56 +03:00
|
|
|
// Note that if the property is overridden by !important rules,
|
2016-10-13 10:54:25 +03:00
|
|
|
// GetEffectiveAnimationOfProperty returns null instead.
|
2016-10-05 08:42:56 +03:00
|
|
|
// This is what we want, since if we have animations overridden by
|
|
|
|
// !important rules, we don't want to send them to the compositor.
|
|
|
|
MOZ_ASSERT(anim->CascadeLevel() !=
|
|
|
|
EffectCompositor::CascadeLevel::Animations ||
|
|
|
|
!effects->PropertiesWithImportantRules()
|
|
|
|
.HasProperty(aProperty),
|
2016-10-13 10:54:25 +03:00
|
|
|
"GetEffectiveAnimationOfProperty already tested the property "
|
|
|
|
"is not overridden by !important rules");
|
2015-03-20 07:10:00 +03:00
|
|
|
|
2015-04-28 05:17:10 +03:00
|
|
|
// Don't add animations that are pending if their timeline does not
|
|
|
|
// track wallclock time. This is because any pending animations on layers
|
|
|
|
// will have their start time updated with the current wallclock time.
|
|
|
|
// If we can't convert that wallclock time back to an equivalent timeline
|
|
|
|
// time, we won't be able to update the content animation and it will end
|
|
|
|
// up being out of sync with the layer animation.
|
2014-12-22 03:35:42 +03:00
|
|
|
//
|
2015-04-28 05:17:10 +03:00
|
|
|
// Currently this only happens when the timeline is driven by a refresh
|
|
|
|
// driver under test control. In this case, the next time the refresh
|
|
|
|
// driver is advanced it will trigger any pending animations.
|
|
|
|
if (anim->PlayState() == AnimationPlayState::Pending &&
|
2015-04-28 10:25:07 +03:00
|
|
|
(!anim->GetTimeline() ||
|
|
|
|
!anim->GetTimeline()->TracksWallclockTime())) {
|
2015-04-28 05:17:10 +03:00
|
|
|
continue;
|
2014-12-22 03:35:42 +03:00
|
|
|
}
|
|
|
|
|
2015-04-21 04:22:10 +03:00
|
|
|
AddAnimationForProperty(aFrame, *property, anim, aLayer, aData, aPending);
|
2016-07-25 11:56:34 +03:00
|
|
|
keyframeEffect->SetIsRunningOnCompositor(aProperty, true);
|
2014-04-03 09:57:28 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-24 07:14:57 +03:00
|
|
|
static bool
|
2016-05-12 19:08:41 +03:00
|
|
|
GenerateAndPushTextMask(nsIFrame* aFrame, nsRenderingContext* aContext,
|
2016-05-24 07:14:57 +03:00
|
|
|
const nsRect& aFillRect, nsDisplayListBuilder* aBuilder)
|
2016-04-14 11:28:07 +03:00
|
|
|
{
|
2016-05-24 07:14:57 +03:00
|
|
|
if (aBuilder->IsForGenerateGlyphMask() ||
|
|
|
|
aBuilder->IsForPaintingSelectionBG()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-14 11:28:07 +03:00
|
|
|
// The main function of enabling background-clip:text property value.
|
|
|
|
// When a nsDisplayBackgroundImage detects "text" bg-clip style, it will call
|
|
|
|
// this function to
|
2016-05-12 19:08:53 +03:00
|
|
|
// 1. Paint background color of the selection text if any.
|
|
|
|
// 2. Generate a mask by all descendant text frames
|
|
|
|
// 3. Push the generated mask into aContext.
|
|
|
|
//
|
|
|
|
// TBD: we actually generate display list of aFrame twice here. It's better
|
|
|
|
// to reuse the same display list and paint that one twice, one for selection
|
|
|
|
// background, one for generating text mask.
|
2016-04-14 11:28:07 +03:00
|
|
|
|
2016-05-12 19:08:41 +03:00
|
|
|
gfxContext* sourceCtx = aContext->ThebesContext();
|
|
|
|
gfxRect bounds =
|
|
|
|
nsLayoutUtils::RectToGfxRect(aFillRect,
|
|
|
|
aFrame->PresContext()->AppUnitsPerDevPixel());
|
2016-04-14 11:28:07 +03:00
|
|
|
|
2016-05-12 19:08:53 +03:00
|
|
|
{
|
|
|
|
// Paint text selection background into sourceCtx.
|
|
|
|
gfxContextMatrixAutoSaveRestore save(sourceCtx);
|
|
|
|
sourceCtx->SetMatrix(sourceCtx->CurrentMatrix().Translate(bounds.TopLeft()));
|
|
|
|
|
|
|
|
nsLayoutUtils::PaintFrame(aContext, aFrame,
|
|
|
|
nsRect(nsPoint(0, 0), aFrame->GetSize()),
|
|
|
|
NS_RGB(255, 255, 255),
|
|
|
|
nsDisplayListBuilderMode::PAINTING_SELECTION_BACKGROUND);
|
|
|
|
}
|
|
|
|
|
2016-05-12 19:08:41 +03:00
|
|
|
// Evaluate required surface size.
|
|
|
|
IntRect drawRect;
|
|
|
|
{
|
|
|
|
gfxContextMatrixAutoSaveRestore matRestore(sourceCtx);
|
|
|
|
|
|
|
|
sourceCtx->SetMatrix(gfxMatrix());
|
|
|
|
gfxRect clipRect = sourceCtx->GetClipExtents();
|
|
|
|
drawRect = RoundedOut(ToRect(clipRect));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a mask surface.
|
|
|
|
RefPtr<DrawTarget> sourceTarget = sourceCtx->GetDrawTarget();
|
|
|
|
RefPtr<DrawTarget> maskDT =
|
|
|
|
sourceTarget->CreateSimilarDrawTarget(drawRect.Size(),
|
|
|
|
SurfaceFormat::A8);
|
2016-06-07 04:17:48 +03:00
|
|
|
if (!maskDT || !maskDT->IsValid()) {
|
|
|
|
return false;
|
2016-05-12 19:08:41 +03:00
|
|
|
}
|
2016-06-07 02:39:56 +03:00
|
|
|
RefPtr<gfxContext> maskCtx = gfxContext::CreatePreservingTransformOrNull(maskDT);
|
2016-06-07 04:17:48 +03:00
|
|
|
MOZ_ASSERT(maskCtx);
|
2016-05-12 19:08:41 +03:00
|
|
|
gfxMatrix currentMatrix = sourceCtx->CurrentMatrix();
|
|
|
|
maskCtx->SetMatrix(gfxMatrix::Translation(bounds.TopLeft()) *
|
|
|
|
currentMatrix *
|
|
|
|
gfxMatrix::Translation(-drawRect.TopLeft()));
|
|
|
|
|
|
|
|
// Shade text shape into mask A8 surface.
|
|
|
|
nsRenderingContext rc(maskCtx);
|
|
|
|
nsLayoutUtils::PaintFrame(&rc, aFrame,
|
2016-05-03 22:55:26 +03:00
|
|
|
nsRect(nsPoint(0, 0), aFrame->GetSize()),
|
2016-04-25 19:26:51 +03:00
|
|
|
NS_RGB(255, 255, 255),
|
2016-04-27 07:01:54 +03:00
|
|
|
nsDisplayListBuilderMode::GENERATE_GLYPH);
|
2016-04-14 11:28:07 +03:00
|
|
|
|
2016-05-12 19:08:41 +03:00
|
|
|
// Push the generated mask into aContext, so that the caller can pop and
|
|
|
|
// blend with it.
|
|
|
|
Matrix maskTransform = ToMatrix(currentMatrix) *
|
|
|
|
Matrix::Translation(-drawRect.x, -drawRect.y);
|
|
|
|
maskTransform.Invert();
|
|
|
|
|
|
|
|
RefPtr<SourceSurface> maskSurface = maskDT->Snapshot();
|
|
|
|
sourceCtx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, 1.0, maskSurface, maskTransform);
|
2016-05-24 07:14:57 +03:00
|
|
|
|
|
|
|
return true;
|
2016-04-14 11:28:07 +03:00
|
|
|
}
|
|
|
|
|
2014-03-05 08:13:21 +04:00
|
|
|
/* static */ void
|
|
|
|
nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer,
|
|
|
|
nsDisplayListBuilder* aBuilder,
|
|
|
|
nsDisplayItem* aItem,
|
|
|
|
nsIFrame* aFrame,
|
2016-08-10 02:28:19 +03:00
|
|
|
nsCSSPropertyID aProperty)
|
2012-07-31 21:28:21 +04:00
|
|
|
{
|
2015-04-01 01:05:54 +03:00
|
|
|
MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
|
|
|
|
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
|
|
|
|
"inconsistent property flags");
|
|
|
|
|
2014-03-05 08:13:21 +04:00
|
|
|
// This function can be called in two ways: from
|
|
|
|
// nsDisplay*::BuildLayer while constructing a layer (with all
|
|
|
|
// pointers non-null), or from RestyleManager's handling of
|
|
|
|
// UpdateOpacityLayer/UpdateTransformLayer hints.
|
|
|
|
MOZ_ASSERT(!aBuilder == !aItem,
|
|
|
|
"should only be called in two configurations, with both "
|
|
|
|
"aBuilder and aItem, or with neither");
|
|
|
|
MOZ_ASSERT(!aItem || aFrame == aItem->Frame(), "frame mismatch");
|
|
|
|
|
2015-05-08 16:56:37 +03:00
|
|
|
// Only send animations to a layer that is actually using
|
|
|
|
// off-main-thread compositing.
|
|
|
|
if (aLayer->Manager()->GetBackendType() !=
|
|
|
|
layers::LayersBackend::LAYERS_CLIENT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-05 08:13:21 +04:00
|
|
|
bool pending = !aBuilder;
|
|
|
|
|
|
|
|
if (pending) {
|
|
|
|
aLayer->ClearAnimationsForNextTransaction();
|
|
|
|
} else {
|
|
|
|
aLayer->ClearAnimations();
|
|
|
|
}
|
2012-08-07 00:33:23 +04:00
|
|
|
|
2014-11-17 07:46:00 +03:00
|
|
|
// Update the animation generation on the layer. We need to do this before
|
|
|
|
// any early returns since even if we don't add any animations to the
|
|
|
|
// layer, we still need to mark it as up-to-date with regards to animations.
|
|
|
|
// Otherwise, in RestyleManager we'll notice the discrepancy between the
|
|
|
|
// animation generation numbers and update the layer indefinitely.
|
|
|
|
uint64_t animationGeneration =
|
2016-01-06 05:04:05 +03:00
|
|
|
RestyleManager::GetAnimationGenerationForFrame(aFrame);
|
2014-11-17 07:46:00 +03:00
|
|
|
aLayer->SetAnimationGeneration(animationGeneration);
|
|
|
|
|
2016-01-13 01:54:56 +03:00
|
|
|
EffectCompositor::ClearIsRunningOnCompositor(aFrame, aProperty);
|
2015-12-04 02:34:17 +03:00
|
|
|
nsTArray<RefPtr<dom::Animation>> compositorAnimations =
|
|
|
|
EffectCompositor::GetAnimationsForCompositor(aFrame, aProperty);
|
|
|
|
if (compositorAnimations.IsEmpty()) {
|
2012-07-31 21:28:21 +04:00
|
|
|
return;
|
2012-07-31 21:28:22 +04:00
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2013-10-22 14:30:45 +04:00
|
|
|
// If the frame is not prerendered, bail out.
|
2014-03-05 08:13:21 +04:00
|
|
|
// Do this check only during layer construction; during updating the
|
|
|
|
// caller is required to check it appropriately.
|
|
|
|
if (aItem && !aItem->CanUseAsyncAnimations(aBuilder)) {
|
2016-01-13 01:54:56 +03:00
|
|
|
// EffectCompositor needs to know that we refused to run this animation
|
|
|
|
// asynchronously so that it will not throttle the main thread
|
|
|
|
// animation.
|
2016-01-28 06:23:59 +03:00
|
|
|
aFrame->Properties().Set(nsIFrame::RefusedAsyncAnimationProperty(), true);
|
2013-10-22 14:30:45 +04:00
|
|
|
|
2016-01-13 01:54:56 +03:00
|
|
|
// We need to schedule another refresh driver run so that EffectCompositor
|
|
|
|
// gets a chance to unthrottle the animation.
|
2014-03-05 08:13:21 +04:00
|
|
|
aFrame->SchedulePaint();
|
2012-08-07 00:33:23 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-31 21:28:22 +04:00
|
|
|
AnimationData data;
|
|
|
|
if (aProperty == eCSSProperty_transform) {
|
2015-04-28 21:55:42 +03:00
|
|
|
// XXX Performance here isn't ideal for SVG. We'd prefer to avoid resolving
|
|
|
|
// the dimensions of refBox. That said, we only get here if there are CSS
|
|
|
|
// animations or transitions on this element, and that is likely to be a
|
2015-09-16 00:10:48 +03:00
|
|
|
// lot rarer than transforms on SVG (the frequency of which drives the need
|
2015-04-28 21:55:42 +03:00
|
|
|
// for TransformReferenceBox).
|
|
|
|
TransformReferenceBox refBox(aFrame);
|
|
|
|
nsRect bounds(0, 0, refBox.Width(), refBox.Height());
|
2015-04-23 05:37:04 +03:00
|
|
|
// all data passed directly to the compositor should be in dev pixels
|
|
|
|
int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
float scale = devPixelsToAppUnits;
|
2014-08-29 22:47:30 +04:00
|
|
|
Point3D offsetToTransformOrigin =
|
2014-03-05 08:13:21 +04:00
|
|
|
nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds);
|
|
|
|
nsPoint origin;
|
|
|
|
if (aItem) {
|
2015-09-28 10:43:00 +03:00
|
|
|
// This branch is for display items to leverage the cache of
|
|
|
|
// nsDisplayListBuilder.
|
2014-03-05 08:13:21 +04:00
|
|
|
origin = aItem->ToReferenceFrame();
|
|
|
|
} else {
|
2015-09-28 10:43:00 +03:00
|
|
|
// This branch is running for restyling.
|
|
|
|
// Animations are animated at the coordination of the reference
|
|
|
|
// frame outside, not the given frame itself. The given frame
|
|
|
|
// is also reference frame too, so the parent's reference frame
|
|
|
|
// are used.
|
|
|
|
nsIFrame* referenceFrame =
|
|
|
|
nsLayoutUtils::GetReferenceFrame(nsLayoutUtils::GetCrossDocParentFrame(aFrame));
|
2014-03-05 08:13:21 +04:00
|
|
|
origin = aFrame->GetOffsetToCrossDoc(referenceFrame);
|
|
|
|
}
|
2012-07-31 21:28:22 +04:00
|
|
|
|
|
|
|
data = TransformData(origin, offsetToTransformOrigin,
|
2015-11-26 12:32:36 +03:00
|
|
|
bounds, devPixelsToAppUnits);
|
2012-07-31 21:28:22 +04:00
|
|
|
} else if (aProperty == eCSSProperty_opacity) {
|
|
|
|
data = null_t();
|
|
|
|
}
|
|
|
|
|
2015-12-04 02:34:17 +03:00
|
|
|
AddAnimationsForProperty(aFrame, aProperty, compositorAnimations,
|
|
|
|
aLayer, data, pending);
|
2012-07-31 21:28:21 +04:00
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
2016-04-25 19:26:28 +03:00
|
|
|
nsDisplayListBuilderMode aMode, bool aBuildCaret)
|
2006-01-26 05:29:17 +03:00
|
|
|
: mReferenceFrame(aReferenceFrame),
|
2012-07-30 18:20:58 +04:00
|
|
|
mIgnoreScrollFrame(nullptr),
|
2013-12-16 15:22:11 +04:00
|
|
|
mLayerEventRegions(nullptr),
|
2012-07-30 18:20:58 +04:00
|
|
|
mCurrentTableItem(nullptr),
|
2014-05-20 07:49:54 +04:00
|
|
|
mCurrentFrame(aReferenceFrame),
|
|
|
|
mCurrentReferenceFrame(aReferenceFrame),
|
2015-11-25 01:53:51 +03:00
|
|
|
mCurrentAGR(&mRootAGR),
|
|
|
|
mRootAGR(aReferenceFrame, nullptr),
|
2016-02-18 18:54:13 +03:00
|
|
|
mUsedAGRBudget(0),
|
2014-05-20 07:59:14 +04:00
|
|
|
mDirtyRect(-1,-1,-1,-1),
|
2012-07-30 18:20:58 +04:00
|
|
|
mGlassDisplayItem(nullptr),
|
2016-02-23 21:11:43 +03:00
|
|
|
mScrollInfoItemsForHoisting(nullptr),
|
2010-11-08 12:06:14 +03:00
|
|
|
mMode(aMode),
|
2014-04-12 03:39:22 +04:00
|
|
|
mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID),
|
2014-06-04 23:18:20 +04:00
|
|
|
mCurrentScrollbarTarget(FrameMetrics::NULL_SCROLL_ID),
|
|
|
|
mCurrentScrollbarFlags(0),
|
2015-11-26 12:32:36 +03:00
|
|
|
mPerspectiveItemIndex(0),
|
2016-02-23 21:11:43 +03:00
|
|
|
mSVGEffectsBuildingDepth(0),
|
2016-03-05 20:46:14 +03:00
|
|
|
mContainsBlendMode(false),
|
2015-10-22 11:13:30 +03:00
|
|
|
mIsBuildingScrollbar(false),
|
2015-10-20 12:39:34 +03:00
|
|
|
mCurrentScrollbarWillHaveLayer(false),
|
2010-12-04 12:58:39 +03:00
|
|
|
mBuildCaret(aBuildCaret),
|
2011-10-17 18:59:28 +04:00
|
|
|
mIgnoreSuppression(false),
|
|
|
|
mIsAtRootOfPseudoStackingContext(false),
|
|
|
|
mIncludeAllOutOfFlows(false),
|
2013-12-18 09:37:24 +04:00
|
|
|
mDescendIntoSubdocuments(true),
|
2011-10-17 18:59:28 +04:00
|
|
|
mSelectedFramesOnly(false),
|
|
|
|
mAccurateVisibleRegions(false),
|
2012-10-06 17:03:23 +04:00
|
|
|
mAllowMergingAndFlattening(true),
|
|
|
|
mWillComputePluginGeometry(false),
|
2011-10-17 18:59:28 +04:00
|
|
|
mInTransform(false),
|
2015-02-09 21:24:51 +03:00
|
|
|
mIsInChromePresContext(false),
|
2011-10-17 18:59:28 +04:00
|
|
|
mSyncDecodeImages(false),
|
|
|
|
mIsPaintingToWindow(false),
|
2012-10-18 09:34:58 +04:00
|
|
|
mIsCompositingCheap(false),
|
2013-09-15 07:30:00 +04:00
|
|
|
mContainsPluginItem(false),
|
2015-02-11 00:28:07 +03:00
|
|
|
mAncestorHasApzAwareEventHandler(false),
|
2015-02-02 23:10:51 +03:00
|
|
|
mHaveScrollableDisplayPort(false),
|
2015-02-09 21:24:51 +03:00
|
|
|
mWindowDraggingAllowed(false),
|
2015-02-24 12:24:04 +03:00
|
|
|
mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame)),
|
2015-06-04 23:51:10 +03:00
|
|
|
mForceLayerForScrollParent(false),
|
2016-07-12 08:49:11 +03:00
|
|
|
mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame)),
|
2016-11-28 23:46:56 +03:00
|
|
|
mBuildingInvisibleItems(false),
|
|
|
|
mHitTestShouldStopAtFirstOpaque(false)
|
2011-04-08 20:35:16 +04:00
|
|
|
{
|
2010-06-21 20:21:41 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayListBuilder);
|
2016-03-01 08:48:31 +03:00
|
|
|
PL_InitArenaPool(&mPool, "displayListArena", 4096,
|
2013-01-15 16:22:03 +04:00
|
|
|
std::max(NS_ALIGNMENT_OF(void*),NS_ALIGNMENT_OF(double))-1);
|
2006-01-26 05:29:17 +03:00
|
|
|
|
2007-03-31 01:11:41 +04:00
|
|
|
nsPresContext* pc = aReferenceFrame->PresContext();
|
2006-01-26 05:29:17 +03:00
|
|
|
nsIPresShell *shell = pc->PresShell();
|
|
|
|
if (pc->IsRenderingOnlySelection()) {
|
|
|
|
nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(shell));
|
|
|
|
if (selcon) {
|
|
|
|
selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
|
|
|
getter_AddRefs(mBoundingSelection));
|
|
|
|
}
|
|
|
|
}
|
2006-04-18 03:16:46 +04:00
|
|
|
|
2015-11-25 01:53:51 +03:00
|
|
|
mFrameToAnimatedGeometryRootMap.Put(aReferenceFrame, &mRootAGR);
|
|
|
|
|
2012-11-19 14:54:41 +04:00
|
|
|
nsCSSRendering::BeginFrameTreesLocked();
|
2016-08-23 18:24:54 +03:00
|
|
|
static_assert(nsDisplayItem::TYPE_MAX < (1 << nsDisplayItem::TYPE_BITS),
|
|
|
|
"Check nsDisplayItem::TYPE_MAX should not overflow");
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2006-04-27 06:45:03 +04:00
|
|
|
static void MarkFrameForDisplay(nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
|
2006-10-19 05:47:47 +04:00
|
|
|
for (nsIFrame* f = aFrame; f;
|
2012-06-08 16:22:25 +04:00
|
|
|
f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
|
2006-04-27 06:45:03 +04:00
|
|
|
if (f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)
|
|
|
|
return;
|
|
|
|
f->AddStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
|
|
|
|
if (f == aStopAtFrame) {
|
|
|
|
// we've reached a frame that we know will be painted, so we can stop.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-20 19:24:39 +04:00
|
|
|
bool nsDisplayListBuilder::NeedToForceTransparentSurfaceForItem(nsDisplayItem* aItem)
|
|
|
|
{
|
|
|
|
return aItem == mGlassDisplayItem || aItem->ClearsBackground();
|
|
|
|
}
|
|
|
|
|
2015-11-25 01:53:51 +03:00
|
|
|
AnimatedGeometryRoot*
|
|
|
|
nsDisplayListBuilder::WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot,
|
|
|
|
AnimatedGeometryRoot* aParent /* = nullptr */)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(IsAnimatedGeometryRoot(aAnimatedGeometryRoot));
|
|
|
|
|
|
|
|
AnimatedGeometryRoot* result = nullptr;
|
|
|
|
if (!mFrameToAnimatedGeometryRootMap.Get(aAnimatedGeometryRoot, &result)) {
|
2015-11-26 23:57:31 +03:00
|
|
|
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(RootReferenceFrame(), aAnimatedGeometryRoot));
|
2015-11-25 01:53:51 +03:00
|
|
|
AnimatedGeometryRoot* parent = aParent;
|
|
|
|
if (!parent) {
|
|
|
|
nsIFrame* parentFrame = nsLayoutUtils::GetCrossDocParentFrame(aAnimatedGeometryRoot);
|
|
|
|
if (parentFrame) {
|
|
|
|
nsIFrame* parentAGRFrame = FindAnimatedGeometryRootFrameFor(parentFrame);
|
|
|
|
parent = WrapAGRForFrame(parentAGRFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result = new (this) AnimatedGeometryRoot(aAnimatedGeometryRoot, parent);
|
|
|
|
mFrameToAnimatedGeometryRootMap.Put(aAnimatedGeometryRoot, result);
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(!aParent || result->mParentAGR == aParent);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimatedGeometryRoot*
|
|
|
|
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame)
|
|
|
|
{
|
2015-11-26 23:57:31 +03:00
|
|
|
if (!IsPaintingToWindow()) {
|
2015-11-25 01:53:51 +03:00
|
|
|
return &mRootAGR;
|
|
|
|
}
|
|
|
|
if (aFrame == mCurrentFrame) {
|
|
|
|
return mCurrentAGR;
|
|
|
|
}
|
|
|
|
AnimatedGeometryRoot* result = nullptr;
|
|
|
|
if (mFrameToAnimatedGeometryRootMap.Get(aFrame, &result)) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame* agrFrame = FindAnimatedGeometryRootFrameFor(aFrame);
|
|
|
|
result = WrapAGRForFrame(agrFrame);
|
|
|
|
mFrameToAnimatedGeometryRootMap.Put(aFrame, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
AnimatedGeometryRoot*
|
|
|
|
nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsDisplayItem* aItem)
|
|
|
|
{
|
|
|
|
if (aItem->ShouldFixToViewport(this)) {
|
|
|
|
// Make its active scrolled root be the active scrolled root of
|
|
|
|
// the enclosing viewport, since it shouldn't be scrolled by scrolled
|
|
|
|
// frames in its document. InvalidateFixedBackgroundFramesFromList in
|
|
|
|
// nsGfxScrollFrame will not repaint this item when scrolling occurs.
|
|
|
|
nsIFrame* viewportFrame =
|
|
|
|
nsLayoutUtils::GetClosestFrameOfType(aItem->Frame(), nsGkAtoms::viewportFrame, RootReferenceFrame());
|
|
|
|
if (viewportFrame) {
|
|
|
|
return FindAnimatedGeometryRootFor(viewportFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FindAnimatedGeometryRootFor(aItem->Frame());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-04-08 20:35:16 +04:00
|
|
|
void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
const nsRect& aDirtyRect)
|
|
|
|
{
|
2013-09-27 10:01:15 +04:00
|
|
|
nsRect dirtyRectRelativeToDirtyFrame = aDirtyRect;
|
2015-12-23 13:09:42 +03:00
|
|
|
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame) &&
|
|
|
|
IsPaintingToWindow()) {
|
|
|
|
NS_ASSERTION(aDirtyFrame == aFrame->GetParent(), "Dirty frame should be viewport frame");
|
|
|
|
// position: fixed items are reflowed into and only drawn inside the
|
|
|
|
// viewport, or the scroll position clamping scrollport size, if one is
|
|
|
|
// set.
|
|
|
|
nsIPresShell* ps = aFrame->PresContext()->PresShell();
|
|
|
|
dirtyRectRelativeToDirtyFrame.MoveTo(0, 0);
|
|
|
|
if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
|
|
|
|
dirtyRectRelativeToDirtyFrame.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
|
|
|
|
} else {
|
|
|
|
dirtyRectRelativeToDirtyFrame.SizeTo(aDirtyFrame->GetSize());
|
|
|
|
}
|
|
|
|
}
|
2016-01-07 22:34:24 +03:00
|
|
|
nsRect dirty = dirtyRectRelativeToDirtyFrame - aFrame->GetOffsetTo(aDirtyFrame);
|
2010-10-07 08:25:47 +04:00
|
|
|
nsRect overflowRect = aFrame->GetVisualOverflowRect();
|
2011-04-08 20:35:16 +04:00
|
|
|
|
2013-03-19 17:08:29 +04:00
|
|
|
if (aFrame->IsTransformed() &&
|
2015-12-10 00:28:10 +03:00
|
|
|
EffectCompositor::HasAnimationsForCompositor(aFrame,
|
|
|
|
eCSSProperty_transform)) {
|
2013-03-19 17:08:29 +04:00
|
|
|
/**
|
|
|
|
* Add a fuzz factor to the overflow rectangle so that elements only just
|
|
|
|
* out of view are pulled into the display list, so they can be
|
|
|
|
* prerendered if necessary.
|
|
|
|
*/
|
|
|
|
overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
|
|
|
|
}
|
|
|
|
|
2016-07-08 08:25:18 +03:00
|
|
|
if (!dirty.IntersectRect(dirty, overflowRect) &&
|
|
|
|
!(aFrame->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
|
2006-04-27 06:45:03 +04:00
|
|
|
return;
|
2016-07-08 08:25:18 +03:00
|
|
|
}
|
2015-02-20 21:55:28 +03:00
|
|
|
|
|
|
|
const DisplayItemClip* oldClip = mClipState.GetClipForContainingBlockDescendants();
|
2015-12-22 18:54:19 +03:00
|
|
|
const DisplayItemScrollClip* sc = mClipState.GetCurrentInnermostScrollClip();
|
2016-05-24 12:13:59 +03:00
|
|
|
OutOfFlowDisplayData* data = new OutOfFlowDisplayData(oldClip, sc, dirty);
|
2013-06-18 13:15:39 +04:00
|
|
|
aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDisplayDataProperty(), data);
|
2006-04-27 06:45:03 +04:00
|
|
|
|
|
|
|
MarkFrameForDisplay(aFrame, aDirtyFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
|
2010-03-29 05:46:55 +04:00
|
|
|
nsPresContext* presContext = aFrame->PresContext();
|
|
|
|
presContext->PropertyTable()->
|
2013-03-04 13:56:02 +04:00
|
|
|
Delete(aFrame, nsDisplayListBuilder::OutOfFlowDisplayDataProperty());
|
2006-04-27 06:45:03 +04:00
|
|
|
|
2006-10-19 05:47:47 +04:00
|
|
|
for (nsIFrame* f = aFrame; f;
|
2012-06-08 16:22:25 +04:00
|
|
|
f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) {
|
2006-04-27 06:45:03 +04:00
|
|
|
if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO))
|
|
|
|
return;
|
|
|
|
f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
nsDisplayListBuilder::~nsDisplayListBuilder() {
|
2008-01-04 04:53:01 +03:00
|
|
|
NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
|
|
|
|
"All frames should have been unmarked");
|
|
|
|
NS_ASSERTION(mPresShellStates.Length() == 0,
|
|
|
|
"All presshells should have been exited");
|
2008-04-06 15:34:14 +04:00
|
|
|
NS_ASSERTION(!mCurrentTableItem, "No table item should be active");
|
2006-04-27 06:45:03 +04:00
|
|
|
|
2012-11-19 14:54:41 +04:00
|
|
|
nsCSSRendering::EndFrameTreesLocked();
|
|
|
|
|
2015-12-22 18:54:19 +03:00
|
|
|
for (DisplayItemClip* c : mDisplayItemClipsToDestroy) {
|
|
|
|
c->DisplayItemClip::~DisplayItemClip();
|
|
|
|
}
|
|
|
|
for (DisplayItemScrollClip* c : mScrollClipsToDestroy) {
|
|
|
|
c->DisplayItemScrollClip::~DisplayItemScrollClip();
|
2013-04-15 09:11:10 +04:00
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
PL_FinishArenaPool(&mPool);
|
2010-06-21 20:21:41 +04:00
|
|
|
MOZ_COUNT_DTOR(nsDisplayListBuilder);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t
|
2009-09-13 02:44:18 +04:00
|
|
|
nsDisplayListBuilder::GetBackgroundPaintFlags() {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t flags = 0;
|
2009-09-13 02:44:18 +04:00
|
|
|
if (mSyncDecodeImages) {
|
|
|
|
flags |= nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES;
|
|
|
|
}
|
2010-10-25 18:38:09 +04:00
|
|
|
if (mIsPaintingToWindow) {
|
|
|
|
flags |= nsCSSRendering::PAINTBG_TO_WINDOW;
|
|
|
|
}
|
2009-09-13 02:44:18 +04:00
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2009-08-14 06:09:51 +04:00
|
|
|
void
|
|
|
|
nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
|
2011-05-13 20:40:46 +04:00
|
|
|
const nsRegion& aRegion)
|
2009-08-14 06:09:51 +04:00
|
|
|
{
|
2011-01-03 04:48:09 +03:00
|
|
|
if (aRegion.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
2009-09-19 16:12:48 +04:00
|
|
|
nsRegion tmp;
|
|
|
|
tmp.Sub(*aVisibleRegion, aRegion);
|
|
|
|
// Don't let *aVisibleRegion get too complex, but don't let it fluff out
|
|
|
|
// to its bounds either, which can be very bad (see bug 516740).
|
2011-01-04 11:43:47 +03:00
|
|
|
// Do let aVisibleRegion get more complex if by doing so we reduce its
|
|
|
|
// area by at least half.
|
2011-05-13 20:40:46 +04:00
|
|
|
if (GetAccurateVisibleRegions() || tmp.GetNumRects() <= 15 ||
|
2013-07-30 20:22:43 +04:00
|
|
|
tmp.Area() <= aVisibleRegion->Area()/2) {
|
2009-09-19 16:12:48 +04:00
|
|
|
*aVisibleRegion = tmp;
|
2009-08-14 06:09:51 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-16 14:52:01 +04:00
|
|
|
nsCaret *
|
2006-04-18 03:16:46 +04:00
|
|
|
nsDisplayListBuilder::GetCaret() {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsCaret> caret = CurrentPresShellState()->mPresShell->GetCaret();
|
2006-04-18 03:16:46 +04:00
|
|
|
return caret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-02-03 18:52:51 +03:00
|
|
|
nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
|
|
|
|
bool aPointerEventsNoneDoc)
|
2014-09-06 08:16:34 +04:00
|
|
|
{
|
2008-01-04 04:53:01 +03:00
|
|
|
PresShellState* state = mPresShellStates.AppendElement();
|
|
|
|
state->mPresShell = aReferenceFrame->PresContext()->PresShell();
|
2012-07-30 18:20:58 +04:00
|
|
|
state->mCaretFrame = nullptr;
|
2008-01-04 04:53:01 +03:00
|
|
|
state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length();
|
|
|
|
|
2009-04-25 12:19:23 +04:00
|
|
|
state->mPresShell->UpdateCanvasBackground();
|
|
|
|
|
2010-05-13 04:56:08 +04:00
|
|
|
if (mIsPaintingToWindow) {
|
2011-01-28 00:53:10 +03:00
|
|
|
mReferenceFrame->AddPaintedPresShell(state->mPresShell);
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2010-05-13 04:56:08 +04:00
|
|
|
state->mPresShell->IncrementPaintCount();
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool buildCaret = mBuildCaret;
|
2010-09-02 00:44:48 +04:00
|
|
|
if (mIgnoreSuppression || !state->mPresShell->IsPaintingSuppressed()) {
|
2011-10-17 18:59:28 +04:00
|
|
|
state->mIsBackgroundOnly = false;
|
2010-09-02 00:44:48 +04:00
|
|
|
} else {
|
2011-10-17 18:59:28 +04:00
|
|
|
state->mIsBackgroundOnly = true;
|
|
|
|
buildCaret = false;
|
2010-09-02 00:44:48 +04:00
|
|
|
}
|
|
|
|
|
2015-02-03 18:52:51 +03:00
|
|
|
bool pointerEventsNone = aPointerEventsNoneDoc;
|
|
|
|
if (IsInSubdocument()) {
|
|
|
|
pointerEventsNone |= mPresShellStates[mPresShellStates.Length() - 2].mInsidePointerEventsNoneDoc;
|
|
|
|
}
|
|
|
|
state->mInsidePointerEventsNoneDoc = pointerEventsNone;
|
|
|
|
|
2010-09-02 00:44:48 +04:00
|
|
|
if (!buildCaret)
|
2006-04-18 03:16:46 +04:00
|
|
|
return;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
|
2014-08-06 09:19:28 +04:00
|
|
|
state->mCaretFrame = caret->GetPaintGeometry(&state->mCaretRect);
|
2008-01-04 04:53:01 +03:00
|
|
|
if (state->mCaretFrame) {
|
2014-08-06 09:19:28 +04:00
|
|
|
mFramesMarkedForDisplay.AppendElement(state->mCaretFrame);
|
|
|
|
MarkFrameForDisplay(state->mCaretFrame, nullptr);
|
2006-04-27 06:45:03 +04:00
|
|
|
}
|
2015-02-02 23:10:51 +03:00
|
|
|
|
|
|
|
nsPresContext* pc = aReferenceFrame->PresContext();
|
2016-09-02 13:58:59 +03:00
|
|
|
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
|
|
|
|
if (docShell) {
|
|
|
|
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
|
|
|
|
}
|
2015-02-09 21:24:51 +03:00
|
|
|
mIsInChromePresContext = pc->IsChrome();
|
2006-04-18 03:16:46 +04:00
|
|
|
}
|
|
|
|
|
2016-11-10 06:46:26 +03:00
|
|
|
// A non-blank paint is a paint that does not just contain the canvas background.
|
|
|
|
static bool
|
|
|
|
DisplayListIsNonBlank(nsDisplayList* aList)
|
|
|
|
{
|
|
|
|
for (nsDisplayItem* i = aList->GetBottom(); i != nullptr; i = i->GetAbove()) {
|
|
|
|
switch (i->GetType()) {
|
|
|
|
case nsDisplayItem::TYPE_LAYER_EVENT_REGIONS:
|
|
|
|
case nsDisplayItem::TYPE_CANVAS_BACKGROUND_COLOR:
|
|
|
|
case nsDisplayItem::TYPE_CANVAS_BACKGROUND_IMAGE:
|
|
|
|
continue;
|
|
|
|
case nsDisplayItem::TYPE_SOLID_COLOR:
|
|
|
|
case nsDisplayItem::TYPE_BACKGROUND:
|
|
|
|
case nsDisplayItem::TYPE_BACKGROUND_COLOR:
|
|
|
|
if (i->Frame()->GetType() == nsGkAtoms::canvasFrame) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-04-18 03:16:46 +04:00
|
|
|
void
|
2016-11-10 06:46:26 +03:00
|
|
|
nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame, nsDisplayList* aPaintedContents)
|
2014-09-06 08:16:34 +04:00
|
|
|
{
|
2014-05-20 07:59:14 +04:00
|
|
|
NS_ASSERTION(CurrentPresShellState()->mPresShell ==
|
|
|
|
aReferenceFrame->PresContext()->PresShell(),
|
|
|
|
"Presshell mismatch");
|
2015-02-02 23:10:51 +03:00
|
|
|
|
2016-11-10 06:46:26 +03:00
|
|
|
if (mIsPaintingToWindow) {
|
|
|
|
nsPresContext* pc = aReferenceFrame->PresContext();
|
|
|
|
if (!pc->HadNonBlankPaint()) {
|
|
|
|
if (!CurrentPresShellState()->mIsBackgroundOnly &&
|
|
|
|
DisplayListIsNonBlank(aPaintedContents)) {
|
|
|
|
pc->NotifyNonBlankPaint();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-18 13:15:37 +04:00
|
|
|
ResetMarkedFramesForDisplayList();
|
|
|
|
mPresShellStates.SetLength(mPresShellStates.Length() - 1);
|
2015-02-02 23:10:51 +03:00
|
|
|
|
|
|
|
if (!mPresShellStates.IsEmpty()) {
|
|
|
|
nsPresContext* pc = CurrentPresContext();
|
2016-09-02 13:58:59 +03:00
|
|
|
nsCOMPtr<nsIDocShell> docShell = pc->GetDocShell();
|
|
|
|
if (docShell) {
|
|
|
|
docShell->GetWindowDraggingAllowed(&mWindowDraggingAllowed);
|
|
|
|
}
|
2015-02-09 21:24:51 +03:00
|
|
|
mIsInChromePresContext = pc->IsChrome();
|
2015-02-02 23:10:51 +03:00
|
|
|
}
|
2013-06-18 13:15:37 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayListBuilder::ResetMarkedFramesForDisplayList()
|
|
|
|
{
|
2008-01-04 04:53:01 +03:00
|
|
|
// Unmark and pop off the frames marked for display in this pres shell.
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t firstFrameForShell = CurrentPresShellState()->mFirstFrameMarkedForDisplay;
|
|
|
|
for (uint32_t i = firstFrameForShell;
|
2008-01-04 04:53:01 +03:00
|
|
|
i < mFramesMarkedForDisplay.Length(); ++i) {
|
|
|
|
UnmarkFrameForDisplay(mFramesMarkedForDisplay[i]);
|
|
|
|
}
|
|
|
|
mFramesMarkedForDisplay.SetLength(firstFrameForShell);
|
2006-04-18 03:16:46 +04:00
|
|
|
}
|
|
|
|
|
2006-04-27 06:45:03 +04:00
|
|
|
void
|
2009-07-28 16:51:09 +04:00
|
|
|
nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
|
|
|
|
const nsFrameList& aFrames,
|
2006-04-27 06:45:03 +04:00
|
|
|
const nsRect& aDirtyRect) {
|
2014-04-22 00:46:03 +04:00
|
|
|
mFramesMarkedForDisplay.SetCapacity(mFramesMarkedForDisplay.Length() + aFrames.GetLength());
|
2015-05-27 11:37:44 +03:00
|
|
|
for (nsIFrame* e : aFrames) {
|
|
|
|
// Skip the AccessibleCaret frame when building no caret.
|
|
|
|
if (!IsBuildingCaret()) {
|
|
|
|
nsIContent* content = e->GetContent();
|
|
|
|
if (content && content->IsInNativeAnonymousSubtree() && content->IsElement()) {
|
|
|
|
auto classList = content->AsElement()->ClassList();
|
2016-05-05 13:07:22 +03:00
|
|
|
if (classList->Contains(NS_LITERAL_STRING("moz-accessiblecaret"))) {
|
2015-05-27 11:37:44 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mFramesMarkedForDisplay.AppendElement(e);
|
|
|
|
MarkOutOfFlowFrameForDisplay(aDirtyFrame, e, aDirtyRect);
|
2006-04-27 06:45:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-17 04:31:00 +03:00
|
|
|
/**
|
|
|
|
* Mark all preserve-3d children with
|
|
|
|
* NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO to make sure
|
|
|
|
* nsFrame::BuildDisplayListForChild() would visit them. Also compute
|
|
|
|
* dirty rect for preserve-3d children.
|
|
|
|
*
|
|
|
|
* @param aDirtyFrame is the frame to mark children extending context.
|
|
|
|
*/
|
2012-05-11 11:49:14 +04:00
|
|
|
void
|
2016-02-11 14:18:55 +03:00
|
|
|
nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame)
|
2012-05-11 11:49:14 +04:00
|
|
|
{
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsIFrame::ChildList,4> childListArray;
|
2012-05-11 11:49:14 +04:00
|
|
|
aDirtyFrame->GetChildLists(&childListArray);
|
|
|
|
nsIFrame::ChildListArrayIterator lists(childListArray);
|
|
|
|
for (; !lists.IsDone(); lists.Next()) {
|
|
|
|
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
|
|
|
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
|
|
|
nsIFrame *child = childFrames.get();
|
2015-09-17 04:31:00 +03:00
|
|
|
if (child->Combines3DTransformWithAncestors()) {
|
2012-05-11 11:49:14 +04:00
|
|
|
mFramesMarkedForDisplay.AppendElement(child);
|
|
|
|
MarkFrameForDisplay(child, aDirtyFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
void*
|
2014-10-21 19:42:24 +04:00
|
|
|
nsDisplayListBuilder::Allocate(size_t aSize)
|
|
|
|
{
|
2006-01-26 05:29:17 +03:00
|
|
|
void *tmp;
|
|
|
|
PL_ARENA_ALLOCATE(tmp, &mPool, aSize);
|
2012-11-07 23:55:53 +04:00
|
|
|
if (!tmp) {
|
2014-10-21 19:42:24 +04:00
|
|
|
NS_ABORT_OOM(aSize);
|
2012-11-07 23:55:53 +04:00
|
|
|
}
|
2006-01-26 05:29:17 +03:00
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2013-05-08 09:16:30 +04:00
|
|
|
const DisplayItemClip*
|
2013-04-15 09:11:10 +04:00
|
|
|
nsDisplayListBuilder::AllocateDisplayItemClip(const DisplayItemClip& aOriginal)
|
|
|
|
{
|
|
|
|
void* p = Allocate(sizeof(DisplayItemClip));
|
2013-05-08 09:16:30 +04:00
|
|
|
if (!aOriginal.GetRoundedRectCount()) {
|
|
|
|
memcpy(p, &aOriginal, sizeof(DisplayItemClip));
|
|
|
|
return static_cast<DisplayItemClip*>(p);
|
|
|
|
}
|
|
|
|
|
2016-08-17 22:28:45 +03:00
|
|
|
DisplayItemClip* c = new (KnownNotNull, p) DisplayItemClip(aOriginal);
|
2013-04-15 09:11:10 +04:00
|
|
|
mDisplayItemClipsToDestroy.AppendElement(c);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2015-12-22 18:54:19 +03:00
|
|
|
DisplayItemScrollClip*
|
|
|
|
nsDisplayListBuilder::AllocateDisplayItemScrollClip(const DisplayItemScrollClip* aParent,
|
|
|
|
nsIScrollableFrame* aScrollableFrame,
|
|
|
|
const DisplayItemClip* aClip,
|
|
|
|
bool aIsAsyncScrollable)
|
|
|
|
{
|
|
|
|
void* p = Allocate(sizeof(DisplayItemScrollClip));
|
|
|
|
DisplayItemScrollClip* c =
|
2016-08-17 22:28:45 +03:00
|
|
|
new (KnownNotNull, p) DisplayItemScrollClip(aParent, aScrollableFrame,
|
|
|
|
aClip, aIsAsyncScrollable);
|
2015-12-22 18:54:19 +03:00
|
|
|
mScrollClipsToDestroy.AppendElement(c);
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2014-07-22 09:50:11 +04:00
|
|
|
const nsIFrame*
|
|
|
|
nsDisplayListBuilder::FindReferenceFrameFor(const nsIFrame *aFrame,
|
|
|
|
nsPoint* aOffset)
|
|
|
|
{
|
|
|
|
if (aFrame == mCurrentFrame) {
|
|
|
|
if (aOffset) {
|
|
|
|
*aOffset = mCurrentOffsetToReferenceFrame;
|
|
|
|
}
|
|
|
|
return mCurrentReferenceFrame;
|
|
|
|
}
|
|
|
|
for (const nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f))
|
|
|
|
{
|
|
|
|
if (f == mReferenceFrame || f->IsTransformed()) {
|
|
|
|
if (aOffset) {
|
|
|
|
*aOffset = aFrame->GetOffsetToCrossDoc(f);
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (aOffset) {
|
|
|
|
*aOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame);
|
|
|
|
}
|
|
|
|
return mReferenceFrame;
|
|
|
|
}
|
|
|
|
|
2014-11-21 03:58:18 +03:00
|
|
|
// Sticky frames are active if their nearest scrollable frame is also active.
|
|
|
|
static bool
|
|
|
|
IsStickyFrameActive(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* aParent)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY);
|
|
|
|
|
|
|
|
// Find the nearest scrollframe.
|
|
|
|
nsIFrame* cursor = aFrame;
|
|
|
|
nsIFrame* parent = aParent;
|
2015-12-31 08:00:47 +03:00
|
|
|
if (!parent) {
|
|
|
|
parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
|
|
|
|
}
|
2014-11-21 03:58:18 +03:00
|
|
|
while (parent->GetType() != nsGkAtoms::scrollFrame) {
|
|
|
|
cursor = parent;
|
|
|
|
if ((parent = nsLayoutUtils::GetCrossDocParentFrame(cursor)) == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
|
|
|
return sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent)
|
|
|
|
{
|
2015-11-26 23:57:31 +03:00
|
|
|
if (aFrame == mReferenceFrame) {
|
2015-11-25 01:53:51 +03:00
|
|
|
return true;
|
2015-11-26 23:57:31 +03:00
|
|
|
}
|
|
|
|
if (!IsPaintingToWindow()) {
|
|
|
|
if (aParent) {
|
|
|
|
*aParent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-21 03:58:18 +03:00
|
|
|
if (nsLayoutUtils::IsPopup(aFrame))
|
|
|
|
return true;
|
2016-02-18 18:54:13 +03:00
|
|
|
if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(aFrame)) {
|
|
|
|
const bool inBudget = AddToAGRBudget(aFrame);
|
|
|
|
if (inBudget) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2014-11-21 03:58:18 +03:00
|
|
|
if (!aFrame->GetParent() &&
|
|
|
|
nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext())) {
|
|
|
|
// Viewport frames in a display port need to be animated geometry roots
|
|
|
|
// for background-attachment:fixed elements.
|
|
|
|
return true;
|
|
|
|
}
|
2015-11-03 11:03:47 +03:00
|
|
|
if (aFrame->IsTransformed()) {
|
|
|
|
return true;
|
|
|
|
}
|
2014-11-21 03:58:18 +03:00
|
|
|
|
|
|
|
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
|
|
|
|
if (!parent)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
nsIAtom* parentType = parent->GetType();
|
|
|
|
// Treat the slider thumb as being as an active scrolled root when it wants
|
|
|
|
// its own layer so that it can move without repainting.
|
|
|
|
if (parentType == nsGkAtoms::sliderFrame && nsLayoutUtils::IsScrollbarThumbLayerized(aFrame)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
|
|
|
|
IsStickyFrameActive(this, aFrame, parent))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-13 23:11:08 +03:00
|
|
|
if (parentType == nsGkAtoms::scrollFrame || parentType == nsGkAtoms::listControlFrame) {
|
2014-11-21 03:58:18 +03:00
|
|
|
nsIScrollableFrame* sf = do_QueryFrame(parent);
|
|
|
|
if (sf->IsScrollingActive(this) && sf->GetScrolledFrame() == aFrame) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fixed-pos frames are parented by the viewport frame, which has no parent.
|
|
|
|
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aParent) {
|
|
|
|
*aParent = parent;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-25 01:53:51 +03:00
|
|
|
nsIFrame*
|
|
|
|
nsDisplayListBuilder::FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame)
|
2014-11-21 03:58:18 +03:00
|
|
|
{
|
2015-11-26 23:57:31 +03:00
|
|
|
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(RootReferenceFrame(), aFrame));
|
2014-11-21 03:58:18 +03:00
|
|
|
nsIFrame* cursor = aFrame;
|
2015-11-25 01:53:51 +03:00
|
|
|
while (cursor != RootReferenceFrame()) {
|
2014-11-21 03:58:18 +03:00
|
|
|
nsIFrame* next;
|
2015-11-25 01:53:51 +03:00
|
|
|
if (IsAnimatedGeometryRoot(cursor, &next))
|
2014-11-21 03:58:18 +03:00
|
|
|
return cursor;
|
|
|
|
cursor = next;
|
|
|
|
}
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
|
|
|
|
{
|
2015-11-25 01:53:51 +03:00
|
|
|
if (*mCurrentAGR != mCurrentFrame &&
|
|
|
|
IsAnimatedGeometryRoot(const_cast<nsIFrame*>(mCurrentFrame))) {
|
|
|
|
AnimatedGeometryRoot* oldAGR = mCurrentAGR;
|
|
|
|
mCurrentAGR = WrapAGRForFrame(const_cast<nsIFrame*>(mCurrentFrame), mCurrentAGR);
|
|
|
|
|
|
|
|
// Iterate the AGR cache and look for any objects that reference the old AGR and check
|
|
|
|
// to see if they need to be updated. AGRs can be in the cache multiple times, so we may
|
|
|
|
// end up doing the work multiple times for AGRs that don't change.
|
|
|
|
for (auto iter = mFrameToAnimatedGeometryRootMap.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
AnimatedGeometryRoot* cached = iter.UserData();
|
|
|
|
if (cached->mParentAGR == oldAGR && cached != mCurrentAGR) {
|
|
|
|
// It's possible that this cached AGR struct that has the old AGR as a parent
|
|
|
|
// should instead have mCurrentFrame has a parent.
|
|
|
|
nsIFrame* parent = FindAnimatedGeometryRootFrameFor(*cached);
|
|
|
|
MOZ_ASSERT(parent == mCurrentFrame || parent == *oldAGR);
|
|
|
|
if (parent == mCurrentFrame) {
|
|
|
|
cached->mParentAGR = mCurrentAGR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-21 03:58:18 +03:00
|
|
|
}
|
|
|
|
|
2014-09-18 12:52:27 +04:00
|
|
|
void
|
|
|
|
nsDisplayListBuilder::AdjustWindowDraggingRegion(nsIFrame* aFrame)
|
|
|
|
{
|
2015-02-02 23:10:51 +03:00
|
|
|
if (!mWindowDraggingAllowed || !IsForPainting()) {
|
2014-09-18 12:52:27 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-27 13:58:33 +03:00
|
|
|
const nsStyleUIReset* styleUI = aFrame->StyleUIReset();
|
2016-10-29 11:51:05 +03:00
|
|
|
if (styleUI->mWindowDragging == StyleWindowDragging::Default) {
|
2016-01-27 13:58:33 +03:00
|
|
|
// This frame has the default value and doesn't influence the window
|
|
|
|
// dragging region.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-01 04:14:31 +03:00
|
|
|
LayoutDeviceToLayoutDeviceMatrix4x4 referenceFrameToRootReferenceFrame;
|
2015-01-23 21:07:51 +03:00
|
|
|
|
|
|
|
// The const_cast is for nsLayoutUtils::GetTransformToAncestor.
|
|
|
|
nsIFrame* referenceFrame = const_cast<nsIFrame*>(FindReferenceFrameFor(aFrame));
|
|
|
|
|
|
|
|
if (IsInTransform()) {
|
|
|
|
// Only support 2d rectilinear transforms. Transform support is needed for
|
|
|
|
// the horizontal flip transform that's applied to the urlbar textbox in
|
|
|
|
// RTL mode - it should be able to exclude itself from the draggable region.
|
|
|
|
referenceFrameToRootReferenceFrame =
|
2015-12-01 04:14:31 +03:00
|
|
|
ViewAs<LayoutDeviceToLayoutDeviceMatrix4x4>(
|
|
|
|
nsLayoutUtils::GetTransformToAncestor(referenceFrame, mReferenceFrame));
|
2015-01-23 21:07:51 +03:00
|
|
|
Matrix referenceFrameToRootReferenceFrame2d;
|
|
|
|
if (!referenceFrameToRootReferenceFrame.Is2D(&referenceFrameToRootReferenceFrame2d) ||
|
|
|
|
!referenceFrameToRootReferenceFrame2d.IsRectilinear()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(referenceFrame == mReferenceFrame,
|
|
|
|
"referenceFrameToRootReferenceFrame needs to be adjusted");
|
|
|
|
}
|
|
|
|
|
2014-09-18 12:52:27 +04:00
|
|
|
// We do some basic visibility checking on the frame's border box here.
|
|
|
|
// We intersect it both with the current dirty rect and with the current
|
|
|
|
// clip. Either one is just a conservative approximation on its own, but
|
|
|
|
// their intersection luckily works well enough for our purposes, so that
|
|
|
|
// we don't have to do full-blown visibility computations.
|
|
|
|
// The most important case we need to handle is the scrolled-off tab:
|
|
|
|
// If the tab bar overflows, tab parts that are clipped by the scrollbox
|
|
|
|
// should not be allowed to interfere with the window dragging region. Using
|
|
|
|
// just the current DisplayItemClip is not enough to cover this case
|
|
|
|
// completely because clips are reset while building stacking context
|
|
|
|
// contents, so for example we'd fail to clip frames that have a clip path
|
|
|
|
// applied to them. But the current dirty rect doesn't get reset in that
|
|
|
|
// case, so we use it to make this case work.
|
|
|
|
nsRect borderBox = aFrame->GetRectRelativeToSelf().Intersect(mDirtyRect);
|
|
|
|
borderBox += ToReferenceFrame(aFrame);
|
|
|
|
const DisplayItemClip* clip = ClipState().GetCurrentCombinedClip(this);
|
|
|
|
if (clip) {
|
|
|
|
borderBox = clip->ApplyNonRoundedIntersection(borderBox);
|
|
|
|
}
|
|
|
|
if (!borderBox.IsEmpty()) {
|
2015-01-23 21:07:51 +03:00
|
|
|
LayoutDeviceRect devPixelBorderBox =
|
|
|
|
LayoutDevicePixel::FromAppUnits(borderBox, aFrame->PresContext()->AppUnitsPerDevPixel());
|
|
|
|
LayoutDeviceRect transformedDevPixelBorderBox =
|
2015-12-01 04:06:45 +03:00
|
|
|
TransformBy(referenceFrameToRootReferenceFrame, devPixelBorderBox);
|
2015-01-23 21:07:51 +03:00
|
|
|
transformedDevPixelBorderBox.Round();
|
|
|
|
LayoutDeviceIntRect transformedDevPixelBorderBoxInt;
|
|
|
|
if (transformedDevPixelBorderBox.ToIntRect(&transformedDevPixelBorderBoxInt)) {
|
2016-10-29 11:51:05 +03:00
|
|
|
if (styleUI->mWindowDragging == StyleWindowDragging::Drag) {
|
2015-11-26 07:32:47 +03:00
|
|
|
mWindowDraggingRegion.OrWith(transformedDevPixelBorderBoxInt);
|
2015-01-23 21:07:51 +03:00
|
|
|
} else {
|
2016-01-27 13:58:33 +03:00
|
|
|
mWindowNoDraggingRegion.OrWith(transformedDevPixelBorderBoxInt);
|
2015-01-23 21:07:51 +03:00
|
|
|
}
|
2014-09-18 12:52:27 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-27 13:58:33 +03:00
|
|
|
LayoutDeviceIntRegion
|
|
|
|
nsDisplayListBuilder::GetWindowDraggingRegion() const
|
|
|
|
{
|
|
|
|
LayoutDeviceIntRegion result;
|
|
|
|
result.Sub(mWindowDraggingRegion, mWindowNoDraggingRegion);;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-07-06 23:32:53 +03:00
|
|
|
const uint32_t gWillChangeAreaMultiplier = 3;
|
2016-02-18 18:54:13 +03:00
|
|
|
static uint32_t GetLayerizationCost(const nsSize& aSize) {
|
2014-10-22 05:54:32 +04:00
|
|
|
// There's significant overhead for each layer created from Gecko
|
|
|
|
// (IPC+Shared Objects) and from the backend (like an OpenGL texture).
|
|
|
|
// Therefore we set a minimum cost threshold of a 64x64 area.
|
|
|
|
int minBudgetCost = 64 * 64;
|
|
|
|
|
2015-07-06 23:32:53 +03:00
|
|
|
uint32_t budgetCost =
|
2014-10-22 05:54:32 +04:00
|
|
|
std::max(minBudgetCost,
|
2015-07-06 23:32:53 +03:00
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(aSize.width) *
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(aSize.height));
|
2014-10-22 05:54:32 +04:00
|
|
|
|
2015-07-06 23:32:53 +03:00
|
|
|
return budgetCost;
|
2014-10-22 05:54:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2015-07-06 23:32:53 +03:00
|
|
|
nsDisplayListBuilder::AddToWillChangeBudget(nsIFrame* aFrame,
|
|
|
|
const nsSize& aSize) {
|
2016-02-18 18:54:13 +03:00
|
|
|
if (mWillChangeBudgetSet.Contains(aFrame)) {
|
2015-07-06 23:32:53 +03:00
|
|
|
return true; // Already accounted
|
|
|
|
}
|
2014-10-22 05:55:55 +04:00
|
|
|
|
2014-10-22 05:54:32 +04:00
|
|
|
nsPresContext* key = aFrame->PresContext();
|
|
|
|
if (!mWillChangeBudget.Contains(key)) {
|
2015-07-06 23:32:53 +03:00
|
|
|
mWillChangeBudget.Put(key, DocumentWillChangeBudget());
|
2014-10-22 05:54:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
DocumentWillChangeBudget budget;
|
|
|
|
mWillChangeBudget.Get(key, &budget);
|
|
|
|
|
|
|
|
nsRect area = aFrame->PresContext()->GetVisibleArea();
|
|
|
|
uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(area.height);
|
|
|
|
|
2016-02-18 18:54:13 +03:00
|
|
|
uint32_t cost = GetLayerizationCost(aSize);
|
2015-07-06 23:32:53 +03:00
|
|
|
bool onBudget = (budget.mBudget + cost) /
|
|
|
|
gWillChangeAreaMultiplier < budgetLimit;
|
|
|
|
|
|
|
|
if (onBudget) {
|
|
|
|
budget.mBudget += cost;
|
|
|
|
mWillChangeBudget.Put(key, budget);
|
2016-02-18 18:54:13 +03:00
|
|
|
mWillChangeBudgetSet.PutEntry(aFrame);
|
2015-07-06 23:32:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return onBudget;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayListBuilder::IsInWillChangeBudget(nsIFrame* aFrame,
|
|
|
|
const nsSize& aSize) {
|
|
|
|
bool onBudget = AddToWillChangeBudget(aFrame, aSize);
|
|
|
|
|
2015-08-07 23:05:19 +03:00
|
|
|
if (!onBudget) {
|
2014-11-22 08:35:20 +03:00
|
|
|
nsString usageStr;
|
2016-02-18 18:54:13 +03:00
|
|
|
usageStr.AppendInt(GetLayerizationCost(aSize));
|
2014-11-22 08:35:20 +03:00
|
|
|
|
|
|
|
nsString multiplierStr;
|
2015-07-06 23:32:53 +03:00
|
|
|
multiplierStr.AppendInt(gWillChangeAreaMultiplier);
|
2014-11-22 08:35:20 +03:00
|
|
|
|
|
|
|
nsString limitStr;
|
2015-07-06 23:32:53 +03:00
|
|
|
nsRect area = aFrame->PresContext()->GetVisibleArea();
|
|
|
|
uint32_t budgetLimit = nsPresContext::AppUnitsToIntCSSPixels(area.width) *
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(area.height);
|
2014-11-22 08:35:20 +03:00
|
|
|
limitStr.AppendInt(budgetLimit);
|
|
|
|
|
2015-08-07 23:05:19 +03:00
|
|
|
const char16_t* params[] = { multiplierStr.get(), limitStr.get() };
|
2015-07-06 23:32:53 +03:00
|
|
|
aFrame->PresContext()->Document()->WarnOnceAbout(
|
2015-08-07 23:05:19 +03:00
|
|
|
nsIDocument::eIgnoringWillChangeOverBudget, false,
|
2015-07-06 23:32:53 +03:00
|
|
|
params, ArrayLength(params));
|
2014-11-22 08:35:20 +03:00
|
|
|
}
|
|
|
|
return onBudget;
|
2014-10-22 05:54:32 +04:00
|
|
|
}
|
|
|
|
|
2016-02-18 18:54:13 +03:00
|
|
|
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
|
|
|
const float gAGRBudgetAreaMultiplier = 0.3;
|
|
|
|
#else
|
|
|
|
const float gAGRBudgetAreaMultiplier = 3.0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayListBuilder::AddToAGRBudget(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
if (mAGRBudgetSet.Contains(aFrame)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsPresContext* presContext = aFrame->PresContext()->GetRootPresContext();
|
|
|
|
if (!presContext) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsRect area = presContext->GetVisibleArea();
|
|
|
|
const uint32_t budgetLimit = gAGRBudgetAreaMultiplier *
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(area.width) *
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(area.height);
|
|
|
|
|
|
|
|
const uint32_t cost = GetLayerizationCost(aFrame->GetSize());
|
|
|
|
const bool onBudget = mUsedAGRBudget + cost < budgetLimit;
|
|
|
|
|
|
|
|
if (onBudget) {
|
|
|
|
mUsedAGRBudget += cost;
|
|
|
|
mAGRBudgetSet.PutEntry(aFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
return onBudget;
|
|
|
|
}
|
|
|
|
|
2016-02-23 21:11:43 +03:00
|
|
|
void
|
|
|
|
nsDisplayListBuilder::EnterSVGEffectsContents(nsDisplayList* aHoistedItemsStorage)
|
2015-04-30 21:54:48 +03:00
|
|
|
{
|
2016-02-23 21:11:43 +03:00
|
|
|
MOZ_ASSERT(mSVGEffectsBuildingDepth >= 0);
|
|
|
|
MOZ_ASSERT(aHoistedItemsStorage);
|
|
|
|
if (mSVGEffectsBuildingDepth == 0) {
|
|
|
|
MOZ_ASSERT(!mScrollInfoItemsForHoisting);
|
|
|
|
mScrollInfoItemsForHoisting = aHoistedItemsStorage;
|
|
|
|
}
|
|
|
|
mSVGEffectsBuildingDepth++;
|
2015-04-30 21:54:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-02-23 21:11:43 +03:00
|
|
|
nsDisplayListBuilder::ExitSVGEffectsContents()
|
2015-04-30 21:54:48 +03:00
|
|
|
{
|
2016-02-23 21:11:43 +03:00
|
|
|
mSVGEffectsBuildingDepth--;
|
|
|
|
MOZ_ASSERT(mSVGEffectsBuildingDepth >= 0);
|
|
|
|
MOZ_ASSERT(mScrollInfoItemsForHoisting);
|
|
|
|
if (mSVGEffectsBuildingDepth == 0) {
|
|
|
|
mScrollInfoItemsForHoisting = nullptr;
|
|
|
|
}
|
2015-04-30 21:54:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayListBuilder::AppendNewScrollInfoItemForHoisting(nsDisplayScrollInfoLayer* aScrollInfoItem)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(ShouldBuildScrollInfoItemsForHoisting());
|
2016-02-23 21:11:43 +03:00
|
|
|
MOZ_ASSERT(mScrollInfoItemsForHoisting);
|
|
|
|
mScrollInfoItemsForHoisting->AppendNewToTop(aScrollInfoItem);
|
2015-04-30 21:54:48 +03:00
|
|
|
}
|
|
|
|
|
2015-07-13 18:53:10 +03:00
|
|
|
bool
|
|
|
|
nsDisplayListBuilder::IsBuildingLayerEventRegions()
|
|
|
|
{
|
2016-03-08 01:08:31 +03:00
|
|
|
if (IsPaintingToWindow()) {
|
2016-03-04 00:52:09 +03:00
|
|
|
// Note: this function and LayerEventRegionsEnabled are the only places
|
|
|
|
// that get to query LayoutEventRegionsEnabled 'directly' - other code
|
|
|
|
// should call this function.
|
2015-07-13 18:53:10 +03:00
|
|
|
return gfxPrefs::LayoutEventRegionsEnabledDoNotUseDirectly() ||
|
|
|
|
mAsyncPanZoomEnabled;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-04 00:52:09 +03:00
|
|
|
/* static */ bool
|
|
|
|
nsDisplayListBuilder::LayerEventRegionsEnabled()
|
|
|
|
{
|
|
|
|
// Note: this function and IsBuildingLayerEventRegions are the only places
|
|
|
|
// that get to query LayoutEventRegionsEnabled 'directly' - other code
|
|
|
|
// should call this function.
|
|
|
|
return gfxPrefs::LayoutEventRegionsEnabledDoNotUseDirectly() ||
|
|
|
|
gfxPlatform::AsyncPanZoomEnabled();
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const
|
|
|
|
{
|
|
|
|
aDestination.BorderBackground()->AppendToTop(BorderBackground());
|
|
|
|
aDestination.BlockBorderBackgrounds()->AppendToTop(BlockBorderBackgrounds());
|
|
|
|
aDestination.Floats()->AppendToTop(Floats());
|
|
|
|
aDestination.Content()->AppendToTop(Content());
|
|
|
|
aDestination.PositionedDescendants()->AppendToTop(PositionedDescendants());
|
|
|
|
aDestination.Outlines()->AppendToTop(Outlines());
|
|
|
|
}
|
|
|
|
|
2014-06-09 08:48:02 +04:00
|
|
|
static void
|
|
|
|
MoveListTo(nsDisplayList* aList, nsTArray<nsDisplayItem*>* aElements) {
|
2006-01-26 05:29:17 +03:00
|
|
|
nsDisplayItem* item;
|
2014-06-09 08:48:02 +04:00
|
|
|
while ((item = aList->RemoveBottom()) != nullptr) {
|
|
|
|
aElements->AppendElement(item);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-11 04:24:16 +04:00
|
|
|
nsRect
|
|
|
|
nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const {
|
|
|
|
nsRect bounds;
|
2012-07-30 18:20:58 +04:00
|
|
|
for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
|
2013-03-04 13:56:02 +04:00
|
|
|
bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder));
|
2008-09-11 04:24:16 +04:00
|
|
|
}
|
|
|
|
return bounds;
|
|
|
|
}
|
|
|
|
|
2015-12-22 18:54:19 +03:00
|
|
|
nsRect
|
2015-12-24 14:16:46 +03:00
|
|
|
nsDisplayList::GetScrollClippedBoundsUpTo(nsDisplayListBuilder* aBuilder,
|
|
|
|
const DisplayItemScrollClip* aIncludeScrollClipsUpTo) const {
|
2015-12-22 18:54:19 +03:00
|
|
|
nsRect bounds;
|
|
|
|
for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
|
2016-02-22 18:17:16 +03:00
|
|
|
nsRect r = i->GetClippedBounds(aBuilder);
|
|
|
|
if (r.IsEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (auto* sc = i->ScrollClip(); sc && sc != aIncludeScrollClipsUpTo; sc = sc->mParent) {
|
|
|
|
if (sc->mClip && sc->mClip->HasClip()) {
|
|
|
|
if (sc->mIsAsyncScrollable) {
|
|
|
|
// Assume the item can move anywhere in the scroll clip's clip rect.
|
|
|
|
r = sc->mClip->GetClipRect();
|
|
|
|
} else {
|
|
|
|
r = sc->mClip->ApplyNonRoundedIntersection(r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bounds.UnionRect(bounds, r);
|
2015-12-22 18:54:19 +03:00
|
|
|
}
|
|
|
|
return bounds;
|
|
|
|
}
|
|
|
|
|
2014-07-15 15:47:46 +04:00
|
|
|
nsRect
|
|
|
|
nsDisplayList::GetVisibleRect() const {
|
|
|
|
nsRect result;
|
|
|
|
for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) {
|
|
|
|
result.UnionRect(result, i->GetVisibleRect());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2010-08-28 03:15:08 +04:00
|
|
|
nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
|
2016-01-06 03:08:17 +03:00
|
|
|
nsRegion* aVisibleRegion) {
|
2014-05-24 01:12:29 +04:00
|
|
|
PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot",
|
|
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
|
2010-08-28 03:15:08 +04:00
|
|
|
nsRegion r;
|
|
|
|
r.And(*aVisibleRegion, GetBounds(aBuilder));
|
2016-01-06 03:08:17 +03:00
|
|
|
return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds());
|
2010-08-28 03:15:08 +04:00
|
|
|
}
|
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
static nsRegion
|
2012-05-03 08:29:05 +04:00
|
|
|
TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
|
2010-11-08 12:06:14 +03:00
|
|
|
{
|
2012-04-10 15:24:18 +04:00
|
|
|
bool snap;
|
2012-05-03 08:29:05 +04:00
|
|
|
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap);
|
2014-12-11 11:37:02 +03:00
|
|
|
if (aBuilder->IsForPluginGeometry() &&
|
|
|
|
aItem->GetType() != nsDisplayItem::TYPE_LAYER_EVENT_REGIONS)
|
|
|
|
{
|
2012-11-02 16:59:03 +04:00
|
|
|
// Treat all leaf chrome items as opaque, unless their frames are opacity:0.
|
2011-05-23 04:28:47 +04:00
|
|
|
// Since opacity:0 frames generate an nsDisplayOpacity, that item will
|
|
|
|
// not be treated as opaque here, so opacity:0 chrome content will be
|
|
|
|
// effectively ignored, as it should be.
|
2012-11-02 16:59:03 +04:00
|
|
|
// We treat leaf chrome items as opaque to ensure that they cover
|
|
|
|
// content plugins, for security reasons.
|
|
|
|
// Non-leaf chrome items don't render contents of their own so shouldn't
|
|
|
|
// be treated as opaque (and their bounds is just the union of their
|
|
|
|
// children, which might be a large area their contents don't really cover).
|
2013-04-19 16:02:13 +04:00
|
|
|
nsIFrame* f = aItem->Frame();
|
2013-04-19 16:01:41 +04:00
|
|
|
if (f->PresContext()->IsChrome() && !aItem->GetChildren() &&
|
2016-04-12 08:52:43 +03:00
|
|
|
f->StyleEffects()->mOpacity != 0.0) {
|
2012-04-10 15:24:18 +04:00
|
|
|
opaque = aItem->GetBounds(aBuilder, &snap);
|
2011-01-03 04:48:09 +03:00
|
|
|
}
|
2010-11-08 12:06:14 +03:00
|
|
|
}
|
2013-03-04 13:56:02 +04:00
|
|
|
if (opaque.IsEmpty()) {
|
|
|
|
return opaque;
|
|
|
|
}
|
|
|
|
nsRegion opaqueClipped;
|
2016-01-19 04:20:59 +03:00
|
|
|
for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
|
|
|
|
opaqueClipped.Or(opaqueClipped,
|
|
|
|
aItem->GetClip().ApproximateIntersectInward(iter.Get()));
|
2013-03-04 13:56:02 +04:00
|
|
|
}
|
|
|
|
return opaqueClipped;
|
2010-11-08 12:06:14 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2010-08-28 03:15:08 +04:00
|
|
|
nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRegion* aVisibleRegion,
|
2016-01-06 03:08:17 +03:00
|
|
|
const nsRect& aListVisibleBounds)
|
|
|
|
{
|
2010-08-28 03:15:08 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsRegion r;
|
|
|
|
r.And(*aVisibleRegion, GetBounds(aBuilder));
|
2011-04-19 07:07:23 +04:00
|
|
|
NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds),
|
2010-08-28 03:15:08 +04:00
|
|
|
"bad aListVisibleBounds");
|
|
|
|
#endif
|
2013-03-04 13:56:02 +04:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool anyVisible = false;
|
2010-03-10 23:55:05 +03:00
|
|
|
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsDisplayItem*, 512> elements;
|
2014-06-09 08:48:02 +04:00
|
|
|
MoveListTo(this, &elements);
|
2010-10-19 21:02:25 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t i = elements.Length() - 1; i >= 0; --i) {
|
2007-11-11 23:31:39 +03:00
|
|
|
nsDisplayItem* item = elements[i];
|
2009-09-07 04:35:14 +04:00
|
|
|
|
2016-08-22 20:41:59 +03:00
|
|
|
if (item->mForceNotVisible && !item->GetSameCoordinateSystemChildren()) {
|
2016-07-12 08:49:11 +03:00
|
|
|
NS_ASSERTION(item->mVisibleRect.IsEmpty(),
|
|
|
|
"invisible items should have empty vis rect");
|
|
|
|
} else {
|
|
|
|
nsRect bounds = item->GetClippedBounds(aBuilder);
|
|
|
|
|
|
|
|
nsRegion itemVisible;
|
|
|
|
itemVisible.And(*aVisibleRegion, bounds);
|
|
|
|
item->mVisibleRect = itemVisible.GetBounds();
|
|
|
|
}
|
2011-04-08 20:35:16 +04:00
|
|
|
|
2014-06-23 08:24:51 +04:00
|
|
|
if (item->ComputeVisibility(aBuilder, aVisibleRegion)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
anyVisible = true;
|
2014-03-18 03:39:59 +04:00
|
|
|
|
2014-06-06 15:00:34 +04:00
|
|
|
nsRegion opaque = TreatAsOpaque(item, aBuilder);
|
2014-06-09 08:48:02 +04:00
|
|
|
// Subtract opaque item from the visible region
|
|
|
|
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
2010-07-16 01:08:09 +04:00
|
|
|
AppendToBottom(item);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
2009-08-14 06:09:51 +04:00
|
|
|
|
2014-06-11 16:09:13 +04:00
|
|
|
mIsOpaque = !aVisibleRegion->Intersects(aListVisibleBounds);
|
2010-07-16 01:08:09 +04:00
|
|
|
return anyVisible;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2014-12-22 03:35:41 +03:00
|
|
|
static bool
|
2015-03-27 09:56:45 +03:00
|
|
|
TriggerPendingAnimationsOnSubDocuments(nsIDocument* aDocument, void* aReadyTime)
|
2014-12-22 03:35:41 +03:00
|
|
|
{
|
2015-04-21 04:22:09 +03:00
|
|
|
PendingAnimationTracker* tracker = aDocument->GetPendingAnimationTracker();
|
2014-12-22 03:35:41 +03:00
|
|
|
if (tracker) {
|
|
|
|
nsIPresShell* shell = aDocument->GetShell();
|
|
|
|
// If paint-suppression is in effect then we haven't finished painting
|
|
|
|
// this document yet so we shouldn't start animations
|
|
|
|
if (!shell || !shell->IsPaintingSuppressed()) {
|
2015-01-09 01:57:58 +03:00
|
|
|
const TimeStamp& readyTime = *static_cast<TimeStamp*>(aReadyTime);
|
2015-04-21 04:22:09 +03:00
|
|
|
tracker->TriggerPendingAnimationsOnNextTick(readyTime);
|
2014-12-22 03:35:41 +03:00
|
|
|
}
|
|
|
|
}
|
2015-03-27 09:56:45 +03:00
|
|
|
aDocument->EnumerateSubDocuments(TriggerPendingAnimationsOnSubDocuments,
|
2014-12-22 03:35:41 +03:00
|
|
|
aReadyTime);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-03-27 09:56:45 +03:00
|
|
|
TriggerPendingAnimations(nsIDocument* aDocument,
|
2014-12-22 03:35:41 +03:00
|
|
|
const TimeStamp& aReadyTime) {
|
|
|
|
MOZ_ASSERT(!aReadyTime.IsNull(),
|
|
|
|
"Animation ready time is not set. Perhaps we're using a layer"
|
|
|
|
" manager that doesn't update it");
|
2015-03-27 09:56:45 +03:00
|
|
|
TriggerPendingAnimationsOnSubDocuments(aDocument,
|
|
|
|
const_cast<TimeStamp*>(&aReadyTime));
|
2014-12-22 03:35:41 +03:00
|
|
|
}
|
|
|
|
|
2015-09-25 01:25:08 +03:00
|
|
|
LayerManager*
|
2016-06-24 03:53:27 +03:00
|
|
|
nsDisplayListBuilder::GetWidgetLayerManager(nsView** aView)
|
2015-09-25 01:25:08 +03:00
|
|
|
{
|
|
|
|
nsView* view = RootReferenceFrame()->GetView();
|
|
|
|
if (aView) {
|
|
|
|
*aView = view;
|
|
|
|
}
|
|
|
|
if (RootReferenceFrame() != nsLayoutUtils::GetDisplayRootFrame(RootReferenceFrame())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
nsIWidget* window = RootReferenceFrame()->GetNearestWidget();
|
|
|
|
if (window) {
|
2016-06-24 03:53:27 +03:00
|
|
|
return window->GetLayerManager();
|
2015-09-25 01:25:08 +03:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-10-21 01:32:09 +04:00
|
|
|
/**
|
|
|
|
* We paint by executing a layer manager transaction, constructing a
|
|
|
|
* single layer representing the display list, and then making it the
|
|
|
|
* root of the layer manager, drawing into the PaintedLayers.
|
|
|
|
*/
|
2014-10-21 01:32:10 +04:00
|
|
|
already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx,
|
|
|
|
uint32_t aFlags) {
|
2014-05-24 01:12:29 +04:00
|
|
|
PROFILER_LABEL("nsDisplayList", "PaintRoot",
|
|
|
|
js::ProfileEntry::Category::GRAPHICS);
|
2010-03-10 23:55:05 +03:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<LayerManager> layerManager;
|
2012-08-29 09:48:41 +04:00
|
|
|
bool widgetTransaction = false;
|
2011-01-19 11:27:54 +03:00
|
|
|
bool doBeginTransaction = true;
|
2013-01-03 17:23:11 +04:00
|
|
|
nsView *view = nullptr;
|
2010-03-01 11:03:49 +03:00
|
|
|
if (aFlags & PAINT_USE_WIDGET_LAYERS) {
|
2016-06-24 03:53:27 +03:00
|
|
|
layerManager = aBuilder->GetWidgetLayerManager(&view);
|
2015-09-25 01:25:08 +03:00
|
|
|
if (layerManager) {
|
|
|
|
doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
|
|
|
|
widgetTransaction = true;
|
2010-03-01 11:03:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!layerManager) {
|
|
|
|
if (!aCtx) {
|
|
|
|
NS_WARNING("Nowhere to paint into");
|
2014-10-21 01:32:10 +04:00
|
|
|
return nullptr;
|
2010-03-01 11:03:49 +03:00
|
|
|
}
|
2014-06-19 22:22:17 +04:00
|
|
|
layerManager = new BasicLayerManager(BasicLayerManager::BLM_OFFSCREEN);
|
2010-03-01 11:03:49 +03:00
|
|
|
}
|
|
|
|
|
2012-10-23 15:01:23 +04:00
|
|
|
// Store the existing layer builder to reinstate it on return.
|
|
|
|
FrameLayerBuilder *oldBuilder = layerManager->GetLayerBuilder();
|
|
|
|
|
2012-07-17 21:03:51 +04:00
|
|
|
FrameLayerBuilder *layerBuilder = new FrameLayerBuilder();
|
2012-08-21 08:06:46 +04:00
|
|
|
layerBuilder->Init(aBuilder, layerManager);
|
2012-07-17 21:03:51 +04:00
|
|
|
|
2014-01-30 09:41:17 +04:00
|
|
|
if (aFlags & PAINT_COMPRESSED) {
|
|
|
|
layerBuilder->SetLayerTreeCompressionMode();
|
|
|
|
}
|
|
|
|
|
2011-01-19 11:27:54 +03:00
|
|
|
if (doBeginTransaction) {
|
|
|
|
if (aCtx) {
|
2016-10-29 01:48:34 +03:00
|
|
|
if (!layerManager->BeginTransactionWithTarget(aCtx->ThebesContext())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2011-01-19 11:27:54 +03:00
|
|
|
} else {
|
2016-10-29 01:48:34 +03:00
|
|
|
if (!layerManager->BeginTransaction()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2011-01-19 11:27:54 +03:00
|
|
|
}
|
|
|
|
}
|
2016-08-16 18:46:13 +03:00
|
|
|
|
|
|
|
if (XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
|
|
|
|
FrameLayerBuilder::InvalidateAllLayers(layerManager);
|
|
|
|
}
|
|
|
|
|
2012-10-12 03:38:24 +04:00
|
|
|
if (widgetTransaction) {
|
2012-07-17 21:03:51 +04:00
|
|
|
layerBuilder->DidBeginRetainedLayerTransaction(layerManager);
|
2010-03-01 11:03:49 +03:00
|
|
|
}
|
2010-03-01 10:56:19 +03:00
|
|
|
|
2014-10-21 01:32:09 +04:00
|
|
|
nsIFrame* frame = aBuilder->RootReferenceFrame();
|
|
|
|
nsPresContext* presContext = frame->PresContext();
|
2016-08-25 19:57:57 +03:00
|
|
|
nsIPresShell* presShell = presContext->PresShell();
|
2015-03-02 14:01:58 +03:00
|
|
|
nsRootPresContext* rootPresContext = presContext->GetRootPresContext();
|
2011-06-22 16:11:27 +04:00
|
|
|
|
2012-08-29 09:47:18 +04:00
|
|
|
NotifySubDocInvalidationFunc computeInvalidFunc =
|
|
|
|
presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
|
|
|
|
bool computeInvalidRect = (computeInvalidFunc ||
|
2014-02-25 02:45:40 +04:00
|
|
|
(!layerManager->IsCompositingCheap() && layerManager->NeedsWidgetInvalidation())) &&
|
2012-08-29 09:47:18 +04:00
|
|
|
widgetTransaction;
|
|
|
|
|
2014-08-25 19:09:39 +04:00
|
|
|
UniquePtr<LayerProperties> props;
|
|
|
|
if (computeInvalidRect) {
|
|
|
|
props = Move(LayerProperties::CloneFrom(layerManager->GetRoot()));
|
|
|
|
}
|
2012-08-29 09:47:18 +04:00
|
|
|
|
2016-03-29 02:14:52 +03:00
|
|
|
// Clear any ScrollMetadata that may have been set on the root layer on a
|
2015-07-14 00:48:14 +03:00
|
|
|
// previous paint. This paint will set new metrics if necessary, and if we
|
|
|
|
// don't clear the old one here, we may be left with extra metrics.
|
|
|
|
if (Layer* root = layerManager->GetRoot()) {
|
2016-08-22 20:34:41 +03:00
|
|
|
root->SetScrollMetadata(nsTArray<ScrollMetadata>());
|
2015-07-14 00:48:14 +03:00
|
|
|
}
|
|
|
|
|
2013-09-27 10:01:16 +04:00
|
|
|
ContainerLayerParameters containerParameters
|
2015-03-07 02:07:59 +03:00
|
|
|
(presShell->GetResolution(), presShell->GetResolution());
|
2016-10-12 10:58:04 +03:00
|
|
|
|
|
|
|
RefPtr<ContainerLayer> root;
|
|
|
|
{
|
|
|
|
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
|
|
|
|
root = layerBuilder->
|
|
|
|
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
|
|
|
|
containerParameters, nullptr);
|
|
|
|
}
|
2012-10-23 15:01:23 +04:00
|
|
|
|
2016-08-25 19:57:57 +03:00
|
|
|
nsIDocument* document = presShell->GetDocument();
|
2013-09-04 14:39:31 +04:00
|
|
|
|
2012-07-17 21:03:51 +04:00
|
|
|
if (!root) {
|
2012-10-23 15:01:23 +04:00
|
|
|
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
|
2014-10-21 01:32:10 +04:00
|
|
|
return nullptr;
|
2012-07-17 21:03:51 +04:00
|
|
|
}
|
2011-06-22 16:11:27 +04:00
|
|
|
// Root is being scaled up by the X/Y resolution. Scale it back down.
|
2012-08-04 01:29:22 +04:00
|
|
|
root->SetPostScale(1.0f/containerParameters.mXScale,
|
|
|
|
1.0f/containerParameters.mYScale);
|
2015-01-03 04:06:14 +03:00
|
|
|
root->SetScaleToResolution(presShell->ScaleToResolution(),
|
|
|
|
containerParameters.mXScale);
|
2015-02-17 05:30:02 +03:00
|
|
|
if (aBuilder->IsBuildingLayerEventRegions() &&
|
|
|
|
nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell)) {
|
|
|
|
root->SetEventRegionsOverride(EventRegionsOverride::ForceDispatchToContent);
|
2015-02-25 21:36:19 +03:00
|
|
|
} else {
|
|
|
|
root->SetEventRegionsOverride(EventRegionsOverride::NoOverride);
|
2015-02-17 05:30:02 +03:00
|
|
|
}
|
2010-09-04 00:10:46 +04:00
|
|
|
|
2015-02-13 04:49:10 +03:00
|
|
|
// If we're using containerless scrolling, there is still one case where we
|
|
|
|
// want the root container layer to have metrics. If the parent process is
|
|
|
|
// using XUL windows, there is no root scrollframe, and without explicitly
|
|
|
|
// creating metrics there will be no guaranteed top-level APZC.
|
2015-05-31 08:50:21 +03:00
|
|
|
bool addMetrics = gfxPrefs::LayoutUseContainersForRootFrames() ||
|
|
|
|
(XRE_IsParentProcess() && !presShell->GetRootScrollFrame());
|
|
|
|
|
|
|
|
// Add metrics if there are none in the layer tree with the id (create an id
|
|
|
|
// if there isn't one already) of the root scroll frame/root content.
|
|
|
|
bool ensureMetricsForRootId =
|
2015-06-04 23:51:10 +03:00
|
|
|
nsLayoutUtils::AsyncPanZoomEnabled(frame) &&
|
2015-05-31 08:50:21 +03:00
|
|
|
!gfxPrefs::LayoutUseContainersForRootFrames() &&
|
|
|
|
aBuilder->IsPaintingToWindow() &&
|
|
|
|
!presContext->GetParentPresContext();
|
|
|
|
|
|
|
|
nsIContent* content = nullptr;
|
|
|
|
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
|
|
|
if (rootScrollFrame) {
|
|
|
|
content = rootScrollFrame->GetContent();
|
|
|
|
} else {
|
|
|
|
// If there is no root scroll frame, pick the document element instead.
|
|
|
|
// The only case we don't want to do this is in non-APZ fennec, where
|
|
|
|
// we want the root xul document to get a null scroll id so that the root
|
|
|
|
// content document gets the first non-null scroll id.
|
|
|
|
content = document->GetDocumentElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ensureMetricsForRootId && content) {
|
|
|
|
ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
|
|
|
|
if (nsLayoutUtils::ContainsMetricsWithId(root, scrollId)) {
|
|
|
|
ensureMetricsForRootId = false;
|
2015-02-13 04:49:10 +03:00
|
|
|
}
|
2015-05-31 08:50:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (addMetrics || ensureMetricsForRootId) {
|
2015-06-08 23:01:26 +03:00
|
|
|
bool isRootContent = presContext->IsRootContentDocument();
|
2015-05-31 08:50:21 +03:00
|
|
|
|
|
|
|
nsRect viewport(aBuilder->ToReferenceFrame(frame), frame->GetSize());
|
2015-02-13 04:49:10 +03:00
|
|
|
|
2016-03-29 02:14:52 +03:00
|
|
|
root->SetScrollMetadata(
|
|
|
|
nsLayoutUtils::ComputeScrollMetadata(frame,
|
2015-05-31 08:50:21 +03:00
|
|
|
rootScrollFrame, content,
|
2014-12-18 02:37:28 +03:00
|
|
|
aBuilder->FindReferenceFrameFor(frame),
|
2015-05-26 22:40:24 +03:00
|
|
|
root, FrameMetrics::NULL_SCROLL_ID, viewport, Nothing(),
|
2015-06-08 23:01:26 +03:00
|
|
|
isRootContent, containerParameters));
|
2014-12-18 02:37:28 +03:00
|
|
|
}
|
2014-07-23 01:01:50 +04:00
|
|
|
|
|
|
|
// NS_WARNING is debug-only, so don't even bother checking the conditions in
|
|
|
|
// a release build.
|
|
|
|
#ifdef DEBUG
|
|
|
|
bool usingDisplayport = false;
|
2014-12-18 02:37:28 +03:00
|
|
|
if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
|
2014-07-23 01:01:50 +04:00
|
|
|
nsIContent* content = rootScrollFrame->GetContent();
|
|
|
|
if (content) {
|
2015-12-17 01:22:23 +03:00
|
|
|
usingDisplayport = nsLayoutUtils::HasDisplayPort(content);
|
2014-07-23 01:01:50 +04:00
|
|
|
}
|
|
|
|
}
|
2011-10-23 12:57:47 +04:00
|
|
|
if (usingDisplayport &&
|
2014-07-23 01:01:50 +04:00
|
|
|
!(root->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
|
|
|
SpammyLayoutWarningsEnabled()) {
|
2011-10-23 12:57:47 +04:00
|
|
|
// See bug 693938, attachment 567017
|
2014-02-09 09:28:04 +04:00
|
|
|
NS_WARNING("Transparent content with displayports can be expensive.");
|
2011-10-23 12:57:47 +04:00
|
|
|
}
|
2014-07-23 01:01:50 +04:00
|
|
|
#endif
|
2010-09-04 00:10:46 +04:00
|
|
|
|
2010-03-01 10:56:19 +03:00
|
|
|
layerManager->SetRoot(root);
|
2012-08-29 09:47:15 +04:00
|
|
|
layerBuilder->WillEndTransaction();
|
2014-07-23 10:03:24 +04:00
|
|
|
|
|
|
|
if (widgetTransaction ||
|
|
|
|
// SVG-as-an-image docs don't paint as part of the retained layer tree,
|
|
|
|
// but they still need the invalidation state bits cleared in order for
|
|
|
|
// invalidation for CSS/SMIL animation to work properly.
|
|
|
|
(document && document->IsBeingUsedAsImage())) {
|
2014-10-21 01:32:09 +04:00
|
|
|
frame->ClearInvalidationStateBits();
|
2014-07-23 10:03:24 +04:00
|
|
|
}
|
|
|
|
|
2012-07-23 07:00:36 +04:00
|
|
|
bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
|
2013-12-16 09:38:42 +04:00
|
|
|
LayerManager::EndTransactionFlags flags = LayerManager::END_DEFAULT;
|
|
|
|
if (layerManager->NeedsWidgetInvalidation()) {
|
2013-12-16 12:05:20 +04:00
|
|
|
if (aFlags & PAINT_NO_COMPOSITE) {
|
|
|
|
flags = LayerManager::END_NO_COMPOSITE;
|
|
|
|
}
|
|
|
|
} else {
|
2013-12-16 09:38:42 +04:00
|
|
|
// Client layer managers never composite directly, so
|
|
|
|
// we don't need to worry about END_NO_COMPOSITE.
|
|
|
|
if (aBuilder->WillComputePluginGeometry()) {
|
|
|
|
flags = LayerManager::END_NO_REMOTE_COMPOSITE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-02 14:01:58 +03:00
|
|
|
// If this is the content process, we ship plugin geometry updates over with layer
|
|
|
|
// updates, so calculate that now before we call EndTransaction.
|
2015-11-25 21:11:00 +03:00
|
|
|
if (rootPresContext && XRE_IsContentProcess()) {
|
|
|
|
if (aBuilder->WillComputePluginGeometry()) {
|
|
|
|
rootPresContext->ComputePluginGeometryUpdates(aBuilder->RootReferenceFrame(), aBuilder, this);
|
|
|
|
}
|
|
|
|
// The layer system caches plugin configuration information for forwarding
|
|
|
|
// with layer updates which needs to get set during reflow. This must be
|
|
|
|
// called even if there are no windowed plugins in the page.
|
2015-03-02 14:01:58 +03:00
|
|
|
rootPresContext->CollectPluginGeometryUpdates(layerManager);
|
|
|
|
}
|
|
|
|
|
2014-05-29 01:43:39 +04:00
|
|
|
MaybeSetupTransactionIdAllocator(layerManager, view);
|
|
|
|
|
2014-09-26 21:06:08 +04:00
|
|
|
layerManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer,
|
2013-12-16 09:38:42 +04:00
|
|
|
aBuilder, flags);
|
2012-07-23 07:00:36 +04:00
|
|
|
aBuilder->SetIsCompositingCheap(temp);
|
2012-08-29 09:47:15 +04:00
|
|
|
layerBuilder->DidEndTransaction();
|
2010-03-01 10:56:19 +03:00
|
|
|
|
2015-02-03 08:08:37 +03:00
|
|
|
if (document && widgetTransaction) {
|
2015-03-27 09:56:45 +03:00
|
|
|
TriggerPendingAnimations(document, layerManager->GetAnimationReadyTime());
|
2014-12-22 03:35:41 +03:00
|
|
|
}
|
|
|
|
|
2012-11-12 22:31:15 +04:00
|
|
|
nsIntRegion invalid;
|
2012-08-29 09:47:18 +04:00
|
|
|
if (props) {
|
|
|
|
invalid = props->ComputeDifferences(root, computeInvalidFunc);
|
2012-08-29 09:48:43 +04:00
|
|
|
} else if (widgetTransaction) {
|
|
|
|
LayerProperties::ClearInvalidations(root);
|
2012-08-29 09:47:18 +04:00
|
|
|
}
|
|
|
|
|
2013-06-18 11:59:29 +04:00
|
|
|
bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
|
2012-08-29 09:47:18 +04:00
|
|
|
if (view) {
|
|
|
|
if (props) {
|
|
|
|
if (!invalid.IsEmpty()) {
|
2012-11-12 22:31:15 +04:00
|
|
|
nsIntRect bounds = invalid.GetBounds();
|
|
|
|
nsRect rect(presContext->DevPixelsToAppUnits(bounds.x),
|
|
|
|
presContext->DevPixelsToAppUnits(bounds.y),
|
|
|
|
presContext->DevPixelsToAppUnits(bounds.width),
|
|
|
|
presContext->DevPixelsToAppUnits(bounds.height));
|
2013-06-18 11:59:29 +04:00
|
|
|
if (shouldInvalidate) {
|
|
|
|
view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
|
|
|
|
}
|
2012-11-12 22:31:15 +04:00
|
|
|
presContext->NotifyInvalidation(bounds, 0);
|
2012-08-29 09:47:18 +04:00
|
|
|
}
|
2013-06-18 11:59:29 +04:00
|
|
|
} else if (shouldInvalidate) {
|
2012-08-29 09:47:18 +04:00
|
|
|
view->GetViewManager()->InvalidateView(view);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-23 15:01:23 +04:00
|
|
|
layerManager->SetUserData(&gLayerManagerLayerBuilder, oldBuilder);
|
2014-10-21 01:32:10 +04:00
|
|
|
return layerManager.forget();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t nsDisplayList::Count() const {
|
|
|
|
uint32_t count = 0;
|
2006-01-26 05:29:17 +03:00
|
|
|
for (nsDisplayItem* i = GetBottom(); i; i = i->GetAbove()) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDisplayItem* nsDisplayList::RemoveBottom() {
|
|
|
|
nsDisplayItem* item = mSentinel.mAbove;
|
|
|
|
if (!item)
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2006-01-26 05:29:17 +03:00
|
|
|
mSentinel.mAbove = item->mAbove;
|
|
|
|
if (item == mTop) {
|
|
|
|
// must have been the only item
|
|
|
|
mTop = &mSentinel;
|
|
|
|
}
|
2012-07-30 18:20:58 +04:00
|
|
|
item->mAbove = nullptr;
|
2006-01-26 05:29:17 +03:00
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nsDisplayList::DeleteAll() {
|
|
|
|
nsDisplayItem* item;
|
2012-07-30 18:20:58 +04:00
|
|
|
while ((item = RemoveBottom()) != nullptr) {
|
2006-01-29 21:48:58 +03:00
|
|
|
item->~nsDisplayItem();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool
|
2010-11-30 17:59:46 +03:00
|
|
|
GetMouseThrough(const nsIFrame* aFrame)
|
|
|
|
{
|
2016-04-21 07:28:30 +03:00
|
|
|
if (!aFrame->IsXULBoxFrame())
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2010-11-30 17:59:46 +03:00
|
|
|
|
|
|
|
const nsIFrame* frame = aFrame;
|
|
|
|
while (frame) {
|
|
|
|
if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_ALWAYS) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2010-11-30 17:59:46 +03:00
|
|
|
} else if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2010-11-30 17:59:46 +03:00
|
|
|
}
|
2016-04-21 07:28:32 +03:00
|
|
|
frame = nsBox::GetParentXULBox(frame);
|
2010-11-30 17:59:46 +03:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2010-11-30 17:59:46 +03:00
|
|
|
}
|
|
|
|
|
2013-08-13 11:56:57 +04:00
|
|
|
static bool
|
|
|
|
IsFrameReceivingPointerEvents(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
return NS_STYLE_POINTER_EVENTS_NONE !=
|
2016-04-12 08:52:41 +03:00
|
|
|
aFrame->StyleUserInterface()->GetEffectivePointerEvents(aFrame);
|
2013-08-13 11:56:57 +04:00
|
|
|
}
|
|
|
|
|
2011-10-07 01:24:02 +04:00
|
|
|
// A list of frames, and their z depth. Used for sorting
|
|
|
|
// the results of hit testing.
|
|
|
|
struct FramesWithDepth
|
|
|
|
{
|
2014-09-01 07:36:37 +04:00
|
|
|
explicit FramesWithDepth(float aDepth) :
|
2011-10-07 01:24:02 +04:00
|
|
|
mDepth(aDepth)
|
|
|
|
{}
|
|
|
|
|
|
|
|
bool operator<(const FramesWithDepth& aOther) const {
|
2016-01-25 03:58:38 +03:00
|
|
|
if (!FuzzyEqual(mDepth, aOther.mDepth, 0.1f)) {
|
2011-10-07 01:24:02 +04:00
|
|
|
// We want to sort so that the shallowest item (highest depth value) is first
|
|
|
|
return mDepth > aOther.mDepth;
|
|
|
|
}
|
|
|
|
return this < &aOther;
|
|
|
|
}
|
|
|
|
bool operator==(const FramesWithDepth& aOther) const {
|
|
|
|
return this == &aOther;
|
|
|
|
}
|
|
|
|
|
|
|
|
float mDepth;
|
|
|
|
nsTArray<nsIFrame*> mFrames;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Sort the frames by depth and then moves all the contained frames to the destination
|
|
|
|
void FlushFramesArray(nsTArray<FramesWithDepth>& aSource, nsTArray<nsIFrame*>* aDest)
|
|
|
|
{
|
|
|
|
if (aSource.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
aSource.Sort();
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t length = aSource.Length();
|
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
2015-08-11 18:29:46 +03:00
|
|
|
aDest->AppendElements(Move(aSource[i].mFrames));
|
2011-10-07 01:24:02 +04:00
|
|
|
}
|
|
|
|
aSource.Clear();
|
|
|
|
}
|
|
|
|
|
2010-04-08 04:31:26 +04:00
|
|
|
void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
|
|
|
nsDisplayItem::HitTestState* aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames) const {
|
2006-01-26 05:29:17 +03:00
|
|
|
nsDisplayItem* item;
|
2015-11-15 16:47:27 +03:00
|
|
|
|
|
|
|
if (aState->mInPreserves3D) {
|
|
|
|
// Collect leaves of the current 3D rendering context.
|
|
|
|
for (item = GetBottom(); item; item = item->GetAbove()) {
|
2015-12-23 03:17:00 +03:00
|
|
|
auto itemType = item->GetType();
|
|
|
|
if (itemType != nsDisplayItem::TYPE_TRANSFORM ||
|
|
|
|
!static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
|
2015-11-15 16:47:27 +03:00
|
|
|
item->HitTest(aBuilder, aRect, aState, aOutFrames);
|
|
|
|
} else {
|
|
|
|
// One of leaves in the current 3D rendering context.
|
|
|
|
aState->mItemBuffer.AppendElement(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t itemBufferStart = aState->mItemBuffer.Length();
|
2006-01-26 05:29:17 +03:00
|
|
|
for (item = GetBottom(); item; item = item->GetAbove()) {
|
2008-01-04 05:08:29 +03:00
|
|
|
aState->mItemBuffer.AppendElement(item);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
2015-11-15 16:47:27 +03:00
|
|
|
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<FramesWithDepth, 16> temp;
|
2012-08-22 19:56:38 +04:00
|
|
|
for (int32_t i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart; --i) {
|
2008-01-04 05:08:29 +03:00
|
|
|
// Pop element off the end of the buffer. We want to shorten the buffer
|
|
|
|
// so that recursive calls to HitTest have more buffer space.
|
|
|
|
item = aState->mItemBuffer[i];
|
|
|
|
aState->mItemBuffer.SetLength(i);
|
|
|
|
|
2012-04-10 15:24:18 +04:00
|
|
|
bool snap;
|
2013-03-04 13:56:02 +04:00
|
|
|
nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect);
|
2015-12-23 03:17:00 +03:00
|
|
|
auto itemType = item->GetType();
|
2016-01-25 03:39:09 +03:00
|
|
|
bool same3DContext =
|
2015-12-23 03:17:00 +03:00
|
|
|
(itemType == nsDisplayItem::TYPE_TRANSFORM &&
|
|
|
|
static_cast<nsDisplayTransform*>(item)->IsParticipating3DContext()) ||
|
2016-07-02 15:47:12 +03:00
|
|
|
(itemType == nsDisplayItem::TYPE_PERSPECTIVE &&
|
2016-06-01 04:23:20 +03:00
|
|
|
item->Frame()->Extend3DContext());
|
2016-01-25 03:39:09 +03:00
|
|
|
if (same3DContext &&
|
2016-06-01 04:23:20 +03:00
|
|
|
(itemType != nsDisplayItem::TYPE_TRANSFORM ||
|
|
|
|
!static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext())) {
|
2016-01-25 03:39:09 +03:00
|
|
|
if (!item->GetClip().MayIntersect(aRect)) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsIFrame*, 1> neverUsed;
|
2015-12-23 03:17:00 +03:00
|
|
|
// Start gethering leaves of the 3D rendering context, and
|
|
|
|
// append leaves at the end of mItemBuffer. Leaves are
|
|
|
|
// processed at following iterations.
|
|
|
|
aState->mInPreserves3D = true;
|
|
|
|
item->HitTest(aBuilder, aRect, aState, &neverUsed);
|
|
|
|
aState->mInPreserves3D = false;
|
|
|
|
i = aState->mItemBuffer.Length();
|
|
|
|
continue;
|
|
|
|
}
|
2016-01-25 03:39:09 +03:00
|
|
|
if (same3DContext || item->GetClip().MayIntersect(r)) {
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsIFrame*, 16> outFrames;
|
2015-12-23 03:17:00 +03:00
|
|
|
item->HitTest(aBuilder, aRect, aState, &outFrames);
|
2012-07-31 21:28:21 +04:00
|
|
|
|
|
|
|
// For 3d transforms with preserve-3d we add hit frames into the temp list
|
2011-10-07 01:24:02 +04:00
|
|
|
// so we can sort them later, otherwise we add them directly to the output list.
|
|
|
|
nsTArray<nsIFrame*> *writeFrames = aOutFrames;
|
|
|
|
if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
|
2015-12-23 03:17:00 +03:00
|
|
|
static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
|
2011-10-12 07:16:05 +04:00
|
|
|
if (outFrames.Length()) {
|
|
|
|
nsDisplayTransform *transform = static_cast<nsDisplayTransform*>(item);
|
|
|
|
nsPoint point = aRect.TopLeft();
|
|
|
|
// A 1x1 rect means a point, otherwise use the center of the rect
|
|
|
|
if (aRect.width != 1 || aRect.height != 1) {
|
|
|
|
point = aRect.Center();
|
|
|
|
}
|
2014-02-04 03:25:23 +04:00
|
|
|
temp.AppendElement(FramesWithDepth(transform->GetHitDepthAtPoint(aBuilder, point)));
|
2011-10-12 07:16:05 +04:00
|
|
|
writeFrames = &temp[temp.Length() - 1].mFrames;
|
2011-10-07 01:24:02 +04:00
|
|
|
}
|
|
|
|
} else {
|
2012-07-31 21:28:21 +04:00
|
|
|
// We may have just finished a run of consecutive preserve-3d transforms,
|
2011-10-07 01:24:02 +04:00
|
|
|
// so flush these into the destination array before processing our frame list.
|
|
|
|
FlushFramesArray(temp, aOutFrames);
|
|
|
|
}
|
2010-04-08 04:31:26 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t j = 0; j < outFrames.Length(); j++) {
|
2010-04-08 04:31:26 +04:00
|
|
|
nsIFrame *f = outFrames.ElementAt(j);
|
|
|
|
// Handle the XUL 'mousethrough' feature and 'pointer-events'.
|
2013-08-13 11:56:57 +04:00
|
|
|
if (!GetMouseThrough(f) && IsFrameReceivingPointerEvents(f)) {
|
2011-10-07 01:24:02 +04:00
|
|
|
writeFrames->AppendElement(f);
|
2008-01-04 05:08:29 +03:00
|
|
|
}
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
2016-11-29 00:22:15 +03:00
|
|
|
|
|
|
|
if (aBuilder->HitTestShouldStopAtFirstOpaque() &&
|
|
|
|
item->GetOpaqueRegion(aBuilder, &snap).Contains(aRect)) {
|
|
|
|
// We're exiting early, so pop the remaining items off the buffer.
|
|
|
|
aState->mItemBuffer.SetLength(itemBufferStart);
|
|
|
|
break;
|
|
|
|
}
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
}
|
2011-10-07 01:24:02 +04:00
|
|
|
// Clear any remaining preserve-3d transforms.
|
|
|
|
FlushFramesArray(temp, aOutFrames);
|
2012-08-22 19:56:38 +04:00
|
|
|
NS_ASSERTION(aState->mItemBuffer.Length() == uint32_t(itemBufferStart),
|
2008-01-04 05:08:29 +03:00
|
|
|
"How did we forget to pop some elements?");
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
static void Sort(nsDisplayList* aList, int32_t aCount, nsDisplayList::SortLEQ aCmp,
|
2006-04-18 02:16:24 +04:00
|
|
|
void* aClosure) {
|
2006-01-26 05:29:17 +03:00
|
|
|
if (aCount < 2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsDisplayList list1;
|
|
|
|
nsDisplayList list2;
|
|
|
|
int i;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t half = aCount/2;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool sorted = true;
|
2012-07-30 18:20:58 +04:00
|
|
|
nsDisplayItem* prev = nullptr;
|
2006-01-26 05:29:17 +03:00
|
|
|
for (i = 0; i < aCount; ++i) {
|
|
|
|
nsDisplayItem* item = aList->RemoveBottom();
|
|
|
|
(i < half ? &list1 : &list2)->AppendToTop(item);
|
|
|
|
if (sorted && prev && !aCmp(prev, item, aClosure)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
sorted = false;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
prev = item;
|
|
|
|
}
|
|
|
|
if (sorted) {
|
|
|
|
aList->AppendToTop(&list1);
|
|
|
|
aList->AppendToTop(&list2);
|
|
|
|
return;
|
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
Sort(&list1, half, aCmp, aClosure);
|
|
|
|
Sort(&list2, aCount - half, aCmp, aClosure);
|
|
|
|
|
|
|
|
for (i = 0; i < aCount; ++i) {
|
|
|
|
if (list1.GetBottom() &&
|
|
|
|
(!list2.GetBottom() ||
|
|
|
|
aCmp(list1.GetBottom(), list2.GetBottom(), aClosure))) {
|
|
|
|
aList->AppendToTop(list1.RemoveBottom());
|
|
|
|
} else {
|
|
|
|
aList->AppendToTop(list2.RemoveBottom());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-15 10:55:36 +04:00
|
|
|
static nsIContent* FindContentInDocument(nsDisplayItem* aItem, nsIDocument* aDoc) {
|
2013-04-19 16:02:13 +04:00
|
|
|
nsIFrame* f = aItem->Frame();
|
2013-04-16 10:14:56 +04:00
|
|
|
while (f) {
|
|
|
|
nsPresContext* pc = f->PresContext();
|
|
|
|
if (pc->Document() == aDoc) {
|
|
|
|
return f->GetContent();
|
2013-04-05 12:30:34 +04:00
|
|
|
}
|
2013-04-16 10:14:56 +04:00
|
|
|
f = nsLayoutUtils::GetCrossDocParentFrame(pc->PresShell()->GetRootFrame());
|
2013-04-05 12:30:34 +04:00
|
|
|
}
|
2013-04-16 10:14:56 +04:00
|
|
|
return nullptr;
|
2013-04-05 12:30:34 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool IsContentLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
|
2013-04-05 12:30:34 +04:00
|
|
|
void* aClosure) {
|
|
|
|
nsIContent* commonAncestor = static_cast<nsIContent*>(aClosure);
|
|
|
|
// It's possible that the nsIContent for aItem1 or aItem2 is in a subdocument
|
|
|
|
// of commonAncestor, because display items for subdocuments have been
|
|
|
|
// mixed into the same list. Ensure that we're looking at content
|
|
|
|
// in commonAncestor's document.
|
|
|
|
nsIDocument* commonAncestorDoc = commonAncestor->OwnerDoc();
|
2013-04-15 10:55:36 +04:00
|
|
|
nsIContent* content1 = FindContentInDocument(aItem1, commonAncestorDoc);
|
|
|
|
nsIContent* content2 = FindContentInDocument(aItem2, commonAncestorDoc);
|
2013-04-05 12:30:34 +04:00
|
|
|
if (!content1 || !content2) {
|
|
|
|
NS_ERROR("Document trees are mixed up!");
|
|
|
|
// Something weird going on
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return nsLayoutUtils::CompareTreePosition(content1, content2, commonAncestor) <= 0;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
|
2013-04-05 12:30:34 +04:00
|
|
|
void* aClosure) {
|
2013-04-19 16:01:41 +04:00
|
|
|
// Note that we can't just take the difference of the two
|
2010-04-02 06:09:05 +04:00
|
|
|
// z-indices here, because that might overflow a 32-bit int.
|
2014-03-20 06:12:46 +04:00
|
|
|
return aItem1->ZIndex() <= aItem2->ZIndex();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2016-01-06 03:08:17 +03:00
|
|
|
void nsDisplayList::SortByZOrder() {
|
|
|
|
Sort(IsZOrderLEQ, nullptr);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2016-01-06 03:08:17 +03:00
|
|
|
void nsDisplayList::SortByContentOrder(nsIContent* aCommonAncestor) {
|
|
|
|
Sort(IsContentLEQ, aCommonAncestor);
|
2006-04-18 02:16:24 +04:00
|
|
|
}
|
|
|
|
|
2016-01-06 03:08:17 +03:00
|
|
|
void nsDisplayList::Sort(SortLEQ aCmp, void* aClosure) {
|
2006-04-18 02:16:24 +04:00
|
|
|
::Sort(this, Count(), aCmp, aClosure);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2014-07-22 09:50:11 +04:00
|
|
|
nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
2016-02-26 15:38:12 +03:00
|
|
|
: nsDisplayItem(aBuilder, aFrame, aBuilder->ClipState().GetCurrentInnermostScrollClip())
|
|
|
|
{}
|
|
|
|
|
|
|
|
nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
|
|
|
const DisplayItemScrollClip* aScrollClip)
|
2014-07-22 09:50:11 +04:00
|
|
|
: mFrame(aFrame)
|
|
|
|
, mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder))
|
2016-02-26 15:38:12 +03:00
|
|
|
, mScrollClip(aScrollClip)
|
2015-10-06 00:09:34 +03:00
|
|
|
, mAnimatedGeometryRoot(nullptr)
|
2016-07-12 08:49:11 +03:00
|
|
|
, mForceNotVisible(aBuilder->IsBuildingInvisibleItems())
|
2014-07-22 09:50:11 +04:00
|
|
|
#ifdef MOZ_DUMP_PAINTING
|
|
|
|
, mPainted(false)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
|
2015-10-06 00:09:34 +03:00
|
|
|
// This can return the wrong result if the item override ShouldFixToViewport(),
|
|
|
|
// the item needs to set it again in its constructor.
|
2015-11-25 01:53:51 +03:00
|
|
|
mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(aFrame);
|
2015-10-06 00:09:34 +03:00
|
|
|
MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(aBuilder->RootReferenceFrame(),
|
2015-11-25 01:53:51 +03:00
|
|
|
*mAnimatedGeometryRoot), "Bad");
|
2014-07-22 09:50:11 +04:00
|
|
|
NS_ASSERTION(aBuilder->GetDirtyRect().width >= 0 ||
|
|
|
|
!aBuilder->IsForPainting(), "dirty rect not set");
|
|
|
|
// The dirty rect is for mCurrentFrame, so we have to use
|
|
|
|
// mCurrentOffsetToReferenceFrame
|
|
|
|
mVisibleRect = aBuilder->GetDirtyRect() +
|
|
|
|
aBuilder->GetCurrentFrameOffsetToReferenceFrame();
|
|
|
|
}
|
|
|
|
|
2012-11-23 03:29:05 +04:00
|
|
|
/* static */ bool
|
|
|
|
nsDisplayItem::ForceActiveLayers()
|
|
|
|
{
|
|
|
|
static bool sForce = false;
|
|
|
|
static bool sForceCached = false;
|
|
|
|
|
|
|
|
if (!sForceCached) {
|
|
|
|
Preferences::AddBoolVarCache(&sForce, "layers.force-active", false);
|
|
|
|
sForceCached = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sForce;
|
|
|
|
}
|
|
|
|
|
2016-01-27 13:34:39 +03:00
|
|
|
static int32_t ZIndexForFrame(nsIFrame* aFrame)
|
2014-03-20 06:12:46 +04:00
|
|
|
{
|
2016-08-13 04:39:45 +03:00
|
|
|
if (!aFrame->IsAbsPosContainingBlock() && !aFrame->IsFlexOrGridItem())
|
2014-03-20 06:12:46 +04:00
|
|
|
return 0;
|
|
|
|
|
2016-01-27 13:34:39 +03:00
|
|
|
const nsStylePosition* position = aFrame->StylePosition();
|
2014-03-20 06:12:46 +04:00
|
|
|
if (position->mZIndex.GetUnit() == eStyleUnit_Integer)
|
|
|
|
return position->mZIndex.GetIntValue();
|
|
|
|
|
|
|
|
// sort the auto and 0 elements together
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-27 13:34:39 +03:00
|
|
|
int32_t
|
|
|
|
nsDisplayItem::ZIndex() const
|
|
|
|
{
|
|
|
|
return ZIndexForFrame(mFrame);
|
|
|
|
}
|
|
|
|
|
2014-06-03 16:48:16 +04:00
|
|
|
bool
|
|
|
|
nsDisplayItem::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion)
|
2014-06-03 16:48:16 +04:00
|
|
|
{
|
|
|
|
return !mVisibleRect.IsEmpty() &&
|
|
|
|
!IsInvisibleInRect(aVisibleRegion->GetBounds());
|
|
|
|
}
|
|
|
|
|
2012-11-23 03:29:05 +04:00
|
|
|
bool
|
|
|
|
nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRegion* aVisibleRegion) {
|
2016-08-22 20:41:59 +03:00
|
|
|
if (mForceNotVisible && !GetSameCoordinateSystemChildren()) {
|
|
|
|
// mForceNotVisible wants to ensure that this display item doesn't render
|
|
|
|
// anything itself. If this item has contents, then we obviously want to
|
|
|
|
// render those, so we don't need this check in that case.
|
2016-07-12 08:49:11 +03:00
|
|
|
NS_ASSERTION(mVisibleRect.IsEmpty(),
|
2016-08-22 20:41:59 +03:00
|
|
|
"invisible items without children should have empty vis rect");
|
2016-07-12 08:49:11 +03:00
|
|
|
} else {
|
|
|
|
nsRect bounds = GetClippedBounds(aBuilder);
|
2010-07-16 01:07:51 +04:00
|
|
|
|
2016-07-12 08:49:11 +03:00
|
|
|
nsRegion itemVisible;
|
|
|
|
itemVisible.And(*aVisibleRegion, bounds);
|
|
|
|
mVisibleRect = itemVisible.GetBounds();
|
|
|
|
}
|
2011-04-08 20:35:16 +04:00
|
|
|
|
2011-02-17 01:43:30 +03:00
|
|
|
// When we recompute visibility within layers we don't need to
|
|
|
|
// expand the visible region for content behind plugins (the plugin
|
|
|
|
// is not in the layer).
|
2014-06-23 08:24:51 +04:00
|
|
|
if (!ComputeVisibility(aBuilder, aVisibleRegion)) {
|
2014-06-20 09:24:31 +04:00
|
|
|
mVisibleRect = nsRect();
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2014-06-20 09:24:31 +04:00
|
|
|
}
|
2010-07-16 01:07:51 +04:00
|
|
|
|
2012-05-03 08:29:05 +04:00
|
|
|
nsRegion opaque = TreatAsOpaque(this, aBuilder);
|
2011-01-04 11:45:24 +03:00
|
|
|
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2010-07-16 01:07:51 +04:00
|
|
|
}
|
|
|
|
|
2013-03-04 13:56:02 +04:00
|
|
|
nsRect
|
|
|
|
nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
|
|
|
bool snap;
|
|
|
|
nsRect r = GetBounds(aBuilder, &snap);
|
|
|
|
return GetClip().ApplyNonRoundedIntersection(r);
|
|
|
|
}
|
|
|
|
|
2011-05-12 18:59:09 +04:00
|
|
|
nsRect
|
2012-04-10 15:24:18 +04:00
|
|
|
nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
2011-05-12 18:59:09 +04:00
|
|
|
{
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = true;
|
|
|
|
return mBounds;
|
2011-05-12 18:59:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplaySolidColor::Paint(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx)
|
|
|
|
{
|
2014-10-19 16:22:22 +04:00
|
|
|
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
DrawTarget* drawTarget = aCtx->GetDrawTarget();
|
2014-10-22 15:29:06 +04:00
|
|
|
Rect rect =
|
|
|
|
NSRectToSnappedRect(mVisibleRect, appUnitsPerDevPixel, *drawTarget);
|
2014-10-19 16:22:22 +04:00
|
|
|
drawTarget->FillRect(rect, ColorPattern(ToDeviceColor(mColor)));
|
2009-04-25 12:19:23 +04:00
|
|
|
}
|
|
|
|
|
2014-01-27 02:07:08 +04:00
|
|
|
void
|
2014-11-25 16:45:19 +03:00
|
|
|
nsDisplaySolidColor::WriteDebugInfo(std::stringstream& aStream)
|
2014-01-27 02:07:08 +04:00
|
|
|
{
|
2014-11-25 16:45:19 +03:00
|
|
|
aStream << " (rgba "
|
|
|
|
<< (int)NS_GET_R(mColor) << ","
|
|
|
|
<< (int)NS_GET_G(mColor) << ","
|
|
|
|
<< (int)NS_GET_B(mColor) << ","
|
|
|
|
<< (int)NS_GET_A(mColor) << ")";
|
2014-01-27 02:07:08 +04:00
|
|
|
}
|
|
|
|
|
2016-09-15 06:18:30 +03:00
|
|
|
nsRect
|
|
|
|
nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
|
|
|
{
|
|
|
|
*aSnap = true;
|
|
|
|
return mRegion.GetBounds();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplaySolidColorRegion::Paint(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx)
|
|
|
|
{
|
|
|
|
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
DrawTarget* drawTarget = aCtx->GetDrawTarget();
|
|
|
|
ColorPattern color(mColor);
|
|
|
|
for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
|
|
|
|
Rect rect =
|
|
|
|
NSRectToSnappedRect(iter.Get(), appUnitsPerDevPixel, *drawTarget);
|
|
|
|
drawTarget->FillRect(rect, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplaySolidColorRegion::WriteDebugInfo(std::stringstream& aStream)
|
|
|
|
{
|
|
|
|
aStream << " (rgba "
|
|
|
|
<< int(mColor.r * 255) << ","
|
|
|
|
<< int(mColor.g * 255) << ","
|
|
|
|
<< int(mColor.b * 255) << ","
|
|
|
|
<< mColor.a << ")";
|
|
|
|
}
|
|
|
|
|
2010-07-24 13:35:29 +04:00
|
|
|
static void
|
2015-02-05 01:25:18 +03:00
|
|
|
RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
|
|
|
nsITheme::ThemeGeometryType aType)
|
2010-07-24 13:35:29 +04:00
|
|
|
{
|
2016-10-14 23:45:29 +03:00
|
|
|
if (aBuilder->IsInChromeDocumentOrPopup() && !aBuilder->IsInTransform()) {
|
2014-09-18 12:52:27 +04:00
|
|
|
nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
|
2016-10-14 23:45:29 +03:00
|
|
|
nsPoint offset = aBuilder->IsInSubdocument() ? aBuilder->ToReferenceFrame(aFrame)
|
|
|
|
: aFrame->GetOffsetTo(displayRoot);
|
|
|
|
nsRect borderBox = nsRect(offset, aFrame->GetSize());
|
2015-02-05 01:25:18 +03:00
|
|
|
aBuilder->RegisterThemeGeometry(aType,
|
2015-11-23 07:32:29 +03:00
|
|
|
LayoutDeviceIntRect::FromUnknownRect(
|
|
|
|
borderBox.ToNearestPixels(
|
|
|
|
aFrame->PresContext()->AppUnitsPerDevPixel())));
|
2010-07-24 13:35:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-17 00:13:19 +03:00
|
|
|
// Return the bounds of the viewport relative to |aFrame|'s reference frame.
|
|
|
|
// Returns Nothing() if transforming into |aFrame|'s coordinate space fails.
|
|
|
|
static Maybe<nsRect>
|
|
|
|
GetViewportRectRelativeToReferenceFrame(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
nsIFrame* rootFrame = aFrame->PresContext()->PresShell()->GetRootFrame();
|
|
|
|
nsRect rootRect = rootFrame->GetRectRelativeToSelf();
|
|
|
|
if (nsLayoutUtils::TransformRect(rootFrame, aFrame, rootRect) == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
|
|
|
|
return Some(rootRect + aBuilder->ToReferenceFrame(aFrame));
|
|
|
|
}
|
|
|
|
return Nothing();
|
|
|
|
}
|
|
|
|
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
uint32_t aLayer,
|
2016-05-04 21:14:23 +03:00
|
|
|
const nsRect& aBackgroundRect,
|
2012-11-10 03:14:59 +04:00
|
|
|
const nsStyleBackground* aBackgroundStyle)
|
2012-11-19 07:28:18 +04:00
|
|
|
: nsDisplayImageContainer(aBuilder, aFrame)
|
2012-11-08 08:08:40 +04:00
|
|
|
, mBackgroundStyle(aBackgroundStyle)
|
2016-05-04 21:14:23 +03:00
|
|
|
, mBackgroundRect(aBackgroundRect)
|
2012-11-08 08:08:40 +04:00
|
|
|
, mLayer(aLayer)
|
2016-04-07 09:52:35 +03:00
|
|
|
, mIsRasterImage(false)
|
2010-07-24 13:35:29 +04:00
|
|
|
{
|
2012-11-10 03:14:59 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
|
2010-07-24 13:35:29 +04:00
|
|
|
|
2015-10-29 00:52:15 +03:00
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
|
2016-04-07 09:52:35 +03:00
|
|
|
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
2015-10-29 00:52:15 +03:00
|
|
|
|
2016-04-26 00:20:13 +03:00
|
|
|
bool isTransformedFixed;
|
2015-10-29 00:52:15 +03:00
|
|
|
nsBackgroundLayerState state =
|
2016-01-28 08:27:00 +03:00
|
|
|
nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags,
|
2016-05-04 21:14:23 +03:00
|
|
|
mBackgroundRect, mBackgroundRect, layer,
|
2016-04-26 00:20:13 +03:00
|
|
|
&isTransformedFixed);
|
|
|
|
mShouldTreatAsFixed = ComputeShouldTreatAsFixed(isTransformedFixed);
|
|
|
|
|
|
|
|
mBounds = GetBoundsInternal(aBuilder);
|
|
|
|
if (ShouldFixToViewport(aBuilder)) {
|
|
|
|
mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(this);
|
2016-05-17 00:14:29 +03:00
|
|
|
|
|
|
|
// Expand the item's visible rect to cover the entire bounds, limited to the
|
|
|
|
// viewport rect. This is necessary because the background's clip can move
|
|
|
|
// asynchronously.
|
|
|
|
if (Maybe<nsRect> viewportRect = GetViewportRectRelativeToReferenceFrame(aBuilder, mFrame)) {
|
|
|
|
mVisibleRect = mBounds.Intersect(*viewportRect);
|
|
|
|
}
|
2016-04-26 00:20:13 +03:00
|
|
|
}
|
2016-04-07 09:52:35 +03:00
|
|
|
|
|
|
|
mFillRect = state.mFillArea;
|
|
|
|
mDestRect = state.mDestArea;
|
|
|
|
|
|
|
|
nsImageRenderer* imageRenderer = &state.mImageRenderer;
|
|
|
|
// We only care about images here, not gradients.
|
|
|
|
if (imageRenderer->IsRasterImage()) {
|
|
|
|
mIsRasterImage = true;
|
|
|
|
mImage = imageRenderer->GetImage();
|
|
|
|
}
|
2010-07-24 13:35:29 +04:00
|
|
|
}
|
|
|
|
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
|
2012-08-19 23:33:25 +04:00
|
|
|
{
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
2012-11-10 03:14:59 +04:00
|
|
|
MOZ_COUNT_DTOR(nsDisplayBackgroundImage);
|
2012-08-19 23:33:25 +04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-05-08 07:47:31 +04:00
|
|
|
static nsStyleContext* GetBackgroundStyleContext(nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
nsStyleContext *sc;
|
|
|
|
if (!nsCSSRendering::FindBackground(aFrame, &sc)) {
|
|
|
|
// We don't want to bail out if moz-appearance is set on a root
|
|
|
|
// node. If it has a parent content node, bail because it's not
|
|
|
|
// a root, other wise keep going in order to let the theme stuff
|
|
|
|
// draw the background. The canvas really should be drawing the
|
|
|
|
// bg, but there's no way to hook that up via css.
|
|
|
|
if (!aFrame->StyleDisplay()->mAppearance) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
if (!content || content->GetParent()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
sc = aFrame->StyleContext();
|
|
|
|
}
|
|
|
|
return sc;
|
|
|
|
}
|
|
|
|
|
2014-07-23 09:22:17 +04:00
|
|
|
/* static */ void
|
|
|
|
SetBackgroundClipRegion(DisplayListClipState::AutoSaveRestore& aClipState,
|
|
|
|
nsIFrame* aFrame, const nsPoint& aToReferenceFrame,
|
2016-01-28 08:24:00 +03:00
|
|
|
const nsStyleImageLayers::Layer& aLayer,
|
2016-05-04 21:14:23 +03:00
|
|
|
const nsRect& aBackgroundRect,
|
2014-07-23 09:22:17 +04:00
|
|
|
bool aWillPaintBorder)
|
|
|
|
{
|
2016-01-28 08:27:00 +03:00
|
|
|
nsCSSRendering::ImageLayerClipState clip;
|
|
|
|
nsCSSRendering::GetImageLayerClip(aLayer, aFrame, *aFrame->StyleBorder(),
|
2016-05-04 21:14:23 +03:00
|
|
|
aBackgroundRect, aBackgroundRect, aWillPaintBorder,
|
2014-07-23 09:22:17 +04:00
|
|
|
aFrame->PresContext()->AppUnitsPerDevPixel(),
|
|
|
|
&clip);
|
|
|
|
|
|
|
|
if (clip.mHasAdditionalBGClipArea) {
|
|
|
|
aClipState.ClipContentDescendants(clip.mAdditionalBGClipArea, clip.mBGClipArea,
|
|
|
|
clip.mHasRoundedCorners ? clip.mRadii : nullptr);
|
|
|
|
} else {
|
|
|
|
aClipState.ClipContentDescendants(clip.mBGClipArea, clip.mHasRoundedCorners ? clip.mRadii : nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-15 06:18:30 +03:00
|
|
|
/**
|
|
|
|
* This is used for the find bar highlighter overlay. It's only accessible
|
|
|
|
* through the AnonymousContent API, so it's not exposed to general web pages.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
SpecialCutoutRegionCase(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
const nsRect& aBackgroundRect,
|
|
|
|
nsDisplayList* aList,
|
|
|
|
nscolor aColor)
|
|
|
|
{
|
|
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
if (!content) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* cutoutRegion = content->GetProperty(nsGkAtoms::cutoutregion);
|
|
|
|
if (!cutoutRegion) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_GET_A(aColor) == 0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRegion region;
|
|
|
|
region.Sub(aBackgroundRect, *static_cast<nsRegion*>(cutoutRegion));
|
|
|
|
region.MoveBy(aBuilder->ToReferenceFrame(aFrame));
|
|
|
|
aList->AppendNewToTop(
|
|
|
|
new (aBuilder) nsDisplaySolidColorRegion(aBuilder, aFrame, region, aColor));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-23 09:22:17 +04:00
|
|
|
|
2013-07-24 11:38:55 +04:00
|
|
|
/*static*/ bool
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame,
|
2016-05-04 21:14:23 +03:00
|
|
|
const nsRect& aBackgroundRect,
|
2016-04-28 21:09:06 +03:00
|
|
|
nsDisplayList* aList,
|
2016-10-22 04:13:28 +03:00
|
|
|
bool aAllowWillPaintBorderOptimization,
|
|
|
|
nsStyleContext* aStyleContext)
|
2012-09-13 14:34:23 +04:00
|
|
|
{
|
2016-10-22 04:13:28 +03:00
|
|
|
nsStyleContext* bgSC = aStyleContext;
|
2012-09-13 14:34:23 +04:00
|
|
|
const nsStyleBackground* bg = nullptr;
|
2016-05-04 21:14:23 +03:00
|
|
|
nsRect bgRect = aBackgroundRect + aBuilder->ToReferenceFrame(aFrame);
|
2012-09-13 14:34:23 +04:00
|
|
|
nsPresContext* presContext = aFrame->PresContext();
|
2012-11-08 08:08:40 +04:00
|
|
|
bool isThemed = aFrame->IsThemed();
|
2013-05-08 07:47:31 +04:00
|
|
|
if (!isThemed) {
|
2016-10-22 04:13:28 +03:00
|
|
|
if (!bgSC) {
|
|
|
|
bgSC = GetBackgroundStyleContext(aFrame);
|
|
|
|
}
|
2013-05-08 07:47:31 +04:00
|
|
|
if (bgSC) {
|
|
|
|
bg = bgSC->StyleBackground();
|
|
|
|
}
|
2012-09-13 14:34:23 +04:00
|
|
|
}
|
|
|
|
|
2012-10-25 09:32:25 +04:00
|
|
|
bool drawBackgroundColor = false;
|
2015-01-20 12:42:29 +03:00
|
|
|
// Dummy initialisation to keep Valgrind/Memcheck happy.
|
|
|
|
// See bug 1122375 comment 1.
|
|
|
|
nscolor color = NS_RGBA(0,0,0,0);
|
2012-10-25 09:32:25 +04:00
|
|
|
if (!nsCSSRendering::IsCanvasFrame(aFrame) && bg) {
|
|
|
|
bool drawBackgroundImage;
|
|
|
|
color =
|
|
|
|
nsCSSRendering::DetermineBackgroundColor(presContext, bgSC, aFrame,
|
|
|
|
drawBackgroundImage, drawBackgroundColor);
|
|
|
|
}
|
|
|
|
|
2016-09-15 06:18:30 +03:00
|
|
|
if (SpecialCutoutRegionCase(aBuilder, aFrame, aBackgroundRect, aList, color)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-12 10:53:03 +03:00
|
|
|
const nsStyleBorder* borderStyle = aFrame->StyleBorder();
|
2016-04-12 08:52:42 +03:00
|
|
|
const nsStyleEffects* effectsStyle = aFrame->StyleEffects();
|
|
|
|
bool hasInsetShadow = effectsStyle->mBoxShadow &&
|
|
|
|
effectsStyle->mBoxShadow->HasShadowWithInset(true);
|
2016-04-28 21:09:06 +03:00
|
|
|
bool willPaintBorder = aAllowWillPaintBorderOptimization &&
|
|
|
|
!isThemed && !hasInsetShadow &&
|
2014-11-12 10:53:03 +03:00
|
|
|
borderStyle->HasBorder();
|
2014-07-23 09:22:17 +04:00
|
|
|
|
|
|
|
nsPoint toRef = aBuilder->ToReferenceFrame(aFrame);
|
|
|
|
|
2013-11-08 19:08:03 +04:00
|
|
|
// An auxiliary list is necessary in case we have background blending; if that
|
|
|
|
// is the case, background items need to be wrapped by a blend container to
|
|
|
|
// isolate blending to the background
|
|
|
|
nsDisplayList bgItemList;
|
2012-11-27 16:50:09 +04:00
|
|
|
// Even if we don't actually have a background color to paint, we may still need
|
|
|
|
// to create an item for hit testing.
|
|
|
|
if ((drawBackgroundColor && color != NS_RGBA(0,0,0,0)) ||
|
|
|
|
aBuilder->IsForEventDelivery()) {
|
2014-07-23 09:22:17 +04:00
|
|
|
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
|
|
|
if (bg && !aBuilder->IsForEventDelivery()) {
|
2014-11-12 10:53:03 +03:00
|
|
|
// Disable the will-paint-border optimization for background
|
|
|
|
// colors with no border-radius. Enabling it for background colors
|
|
|
|
// doesn't help much (there are no tiling issues) and clipping the
|
|
|
|
// background breaks detection of the element's border-box being
|
|
|
|
// opaque. For nonzero border-radius we still need it because we
|
|
|
|
// want to inset the background if possible to avoid antialiasing
|
|
|
|
// artifacts along the rounded corners.
|
|
|
|
bool useWillPaintBorderOptimization = willPaintBorder &&
|
|
|
|
nsLayoutUtils::HasNonZeroCorner(borderStyle->mBorderRadius);
|
2014-07-23 09:22:17 +04:00
|
|
|
SetBackgroundClipRegion(clipState, aFrame, toRef,
|
2016-05-04 21:14:23 +03:00
|
|
|
bg->BottomLayer(), bgRect,
|
2014-11-12 10:53:03 +03:00
|
|
|
useWillPaintBorderOptimization);
|
2014-07-23 09:22:17 +04:00
|
|
|
}
|
2013-11-08 19:08:03 +04:00
|
|
|
bgItemList.AppendNewToTop(
|
2016-05-04 21:14:23 +03:00
|
|
|
new (aBuilder) nsDisplayBackgroundColor(aBuilder, aFrame, bgRect, bg,
|
2012-11-27 16:50:09 +04:00
|
|
|
drawBackgroundColor ? color : NS_RGBA(0, 0, 0, 0)));
|
|
|
|
}
|
2012-12-14 02:16:14 +04:00
|
|
|
|
|
|
|
if (isThemed) {
|
2014-08-20 19:26:11 +04:00
|
|
|
nsITheme* theme = presContext->GetTheme();
|
2015-05-26 20:55:08 +03:00
|
|
|
if (theme->NeedToClearBackgroundBehindWidget(aFrame, aFrame->StyleDisplay()->mAppearance) &&
|
2016-10-14 23:45:29 +03:00
|
|
|
aBuilder->IsInChromeDocumentOrPopup() && !aBuilder->IsInTransform()) {
|
2014-08-20 19:26:11 +04:00
|
|
|
bgItemList.AppendNewToTop(
|
|
|
|
new (aBuilder) nsDisplayClearBackground(aBuilder, aFrame));
|
|
|
|
}
|
2013-07-18 10:34:58 +04:00
|
|
|
nsDisplayThemedBackground* bgItem =
|
2016-05-04 21:14:23 +03:00
|
|
|
new (aBuilder) nsDisplayThemedBackground(aBuilder, aFrame, bgRect);
|
2013-11-08 19:08:03 +04:00
|
|
|
bgItemList.AppendNewToTop(bgItem);
|
|
|
|
aList->AppendToTop(&bgItemList);
|
2013-07-24 11:38:55 +04:00
|
|
|
return true;
|
2012-12-14 02:16:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!bg) {
|
2013-11-08 19:08:03 +04:00
|
|
|
aList->AppendToTop(&bgItemList);
|
2013-07-24 11:38:55 +04:00
|
|
|
return false;
|
2012-12-14 02:16:14 +04:00
|
|
|
}
|
2016-03-08 22:22:36 +03:00
|
|
|
|
|
|
|
const DisplayItemScrollClip* scrollClip =
|
|
|
|
aBuilder->ClipState().GetCurrentInnermostScrollClip();
|
2016-03-09 08:14:20 +03:00
|
|
|
|
2016-01-10 02:06:23 +03:00
|
|
|
bool needBlendContainer = false;
|
|
|
|
|
2012-09-13 14:34:23 +04:00
|
|
|
// Passing bg == nullptr in this macro will result in one iteration with
|
|
|
|
// i = 0.
|
2016-01-28 08:39:00 +03:00
|
|
|
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, bg->mImage) {
|
|
|
|
if (bg->mImage.mLayers[i].mImage.IsEmpty()) {
|
2012-12-14 02:16:14 +04:00
|
|
|
continue;
|
|
|
|
}
|
2013-11-08 19:08:03 +04:00
|
|
|
|
2016-01-28 08:39:00 +03:00
|
|
|
if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
|
2016-01-10 02:06:23 +03:00
|
|
|
needBlendContainer = true;
|
2013-11-08 19:08:03 +04:00
|
|
|
}
|
|
|
|
|
2014-07-23 09:22:17 +04:00
|
|
|
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
|
|
|
if (!aBuilder->IsForEventDelivery()) {
|
2016-01-28 08:39:00 +03:00
|
|
|
const nsStyleImageLayers::Layer& layer = bg->mImage.mLayers[i];
|
2014-07-23 09:22:17 +04:00
|
|
|
SetBackgroundClipRegion(clipState, aFrame, toRef,
|
2016-05-04 21:14:23 +03:00
|
|
|
layer, bgRect, willPaintBorder);
|
2014-07-23 09:22:17 +04:00
|
|
|
}
|
|
|
|
|
2016-03-08 22:22:36 +03:00
|
|
|
nsDisplayList thisItemList;
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage* bgItem =
|
2016-05-04 21:14:23 +03:00
|
|
|
new (aBuilder) nsDisplayBackgroundImage(aBuilder, aFrame, i, bgRect, bg);
|
2016-01-26 03:36:48 +03:00
|
|
|
|
|
|
|
if (bgItem->ShouldFixToViewport(aBuilder)) {
|
2016-03-08 22:22:36 +03:00
|
|
|
thisItemList.AppendNewToTop(
|
2016-01-26 03:36:48 +03:00
|
|
|
nsDisplayFixedPosition::CreateForFixedBackground(aBuilder, aFrame, bgItem, i));
|
|
|
|
} else {
|
2016-03-08 22:22:36 +03:00
|
|
|
thisItemList.AppendNewToTop(bgItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bg->mImage.mLayers[i].mBlendMode != NS_STYLE_BLEND_NORMAL) {
|
|
|
|
thisItemList.AppendNewToTop(
|
|
|
|
new (aBuilder) nsDisplayBlendMode(aBuilder, aFrame, &thisItemList,
|
|
|
|
bg->mImage.mLayers[i].mBlendMode,
|
|
|
|
scrollClip, i + 1));
|
2016-01-26 03:36:48 +03:00
|
|
|
}
|
2016-03-08 22:22:36 +03:00
|
|
|
bgItemList.AppendToTop(&thisItemList);
|
2013-11-08 19:08:03 +04:00
|
|
|
}
|
|
|
|
|
2016-01-10 02:06:23 +03:00
|
|
|
if (needBlendContainer) {
|
|
|
|
bgItemList.AppendNewToTop(
|
2016-05-10 03:48:59 +03:00
|
|
|
nsDisplayBlendContainer::CreateForBackgroundBlendMode(aBuilder, aFrame, &bgItemList, scrollClip));
|
2016-01-10 02:06:23 +03:00
|
|
|
}
|
|
|
|
|
2013-11-08 19:08:03 +04:00
|
|
|
aList->AppendToTop(&bgItemList);
|
2013-07-24 11:38:55 +04:00
|
|
|
return false;
|
2012-09-13 14:34:23 +04:00
|
|
|
}
|
|
|
|
|
2010-10-11 22:03:12 +04:00
|
|
|
// Check that the rounded border of aFrame, added to aToReferenceFrame,
|
|
|
|
// intersects aRect. Assumes that the unrounded border has already
|
|
|
|
// been checked for intersection.
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool
|
2010-10-11 22:03:12 +04:00
|
|
|
RoundedBorderIntersectsRect(nsIFrame* aFrame,
|
|
|
|
const nsPoint& aFrameToReferenceFrame,
|
|
|
|
const nsRect& aTestRect)
|
|
|
|
{
|
2011-01-04 13:40:02 +03:00
|
|
|
if (!nsRect(aFrameToReferenceFrame, aFrame->GetSize()).Intersects(aTestRect))
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2011-01-04 13:40:02 +03:00
|
|
|
|
2010-10-11 22:03:12 +04:00
|
|
|
nscoord radii[8];
|
|
|
|
return !aFrame->GetBorderRadii(radii) ||
|
2013-03-06 15:08:16 +04:00
|
|
|
nsLayoutUtils::RoundedRectIntersectsRect(nsRect(aFrameToReferenceFrame,
|
|
|
|
aFrame->GetSize()),
|
|
|
|
radii, aTestRect);
|
2010-10-11 22:03:12 +04:00
|
|
|
}
|
|
|
|
|
2009-04-24 13:24:44 +04:00
|
|
|
// Returns TRUE if aContainedRect is guaranteed to be contained in
|
|
|
|
// the rounded rect defined by aRoundedRect and aRadii. Complex cases are
|
|
|
|
// handled conservatively by returning FALSE in some situations where
|
|
|
|
// a more thorough analysis could return TRUE.
|
2010-10-11 22:03:12 +04:00
|
|
|
//
|
|
|
|
// See also RoundedRectIntersectsRect.
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
|
2012-11-15 05:35:18 +04:00
|
|
|
const nscoord aRadii[8],
|
|
|
|
const nsRect& aContainedRect) {
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect);
|
|
|
|
return rgn.Contains(aContainedRect);
|
2009-04-24 13:24:44 +04:00
|
|
|
}
|
|
|
|
|
2016-04-26 00:20:13 +03:00
|
|
|
bool
|
|
|
|
nsDisplayBackgroundImage::ShouldTreatAsFixed() const
|
|
|
|
{
|
|
|
|
return mShouldTreatAsFixed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayBackgroundImage::ComputeShouldTreatAsFixed(bool isTransformedFixed) const
|
|
|
|
{
|
|
|
|
if (!mBackgroundStyle)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
|
|
|
if (layer.mAttachment != NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// background-attachment:fixed is treated as background-attachment:scroll
|
|
|
|
// if it's affected by a transform.
|
|
|
|
// See https://www.w3.org/Bugs/Public/show_bug.cgi?id=17521.
|
|
|
|
return !isTransformedFixed;
|
|
|
|
}
|
|
|
|
|
2015-09-02 22:27:41 +03:00
|
|
|
bool
|
|
|
|
nsDisplayBackgroundImage::IsNonEmptyFixedImage() const
|
|
|
|
{
|
2016-04-26 00:20:13 +03:00
|
|
|
return ShouldTreatAsFixed() &&
|
2016-01-28 08:39:00 +03:00
|
|
|
!mBackgroundStyle->mImage.mLayers[mLayer].mImage.IsEmpty();
|
2015-09-02 22:27:41 +03:00
|
|
|
}
|
|
|
|
|
2014-08-06 09:19:25 +04:00
|
|
|
bool
|
2015-09-25 01:25:08 +03:00
|
|
|
nsDisplayBackgroundImage::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
|
2014-08-06 09:19:25 +04:00
|
|
|
{
|
2015-08-28 22:13:50 +03:00
|
|
|
// APZ needs background-attachment:fixed images layerized for correctness.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<LayerManager> layerManager = aBuilder->GetWidgetLayerManager();
|
2015-08-28 22:13:50 +03:00
|
|
|
if (!nsLayoutUtils::UsesAsyncScrolling(mFrame) &&
|
2015-09-25 01:25:08 +03:00
|
|
|
layerManager && layerManager->ShouldAvoidComponentAlphaLayers()) {
|
2014-08-06 09:19:25 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put background-attachment:fixed background images in their own
|
2015-08-28 22:13:50 +03:00
|
|
|
// compositing layer.
|
2015-09-02 22:27:41 +03:00
|
|
|
return IsNonEmptyFixedImage();
|
2014-08-06 09:19:25 +04:00
|
|
|
}
|
|
|
|
|
2012-05-04 00:13:12 +04:00
|
|
|
bool
|
2015-05-13 10:23:46 +03:00
|
|
|
nsDisplayBackgroundImage::CanOptimizeToImageLayer(LayerManager* aManager,
|
2012-11-28 06:34:45 +04:00
|
|
|
nsDisplayListBuilder* aBuilder)
|
2012-05-04 00:13:12 +04:00
|
|
|
{
|
2015-05-13 10:23:46 +03:00
|
|
|
if (!mBackgroundStyle) {
|
2012-05-04 00:13:12 +04:00
|
|
|
return false;
|
2015-05-13 10:23:46 +03:00
|
|
|
}
|
2012-05-04 00:13:12 +04:00
|
|
|
|
2015-12-03 19:36:40 +03:00
|
|
|
// We currently can't handle tiled backgrounds.
|
2016-04-07 09:52:35 +03:00
|
|
|
if (!mDestRect.Contains(mFillRect)) {
|
2015-12-03 19:36:40 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For 'contain' and 'cover', we allow any pixel of the image to be sampled
|
|
|
|
// because there isn't going to be any spriting/atlasing going on.
|
2016-04-07 09:52:35 +03:00
|
|
|
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
2015-12-03 19:36:40 +03:00
|
|
|
bool allowPartialImages =
|
2016-01-28 08:24:00 +03:00
|
|
|
(layer.mSize.mWidthType == nsStyleImageLayers::Size::eContain ||
|
|
|
|
layer.mSize.mWidthType == nsStyleImageLayers::Size::eCover);
|
2016-04-07 09:52:35 +03:00
|
|
|
if (!allowPartialImages && !mFillRect.Contains(mDestRect)) {
|
2012-05-04 00:13:12 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-07 09:52:35 +03:00
|
|
|
return nsDisplayImageContainer::CanOptimizeToImageLayer(aManager, aBuilder);
|
|
|
|
}
|
2012-05-04 00:13:12 +04:00
|
|
|
|
2016-04-07 09:52:35 +03:00
|
|
|
nsRect
|
|
|
|
nsDisplayBackgroundImage::GetDestRect()
|
|
|
|
{
|
|
|
|
return mDestRect;
|
|
|
|
}
|
2015-05-13 10:23:46 +03:00
|
|
|
|
2016-04-07 09:52:35 +03:00
|
|
|
already_AddRefed<imgIContainer>
|
|
|
|
nsDisplayBackgroundImage::GetImage()
|
|
|
|
{
|
|
|
|
nsCOMPtr<imgIContainer> image = mImage;
|
|
|
|
return image.forget();
|
2012-05-04 00:13:12 +04:00
|
|
|
}
|
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
nsDisplayBackgroundImage::ImageLayerization
|
|
|
|
nsDisplayBackgroundImage::ShouldCreateOwnLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager)
|
2012-05-04 00:13:12 +04:00
|
|
|
{
|
2016-11-24 08:11:30 +03:00
|
|
|
if (ForceActiveLayers()) {
|
|
|
|
return WHENEVER_POSSIBLE;
|
|
|
|
}
|
|
|
|
|
2015-10-22 23:38:46 +03:00
|
|
|
nsIFrame* backgroundStyleFrame = nsCSSRendering::FindBackgroundStyleFrame(mFrame);
|
2016-04-21 06:34:46 +03:00
|
|
|
if (ActiveLayerTracker::IsBackgroundPositionAnimated(aBuilder,
|
|
|
|
backgroundStyleFrame)) {
|
2015-10-22 23:38:46 +03:00
|
|
|
return WHENEVER_POSSIBLE;
|
|
|
|
}
|
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
if (nsLayoutUtils::AnimatedImageLayersEnabled() && mBackgroundStyle) {
|
2016-01-28 08:39:00 +03:00
|
|
|
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
2013-06-03 18:57:06 +04:00
|
|
|
const nsStyleImage* image = &layer.mImage;
|
|
|
|
if (image->GetType() == eStyleImageType_Image) {
|
|
|
|
imgIRequest* imgreq = image->GetImageData();
|
|
|
|
nsCOMPtr<imgIContainer> image;
|
2016-11-02 11:58:32 +03:00
|
|
|
if (imgreq &&
|
|
|
|
NS_SUCCEEDED(imgreq->GetImage(getter_AddRefs(image))) &&
|
|
|
|
image) {
|
2015-10-30 13:45:55 +03:00
|
|
|
bool animated = false;
|
|
|
|
if (NS_SUCCEEDED(image->GetAnimated(&animated)) && animated) {
|
|
|
|
return WHENEVER_POSSIBLE;
|
2013-06-03 18:57:06 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
if (nsLayoutUtils::GPUImageScalingEnabled() &&
|
|
|
|
aManager->IsCompositingCheap()) {
|
|
|
|
return ONLY_FOR_SCALING;
|
2012-05-04 00:13:12 +04:00
|
|
|
}
|
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
return NO_LAYER_NEEDED;
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerState
|
|
|
|
nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
|
|
|
ImageLayerization shouldLayerize = ShouldCreateOwnLayer(aBuilder, aManager);
|
|
|
|
if (shouldLayerize == NO_LAYER_NEEDED) {
|
|
|
|
// We can skip the call to CanOptimizeToImageLayer if we don't want a
|
|
|
|
// layer anyway.
|
2013-06-03 18:57:06 +04:00
|
|
|
return LAYER_NONE;
|
|
|
|
}
|
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
if (CanOptimizeToImageLayer(aManager, aBuilder)) {
|
|
|
|
if (shouldLayerize == WHENEVER_POSSIBLE) {
|
|
|
|
return LAYER_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(shouldLayerize == ONLY_FOR_SCALING, "unhandled ImageLayerization value?");
|
2015-05-13 10:23:46 +03:00
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
MOZ_ASSERT(mImage);
|
2015-05-13 10:23:46 +03:00
|
|
|
int32_t imageWidth;
|
|
|
|
int32_t imageHeight;
|
|
|
|
mImage->GetWidth(&imageWidth);
|
|
|
|
mImage->GetHeight(&imageHeight);
|
|
|
|
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
|
2016-04-07 09:52:35 +03:00
|
|
|
|
|
|
|
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(GetDestRect(), appUnitsPerDevPixel);
|
2012-05-04 00:13:12 +04:00
|
|
|
|
2016-04-07 09:52:35 +03:00
|
|
|
const LayerRect destLayerRect = destRect * aParameters.Scale();
|
2012-05-04 00:13:12 +04:00
|
|
|
|
2013-05-30 17:50:50 +04:00
|
|
|
// Calculate the scaling factor for the frame.
|
2015-05-13 10:23:46 +03:00
|
|
|
const gfxSize scale = gfxSize(destLayerRect.width / imageWidth,
|
|
|
|
destLayerRect.height / imageHeight);
|
2012-05-04 00:13:12 +04:00
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
if ((scale.width != 1.0f || scale.height != 1.0f) &&
|
|
|
|
(destLayerRect.width * destLayerRect.height >= 64 * 64)) {
|
|
|
|
// Separate this image into a layer.
|
|
|
|
// There's no point in doing this if we are not scaling at all or if the
|
|
|
|
// target size is pretty small.
|
|
|
|
return LAYER_ACTIVE;
|
2013-05-30 17:50:50 +04:00
|
|
|
}
|
2012-05-04 00:13:12 +04:00
|
|
|
}
|
|
|
|
|
2015-10-30 13:45:55 +03:00
|
|
|
return LAYER_NONE;
|
2012-05-04 00:13:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aParameters)
|
2012-05-04 00:13:12 +04:00
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ImageLayer> layer = static_cast<ImageLayer*>
|
2013-05-30 06:42:28 +04:00
|
|
|
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
|
|
|
|
if (!layer) {
|
|
|
|
layer = aManager->CreateImageLayer();
|
|
|
|
if (!layer)
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ImageContainer> imageContainer = GetContainer(aManager, aBuilder);
|
2015-05-13 10:23:46 +03:00
|
|
|
layer->SetContainer(imageContainer);
|
2015-04-08 04:55:28 +03:00
|
|
|
ConfigureLayer(layer, aParameters);
|
2012-05-04 00:13:12 +04:00
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
2010-10-11 22:03:12 +04:00
|
|
|
void
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aRect,
|
|
|
|
HitTestState* aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames)
|
2010-10-11 22:03:12 +04:00
|
|
|
{
|
2013-07-18 10:34:58 +04:00
|
|
|
if (RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
|
|
|
|
aOutFrames->AppendElement(mFrame);
|
2010-10-11 22:03:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion)
|
2010-07-16 01:08:06 +04:00
|
|
|
{
|
2014-06-23 08:24:51 +04:00
|
|
|
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2011-01-28 01:58:50 +03:00
|
|
|
}
|
2010-07-16 01:08:09 +04:00
|
|
|
|
2010-07-16 01:08:06 +04:00
|
|
|
// Return false if the background was propagated away from this
|
|
|
|
// frame. We don't want this display item to show up and confuse
|
|
|
|
// anything.
|
2013-07-18 10:34:58 +04:00
|
|
|
return mBackgroundStyle;
|
2010-07-16 01:08:06 +04:00
|
|
|
}
|
|
|
|
|
2012-10-25 09:32:25 +04:00
|
|
|
/* static */ nsRegion
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::GetInsideClipRegion(nsDisplayItem* aItem,
|
2016-01-06 03:08:17 +03:00
|
|
|
uint8_t aClip,
|
2016-05-04 21:14:23 +03:00
|
|
|
const nsRect& aRect,
|
|
|
|
const nsRect& aBackgroundRect)
|
2011-01-03 04:48:09 +03:00
|
|
|
{
|
|
|
|
nsRegion result;
|
|
|
|
if (aRect.IsEmpty())
|
|
|
|
return result;
|
|
|
|
|
2013-04-19 16:02:13 +04:00
|
|
|
nsIFrame *frame = aItem->Frame();
|
2012-10-25 09:32:25 +04:00
|
|
|
|
2016-05-04 21:14:23 +03:00
|
|
|
nsRect clipRect = aBackgroundRect;
|
2014-05-05 12:27:38 +04:00
|
|
|
if (frame->GetType() == nsGkAtoms::canvasFrame) {
|
|
|
|
nsCanvasFrame* canvasFrame = static_cast<nsCanvasFrame*>(frame);
|
|
|
|
clipRect = canvasFrame->CanvasArea() + aItem->ToReferenceFrame();
|
2016-05-04 21:14:23 +03:00
|
|
|
} else if (aClip == NS_STYLE_IMAGELAYER_CLIP_PADDING ||
|
|
|
|
aClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) {
|
|
|
|
nsMargin border = frame->GetUsedBorder();
|
|
|
|
if (aClip == NS_STYLE_IMAGELAYER_CLIP_CONTENT) {
|
|
|
|
border += frame->GetUsedPadding();
|
2014-05-05 12:27:38 +04:00
|
|
|
}
|
2016-05-04 21:14:23 +03:00
|
|
|
border.ApplySkipSides(frame->GetSkipSides());
|
|
|
|
clipRect.Deflate(border);
|
2011-01-03 04:48:09 +03:00
|
|
|
}
|
|
|
|
|
2014-07-23 09:22:17 +04:00
|
|
|
return clipRect.Intersect(aRect);
|
2011-01-03 04:48:09 +03:00
|
|
|
}
|
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
bool* aSnap) {
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion result;
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = false;
|
2006-01-26 05:29:17 +03:00
|
|
|
|
2012-11-08 08:08:40 +04:00
|
|
|
if (!mBackgroundStyle)
|
2011-01-03 04:48:09 +03:00
|
|
|
return result;
|
2012-11-08 08:08:40 +04:00
|
|
|
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = true;
|
|
|
|
|
2016-08-26 10:14:32 +03:00
|
|
|
// For StyleBoxDecorationBreak::Slice, don't try to optimize here, since
|
2011-01-03 04:48:09 +03:00
|
|
|
// this could easily lead to O(N^2) behavior inside InlineBackgroundData,
|
|
|
|
// which expects frames to be sent to it in content order, not reverse
|
|
|
|
// content order which we'll produce here.
|
|
|
|
// Of course, if there's only one frame in the flow, it doesn't matter.
|
2014-05-05 21:55:54 +04:00
|
|
|
if (mFrame->StyleBorder()->mBoxDecorationBreak ==
|
2016-08-26 10:14:32 +03:00
|
|
|
StyleBoxDecorationBreak::Clone ||
|
2011-01-03 04:48:09 +03:00
|
|
|
(!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
|
2016-01-28 08:39:00 +03:00
|
|
|
const nsStyleImageLayers::Layer& layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
2016-04-14 11:28:07 +03:00
|
|
|
if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL &&
|
2016-05-25 03:29:00 +03:00
|
|
|
layer.mRepeat.mXRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE &&
|
|
|
|
layer.mRepeat.mYRepeat != NS_STYLE_IMAGELAYER_REPEAT_SPACE &&
|
2016-04-14 11:28:07 +03:00
|
|
|
layer.mClip != NS_STYLE_IMAGELAYER_CLIP_TEXT) {
|
2016-05-04 21:14:23 +03:00
|
|
|
result = GetInsideClipRegion(this, layer.mClip, mBounds, mBackgroundRect);
|
2011-01-03 04:48:09 +03:00
|
|
|
}
|
2011-01-03 04:48:09 +03:00
|
|
|
}
|
2009-04-08 19:19:51 +04:00
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
return result;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2016-05-19 11:07:52 +03:00
|
|
|
Maybe<nscolor>
|
|
|
|
nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder) {
|
2012-11-08 08:08:40 +04:00
|
|
|
if (!mBackgroundStyle) {
|
2016-05-19 11:07:52 +03:00
|
|
|
return Some(NS_RGBA(0,0,0,0));
|
2010-05-13 04:56:11 +04:00
|
|
|
}
|
2016-05-19 11:07:52 +03:00
|
|
|
return Nothing();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2012-11-08 19:05:32 +04:00
|
|
|
nsRect
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::GetPositioningArea()
|
2012-11-08 19:05:32 +04:00
|
|
|
{
|
|
|
|
if (!mBackgroundStyle) {
|
|
|
|
return nsRect();
|
|
|
|
}
|
|
|
|
nsIFrame* attachedToFrame;
|
2016-04-26 00:20:13 +03:00
|
|
|
bool transformedFixed;
|
2016-01-28 08:27:00 +03:00
|
|
|
return nsCSSRendering::ComputeImageLayerPositioningArea(
|
2012-11-08 19:05:32 +04:00
|
|
|
mFrame->PresContext(), mFrame,
|
2016-05-04 21:14:23 +03:00
|
|
|
mBackgroundRect,
|
2016-01-28 08:39:00 +03:00
|
|
|
mBackgroundStyle->mImage.mLayers[mLayer],
|
2016-04-26 00:20:13 +03:00
|
|
|
&attachedToFrame,
|
|
|
|
&transformedFixed) + ToReferenceFrame();
|
2012-11-08 19:05:32 +04:00
|
|
|
}
|
|
|
|
|
2012-08-29 09:39:01 +04:00
|
|
|
bool
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
|
2012-08-29 09:39:01 +04:00
|
|
|
{
|
2012-11-08 08:08:40 +04:00
|
|
|
if (!mBackgroundStyle)
|
2012-08-29 09:39:01 +04:00
|
|
|
return false;
|
|
|
|
|
2012-11-08 19:05:32 +04:00
|
|
|
nscoord radii[8];
|
|
|
|
if (mFrame->GetBorderRadii(radii)) {
|
|
|
|
// A change in the size of the positioning area might change the position
|
|
|
|
// of the rounded corners.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-28 08:39:00 +03:00
|
|
|
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
2012-11-08 19:05:32 +04:00
|
|
|
if (layer.RenderingMightDependOnPositioningAreaSizeChange()) {
|
2012-10-25 09:32:25 +04:00
|
|
|
return true;
|
2012-08-29 09:39:01 +04:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-10-25 09:32:25 +04:00
|
|
|
static void CheckForBorderItem(nsDisplayItem *aItem, uint32_t& aFlags)
|
|
|
|
{
|
|
|
|
nsDisplayItem* nextItem = aItem->GetAbove();
|
|
|
|
while (nextItem && nextItem->GetType() == nsDisplayItem::TYPE_BACKGROUND) {
|
|
|
|
nextItem = nextItem->GetAbove();
|
|
|
|
}
|
2016-03-09 08:14:20 +03:00
|
|
|
if (nextItem &&
|
2013-04-19 16:02:13 +04:00
|
|
|
nextItem->Frame() == aItem->Frame() &&
|
2012-10-25 09:32:25 +04:00
|
|
|
nextItem->GetType() == nsDisplayItem::TYPE_BORDER) {
|
|
|
|
aFlags |= nsCSSRendering::PAINTBG_WILL_PAINT_BORDER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
void
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx) {
|
2014-07-23 09:22:17 +04:00
|
|
|
PaintInternal(aBuilder, aCtx, mVisibleRect, &mBounds);
|
2012-12-13 05:15:55 +04:00
|
|
|
}
|
2012-07-23 07:00:36 +04:00
|
|
|
|
2012-12-13 05:15:55 +04:00
|
|
|
void
|
|
|
|
nsDisplayBackgroundImage::PaintInternal(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx, const nsRect& aBounds,
|
|
|
|
nsRect* aClipRect) {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
|
2012-10-25 09:32:25 +04:00
|
|
|
CheckForBorderItem(this, flags);
|
2012-12-13 05:15:55 +04:00
|
|
|
|
2016-04-14 11:28:07 +03:00
|
|
|
gfxContext* ctx = aCtx->ThebesContext();
|
|
|
|
uint8_t clip = mBackgroundStyle->mImage.mLayers[mLayer].mClip;
|
|
|
|
|
|
|
|
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
|
2016-05-24 07:14:57 +03:00
|
|
|
if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
|
|
|
|
return;
|
|
|
|
}
|
2016-04-14 11:28:07 +03:00
|
|
|
}
|
|
|
|
|
2016-05-19 10:43:20 +03:00
|
|
|
nsCSSRendering::PaintBGParams params =
|
|
|
|
nsCSSRendering::PaintBGParams::ForSingleLayer(*mFrame->PresContext(),
|
|
|
|
*aCtx,
|
|
|
|
aBounds, mBackgroundRect,
|
|
|
|
mFrame, flags, mLayer,
|
|
|
|
CompositionOp::OP_OVER);
|
|
|
|
params.bgClipRect = aClipRect;
|
2015-10-23 05:54:48 +03:00
|
|
|
image::DrawResult result =
|
2016-05-19 10:43:20 +03:00
|
|
|
nsCSSRendering::PaintBackground(params);
|
2012-12-13 05:15:55 +04:00
|
|
|
|
2016-04-14 11:28:07 +03:00
|
|
|
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
|
2016-05-12 19:08:41 +03:00
|
|
|
ctx->PopGroupAndBlend();
|
2016-04-14 11:28:07 +03:00
|
|
|
}
|
|
|
|
|
2015-02-10 10:27:39 +03:00
|
|
|
nsDisplayBackgroundGeometry::UpdateDrawResult(this, result);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2012-11-10 03:14:59 +04:00
|
|
|
void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
2012-08-29 09:39:01 +04:00
|
|
|
{
|
2013-07-18 10:34:58 +04:00
|
|
|
if (!mBackgroundStyle) {
|
2012-08-29 09:39:01 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-11-08 19:05:32 +04:00
|
|
|
const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
|
|
|
|
|
2012-08-29 09:39:01 +04:00
|
|
|
bool snap;
|
2012-11-08 19:05:32 +04:00
|
|
|
nsRect bounds = GetBounds(aBuilder, &snap);
|
|
|
|
nsRect positioningArea = GetPositioningArea();
|
|
|
|
if (positioningArea.TopLeft() != geometry->mPositioningArea.TopLeft() ||
|
|
|
|
(positioningArea.Size() != geometry->mPositioningArea.Size() &&
|
|
|
|
RenderingMightDependOnPositioningAreaSizeChange())) {
|
|
|
|
// Positioning area changed in a way that could cause everything to change,
|
|
|
|
// so invalidate everything (both old and new painting areas).
|
|
|
|
aInvalidRegion->Or(bounds, geometry->mBounds);
|
2014-04-24 06:56:15 +04:00
|
|
|
|
|
|
|
if (positioningArea.Size() != geometry->mPositioningArea.Size()) {
|
|
|
|
NotifyRenderingChanged();
|
|
|
|
}
|
2012-11-08 19:05:32 +04:00
|
|
|
return;
|
|
|
|
}
|
2016-04-07 09:52:35 +03:00
|
|
|
if (!mDestRect.IsEqualInterior(geometry->mDestRect)) {
|
2015-10-29 00:52:15 +03:00
|
|
|
// Dest area changed in a way that could cause everything to change,
|
|
|
|
// so invalidate everything (both old and new painting areas).
|
|
|
|
aInvalidRegion->Or(bounds, geometry->mBounds);
|
|
|
|
NotifyRenderingChanged();
|
|
|
|
return;
|
|
|
|
}
|
2013-06-26 20:43:27 +04:00
|
|
|
if (aBuilder->ShouldSyncDecodeImages()) {
|
2016-01-28 08:39:00 +03:00
|
|
|
const nsStyleImage& image = mBackgroundStyle->mImage.mLayers[mLayer].mImage;
|
2015-02-10 10:27:39 +03:00
|
|
|
if (image.GetType() == eStyleImageType_Image &&
|
|
|
|
geometry->ShouldInvalidateToSyncDecodeImages()) {
|
2013-06-26 20:43:27 +04:00
|
|
|
aInvalidRegion->Or(*aInvalidRegion, bounds);
|
2014-04-24 06:56:15 +04:00
|
|
|
|
|
|
|
NotifyRenderingChanged();
|
2013-06-26 20:43:27 +04:00
|
|
|
}
|
|
|
|
}
|
2012-11-08 19:05:32 +04:00
|
|
|
if (!bounds.IsEqualInterior(geometry->mBounds)) {
|
|
|
|
// Positioning area is unchanged, so invalidate just the change in the
|
|
|
|
// painting area.
|
|
|
|
aInvalidRegion->Xor(bounds, geometry->mBounds);
|
2014-04-24 06:56:15 +04:00
|
|
|
|
|
|
|
NotifyRenderingChanged();
|
2012-08-29 09:39:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-18 08:26:38 +03:00
|
|
|
nsRect
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
2012-10-25 09:32:25 +04:00
|
|
|
*aSnap = true;
|
2012-11-28 08:05:32 +04:00
|
|
|
return mBounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
2013-06-04 08:49:03 +04:00
|
|
|
nsDisplayBackgroundImage::GetBoundsInternal(nsDisplayListBuilder* aBuilder) {
|
2011-01-04 13:39:47 +03:00
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
|
2012-11-08 08:08:40 +04:00
|
|
|
if (!mBackgroundStyle) {
|
2012-10-25 09:32:25 +04:00
|
|
|
return nsRect();
|
|
|
|
}
|
|
|
|
|
2016-05-04 21:14:23 +03:00
|
|
|
nsRect clipRect = mBackgroundRect;
|
2013-02-04 16:11:49 +04:00
|
|
|
if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
|
|
|
|
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
|
|
|
|
clipRect = frame->CanvasArea() + ToReferenceFrame();
|
2015-09-02 22:27:41 +03:00
|
|
|
} else if (nsLayoutUtils::UsesAsyncScrolling(mFrame) && IsNonEmptyFixedImage()) {
|
|
|
|
// If this is a background-attachment:fixed image, and APZ is enabled,
|
|
|
|
// async scrolling could reveal additional areas of the image, so don't
|
|
|
|
// clip it beyond clipping to the document's viewport.
|
2016-05-17 00:13:19 +03:00
|
|
|
if (Maybe<nsRect> viewportRect = GetViewportRectRelativeToReferenceFrame(aBuilder, mFrame)) {
|
|
|
|
clipRect = clipRect.Union(*viewportRect);
|
2015-09-02 22:27:41 +03:00
|
|
|
}
|
2013-02-04 16:11:49 +04:00
|
|
|
}
|
2016-01-28 08:39:00 +03:00
|
|
|
const nsStyleImageLayers::Layer& layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
2012-10-25 09:32:25 +04:00
|
|
|
return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
|
2016-05-04 21:14:23 +03:00
|
|
|
mBackgroundRect, clipRect, layer,
|
2013-06-04 08:49:03 +04:00
|
|
|
aBuilder->GetBackgroundPaintFlags());
|
2007-12-18 08:26:38 +03:00
|
|
|
}
|
|
|
|
|
2012-09-13 14:34:23 +04:00
|
|
|
uint32_t
|
2012-11-10 03:14:59 +04:00
|
|
|
nsDisplayBackgroundImage::GetPerFrameKey()
|
2012-09-13 14:34:23 +04:00
|
|
|
{
|
|
|
|
return (mLayer << nsDisplayItem::TYPE_BITS) |
|
|
|
|
nsDisplayItem::GetPerFrameKey();
|
|
|
|
}
|
|
|
|
|
2013-07-18 10:34:58 +04:00
|
|
|
nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder,
|
2016-05-04 21:14:23 +03:00
|
|
|
nsIFrame* aFrame,
|
|
|
|
const nsRect& aBackgroundRect)
|
2013-07-18 10:34:58 +04:00
|
|
|
: nsDisplayItem(aBuilder, aFrame)
|
2016-05-04 21:14:23 +03:00
|
|
|
, mBackgroundRect(aBackgroundRect)
|
2013-07-18 10:34:58 +04:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayThemedBackground);
|
|
|
|
|
|
|
|
const nsStyleDisplay* disp = mFrame->StyleDisplay();
|
|
|
|
mAppearance = disp->mAppearance;
|
|
|
|
mFrame->IsThemed(disp, &mThemeTransparency);
|
2013-06-13 01:42:00 +04:00
|
|
|
|
2013-07-18 10:34:58 +04:00
|
|
|
// Perform necessary RegisterThemeGeometry
|
2015-02-05 01:25:18 +03:00
|
|
|
nsITheme* theme = mFrame->PresContext()->GetTheme();
|
|
|
|
nsITheme::ThemeGeometryType type =
|
|
|
|
theme->ThemeGeometryTypeForWidget(mFrame, disp->mAppearance);
|
|
|
|
if (type != nsITheme::eThemeGeometryTypeUnknown) {
|
|
|
|
RegisterThemeGeometry(aBuilder, aFrame, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
|
|
|
|
disp->mAppearance == NS_THEME_WIN_GLASS) {
|
|
|
|
aBuilder->SetGlassDisplayItem(this);
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
mBounds = GetBoundsInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDisplayThemedBackground::~nsDisplayThemedBackground()
|
|
|
|
{
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayThemedBackground);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-11-25 16:45:19 +03:00
|
|
|
nsDisplayThemedBackground::WriteDebugInfo(std::stringstream& aStream)
|
2013-07-18 10:34:58 +04:00
|
|
|
{
|
2014-11-25 16:45:19 +03:00
|
|
|
aStream << " (themed, appearance:" << (int)mAppearance << ")";
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayThemedBackground::HitTest(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aRect,
|
|
|
|
HitTestState* aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames)
|
|
|
|
{
|
2016-05-04 21:14:23 +03:00
|
|
|
// Assume that any point in our background rect is a hit.
|
|
|
|
if (mBackgroundRect.Intersects(aRect)) {
|
2013-07-18 10:34:58 +04:00
|
|
|
aOutFrames->AppendElement(mFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRegion
|
|
|
|
nsDisplayThemedBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
bool* aSnap) {
|
|
|
|
nsRegion result;
|
|
|
|
*aSnap = false;
|
|
|
|
|
|
|
|
if (mThemeTransparency == nsITheme::eOpaque) {
|
2016-05-04 21:14:23 +03:00
|
|
|
result = mBackgroundRect;
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-05-19 11:07:52 +03:00
|
|
|
Maybe<nscolor>
|
|
|
|
nsDisplayThemedBackground::IsUniform(nsDisplayListBuilder* aBuilder) {
|
2013-07-18 10:34:58 +04:00
|
|
|
if (mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
|
|
|
|
mAppearance == NS_THEME_WIN_GLASS) {
|
2016-05-19 11:07:52 +03:00
|
|
|
return Some(NS_RGBA(0,0,0,0));
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
2016-05-19 11:07:52 +03:00
|
|
|
return Nothing();
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
|
|
|
|
2014-10-24 20:32:23 +04:00
|
|
|
bool
|
2016-01-06 03:08:17 +03:00
|
|
|
nsDisplayThemedBackground::ProvidesFontSmoothingBackgroundColor(nscolor* aColor)
|
2014-10-24 20:32:23 +04:00
|
|
|
{
|
|
|
|
nsITheme* theme = mFrame->PresContext()->GetTheme();
|
|
|
|
return theme->WidgetProvidesFontSmoothingBackgroundColor(mFrame, mAppearance, aColor);
|
|
|
|
}
|
|
|
|
|
2013-07-18 10:34:58 +04:00
|
|
|
nsRect
|
|
|
|
nsDisplayThemedBackground::GetPositioningArea()
|
|
|
|
{
|
2016-05-04 21:14:23 +03:00
|
|
|
return mBackgroundRect;
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayThemedBackground::Paint(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx)
|
|
|
|
{
|
|
|
|
PaintInternal(aBuilder, aCtx, mVisibleRect, nullptr);
|
|
|
|
}
|
|
|
|
|
2014-02-13 04:20:41 +04:00
|
|
|
|
2013-07-18 10:34:58 +04:00
|
|
|
void
|
|
|
|
nsDisplayThemedBackground::PaintInternal(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx, const nsRect& aBounds,
|
|
|
|
nsRect* aClipRect)
|
|
|
|
{
|
|
|
|
// XXXzw this ignores aClipRect.
|
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
nsITheme *theme = presContext->GetTheme();
|
2016-05-04 21:14:23 +03:00
|
|
|
nsRect drawing(mBackgroundRect);
|
2013-07-18 10:34:58 +04:00
|
|
|
theme->GetWidgetOverflow(presContext->DeviceContext(), mFrame, mAppearance,
|
|
|
|
&drawing);
|
|
|
|
drawing.IntersectRect(drawing, aBounds);
|
2016-05-04 21:14:23 +03:00
|
|
|
theme->DrawWidgetBackground(aCtx, mFrame, mAppearance, mBackgroundRect, drawing);
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
|
|
|
|
2013-09-27 19:24:32 +04:00
|
|
|
bool nsDisplayThemedBackground::IsWindowActive()
|
|
|
|
{
|
2014-04-03 08:18:36 +04:00
|
|
|
EventStates docState = mFrame->GetContent()->OwnerDoc()->GetDocumentState();
|
2013-09-27 19:24:32 +04:00
|
|
|
return !docState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
|
|
|
|
}
|
|
|
|
|
2013-07-18 10:34:58 +04:00
|
|
|
void nsDisplayThemedBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
|
|
|
{
|
|
|
|
const nsDisplayThemedBackgroundGeometry* geometry = static_cast<const nsDisplayThemedBackgroundGeometry*>(aGeometry);
|
|
|
|
|
|
|
|
bool snap;
|
|
|
|
nsRect bounds = GetBounds(aBuilder, &snap);
|
|
|
|
nsRect positioningArea = GetPositioningArea();
|
|
|
|
if (!positioningArea.IsEqualInterior(geometry->mPositioningArea)) {
|
|
|
|
// Invalidate everything (both old and new painting areas).
|
|
|
|
aInvalidRegion->Or(bounds, geometry->mBounds);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!bounds.IsEqualInterior(geometry->mBounds)) {
|
|
|
|
// Positioning area is unchanged, so invalidate just the change in the
|
|
|
|
// painting area.
|
|
|
|
aInvalidRegion->Xor(bounds, geometry->mBounds);
|
|
|
|
}
|
2013-09-27 19:24:32 +04:00
|
|
|
nsITheme* theme = mFrame->PresContext()->GetTheme();
|
|
|
|
if (theme->WidgetAppearanceDependsOnWindowFocus(mAppearance) &&
|
|
|
|
IsWindowActive() != geometry->mWindowIsActive) {
|
|
|
|
aInvalidRegion->Or(*aInvalidRegion, bounds);
|
|
|
|
}
|
2013-07-18 10:34:58 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsDisplayThemedBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
|
|
|
*aSnap = true;
|
|
|
|
return mBounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsDisplayThemedBackground::GetBoundsInternal() {
|
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
|
2016-05-04 21:14:23 +03:00
|
|
|
nsRect r = mBackgroundRect - ToReferenceFrame();
|
2013-07-18 10:34:58 +04:00
|
|
|
presContext->GetTheme()->
|
|
|
|
GetWidgetOverflow(presContext->DeviceContext(), mFrame,
|
|
|
|
mFrame->StyleDisplay()->mAppearance, &r);
|
|
|
|
return r + ToReferenceFrame();
|
|
|
|
}
|
|
|
|
|
2016-04-07 09:54:33 +03:00
|
|
|
void
|
|
|
|
nsDisplayImageContainer::ConfigureLayer(ImageLayer* aLayer,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
2016-05-25 19:01:18 +03:00
|
|
|
aLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(mFrame));
|
2016-04-07 09:54:33 +03:00
|
|
|
|
|
|
|
nsCOMPtr<imgIContainer> image = GetImage();
|
|
|
|
MOZ_ASSERT(image);
|
|
|
|
int32_t imageWidth;
|
|
|
|
int32_t imageHeight;
|
|
|
|
image->GetWidth(&imageWidth);
|
|
|
|
image->GetHeight(&imageHeight);
|
|
|
|
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
|
|
|
|
|
|
|
|
if (imageWidth > 0 && imageHeight > 0) {
|
|
|
|
// We're actually using the ImageContainer. Let our frame know that it
|
|
|
|
// should consider itself to have painted successfully.
|
|
|
|
nsDisplayBackgroundGeometry::UpdateDrawResult(this,
|
|
|
|
image::DrawResult::SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX(seth): Right now we ignore aParameters.Scale() and
|
|
|
|
// aParameters.Offset(), because FrameLayerBuilder already applies
|
|
|
|
// aParameters.Scale() via the layer's post-transform, and
|
|
|
|
// aParameters.Offset() is always zero.
|
|
|
|
MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0));
|
|
|
|
|
|
|
|
// It's possible (for example, due to downscale-during-decode) that the
|
|
|
|
// ImageContainer this ImageLayer is holding has a different size from the
|
|
|
|
// intrinsic size of the image. For this reason we compute the transform using
|
|
|
|
// the ImageContainer's size rather than the image's intrinsic size.
|
|
|
|
// XXX(seth): In reality, since the size of the ImageContainer may change
|
|
|
|
// asynchronously, this is not enough. Bug 1183378 will provide a more
|
|
|
|
// complete fix, but this solution is safe in more cases than simply relying
|
|
|
|
// on the intrinsic size.
|
|
|
|
IntSize containerSize = aLayer->GetContainer()
|
|
|
|
? aLayer->GetContainer()->GetCurrentSize()
|
|
|
|
: IntSize(imageWidth, imageHeight);
|
|
|
|
|
|
|
|
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
const LayoutDeviceRect destRect =
|
|
|
|
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
|
|
|
|
|
|
|
|
const LayoutDevicePoint p = destRect.TopLeft();
|
|
|
|
Matrix transform = Matrix::Translation(p.x, p.y);
|
|
|
|
transform.PreScale(destRect.width / containerSize.width,
|
|
|
|
destRect.height / containerSize.height);
|
|
|
|
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
|
|
|
}
|
|
|
|
|
2016-04-07 09:53:15 +03:00
|
|
|
already_AddRefed<ImageContainer>
|
|
|
|
nsDisplayImageContainer::GetContainer(LayerManager* aManager,
|
|
|
|
nsDisplayListBuilder *aBuilder)
|
|
|
|
{
|
|
|
|
nsCOMPtr<imgIContainer> image = GetImage();
|
|
|
|
if (!image) {
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Must call CanOptimizeToImage() and get true "
|
|
|
|
"before calling GetContainer()");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-11-25 08:48:04 +03:00
|
|
|
uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
|
|
|
|
if (aBuilder->ShouldSyncDecodeImages()) {
|
|
|
|
flags |= imgIContainer::FLAG_SYNC_DECODE;
|
|
|
|
}
|
2016-04-07 09:53:15 +03:00
|
|
|
|
|
|
|
return image->GetImageContainer(aManager, flags);
|
|
|
|
}
|
|
|
|
|
2016-04-07 09:52:35 +03:00
|
|
|
bool
|
|
|
|
nsDisplayImageContainer::CanOptimizeToImageLayer(LayerManager* aManager,
|
|
|
|
nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
|
|
|
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
|
|
|
|
? imgIContainer::FLAG_SYNC_DECODE
|
|
|
|
: imgIContainer::FLAG_NONE;
|
|
|
|
|
|
|
|
nsCOMPtr<imgIContainer> image = GetImage();
|
|
|
|
if (!image) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!image->IsImageContainerAvailable(aManager, flags)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t imageWidth;
|
|
|
|
int32_t imageHeight;
|
|
|
|
image->GetWidth(&imageWidth);
|
|
|
|
image->GetHeight(&imageHeight);
|
|
|
|
|
|
|
|
if (imageWidth == 0 || imageHeight == 0) {
|
|
|
|
NS_ASSERTION(false, "invalid image size");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
const LayoutDeviceRect destRect =
|
|
|
|
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
|
|
|
|
|
|
|
|
// Calculate the scaling factor for the frame.
|
|
|
|
const gfxSize scale = gfxSize(destRect.width / imageWidth,
|
|
|
|
destRect.height / imageHeight);
|
|
|
|
|
2016-04-07 09:54:57 +03:00
|
|
|
if (scale.width < 0.34 || scale.height < 0.34) {
|
2016-04-07 09:52:35 +03:00
|
|
|
// This would look awful as long as we can't use high-quality downscaling
|
|
|
|
// for image layers (bug 803703), so don't turn this into an image layer.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-02-20 04:04:09 +03:00
|
|
|
void
|
2014-06-14 19:10:45 +04:00
|
|
|
nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder,
|
|
|
|
float aOpacity,
|
|
|
|
const DisplayItemClip* aClip)
|
|
|
|
{
|
2015-02-20 04:04:09 +03:00
|
|
|
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
|
2014-06-14 19:10:45 +04:00
|
|
|
mColor.a = mColor.a * aOpacity;
|
|
|
|
if (aClip) {
|
|
|
|
IntersectClip(aBuilder, *aClip);
|
|
|
|
}
|
2015-02-20 04:04:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayBackgroundColor::CanApplyOpacity() const
|
|
|
|
{
|
2014-06-14 19:10:45 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-11-24 08:11:29 +03:00
|
|
|
LayerState
|
|
|
|
nsDisplayBackgroundColor::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
|
|
|
uint8_t clip = mBackgroundStyle->mImage.mLayers[0].mClip;
|
|
|
|
if (!ForceActiveLayers() || clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
|
|
|
|
return LAYER_NONE;
|
|
|
|
}
|
|
|
|
return LAYER_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayBackgroundColor::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
|
|
|
{
|
|
|
|
if (mColor == Color()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<ColorLayer> layer = static_cast<ColorLayer*>
|
|
|
|
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
|
|
|
|
if (!layer) {
|
|
|
|
layer = aManager->CreateColorLayer();
|
|
|
|
if (!layer)
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
layer->SetColor(mColor);
|
|
|
|
|
|
|
|
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
layer->SetBounds(mBackgroundRect.ToNearestPixels(appUnitsPerDevPixel));
|
|
|
|
layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
|
|
|
|
aContainerParameters.mOffset.y, 0));
|
|
|
|
|
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
2012-10-25 09:32:25 +04:00
|
|
|
void
|
|
|
|
nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
|
2014-06-14 19:10:45 +04:00
|
|
|
nsRenderingContext* aCtx)
|
2012-10-25 09:32:25 +04:00
|
|
|
{
|
2015-09-24 10:46:32 +03:00
|
|
|
if (mColor == Color()) {
|
2012-10-25 09:32:25 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-10 19:14:14 +03:00
|
|
|
#if 0
|
|
|
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1148418#c21 for why this
|
|
|
|
// results in a precision induced rounding issue that makes the rect one
|
|
|
|
// pixel shorter in rare cases. Disabled in favor of the old code for now.
|
|
|
|
// Note that the pref layout.css.devPixelsPerPx needs to be set to 1 to
|
|
|
|
// reproduce the bug.
|
2016-04-14 11:28:07 +03:00
|
|
|
//
|
|
|
|
// TODO:
|
|
|
|
// This new path does not include support for background-clip:text; need to
|
|
|
|
// be fixed if/when we switch to this new code path.
|
|
|
|
|
2015-05-10 19:35:26 +03:00
|
|
|
DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
|
|
|
|
|
2016-05-04 21:14:23 +03:00
|
|
|
Rect rect = NSRectToSnappedRect(mBackgroundRect,
|
2014-11-24 03:04:33 +03:00
|
|
|
mFrame->PresContext()->AppUnitsPerDevPixel(),
|
|
|
|
aDrawTarget);
|
|
|
|
ColorPattern color(ToDeviceColor(mColor));
|
|
|
|
aDrawTarget.FillRect(rect, color);
|
2015-05-10 19:14:14 +03:00
|
|
|
#else
|
|
|
|
gfxContext* ctx = aCtx->ThebesContext();
|
2016-05-12 19:09:16 +03:00
|
|
|
gfxRect bounds =
|
|
|
|
nsLayoutUtils::RectToGfxRect(mBackgroundRect,
|
|
|
|
mFrame->PresContext()->AppUnitsPerDevPixel());
|
2015-05-10 19:14:14 +03:00
|
|
|
|
2016-04-14 11:28:07 +03:00
|
|
|
uint8_t clip = mBackgroundStyle->mImage.mLayers[0].mClip;
|
|
|
|
if (clip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
|
2016-05-24 07:14:57 +03:00
|
|
|
if (!GenerateAndPushTextMask(mFrame, aCtx, mBackgroundRect, aBuilder)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-14 11:28:07 +03:00
|
|
|
ctx->SetColor(mColor);
|
2016-05-12 19:09:16 +03:00
|
|
|
ctx->Rectangle(bounds, true);
|
2016-04-14 11:28:07 +03:00
|
|
|
ctx->Fill();
|
2016-05-12 19:08:41 +03:00
|
|
|
ctx->PopGroupAndBlend();
|
2016-04-14 11:28:07 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-10 19:14:14 +03:00
|
|
|
ctx->SetColor(mColor);
|
|
|
|
ctx->NewPath();
|
|
|
|
ctx->Rectangle(bounds, true);
|
|
|
|
ctx->Fill();
|
|
|
|
#endif
|
2012-10-25 09:32:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRegion
|
|
|
|
nsDisplayBackgroundColor::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
2014-06-14 19:10:45 +04:00
|
|
|
bool* aSnap)
|
2012-10-25 09:32:25 +04:00
|
|
|
{
|
2016-01-05 07:38:17 +03:00
|
|
|
*aSnap = false;
|
|
|
|
|
2014-06-14 19:10:45 +04:00
|
|
|
if (mColor.a != 1) {
|
2012-10-25 09:32:25 +04:00
|
|
|
return nsRegion();
|
|
|
|
}
|
|
|
|
|
2012-11-08 08:08:40 +04:00
|
|
|
if (!mBackgroundStyle)
|
2012-10-25 09:32:25 +04:00
|
|
|
return nsRegion();
|
|
|
|
|
|
|
|
|
2016-01-28 08:24:00 +03:00
|
|
|
const nsStyleImageLayers::Layer& bottomLayer = mBackgroundStyle->BottomLayer();
|
2016-05-16 17:31:02 +03:00
|
|
|
if (bottomLayer.mClip == NS_STYLE_IMAGELAYER_CLIP_TEXT) {
|
|
|
|
return nsRegion();
|
|
|
|
}
|
|
|
|
|
|
|
|
*aSnap = true;
|
2015-12-07 04:15:53 +03:00
|
|
|
return nsDisplayBackgroundImage::GetInsideClipRegion(this, bottomLayer.mClip,
|
2016-05-04 21:14:23 +03:00
|
|
|
mBackgroundRect, mBackgroundRect);
|
2012-10-25 09:32:25 +04:00
|
|
|
}
|
|
|
|
|
2016-05-19 11:07:52 +03:00
|
|
|
Maybe<nscolor>
|
|
|
|
nsDisplayBackgroundColor::IsUniform(nsDisplayListBuilder* aBuilder)
|
2012-10-25 09:32:25 +04:00
|
|
|
{
|
2016-05-19 11:07:52 +03:00
|
|
|
return Some(mColor.ToABGR());
|
2012-10-25 09:32:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayBackgroundColor::HitTest(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aRect,
|
|
|
|
HitTestState* aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames)
|
|
|
|
{
|
|
|
|
if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
|
|
|
|
// aRect doesn't intersect our border-radius curve.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aOutFrames->AppendElement(mFrame);
|
|
|
|
}
|
|
|
|
|
2014-01-27 02:07:08 +04:00
|
|
|
void
|
2014-11-25 16:45:19 +03:00
|
|
|
nsDisplayBackgroundColor::WriteDebugInfo(std::stringstream& aStream)
|
2014-01-27 02:07:08 +04:00
|
|
|
{
|
2014-11-25 16:45:19 +03:00
|
|
|
aStream << " (rgba " << mColor.r << "," << mColor.g << ","
|
|
|
|
<< mColor.b << "," << mColor.a << ")";
|
2014-01-27 02:07:08 +04:00
|
|
|
}
|
|
|
|
|
2014-08-20 19:16:41 +04:00
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayClearBackground::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ColorLayer> layer = static_cast<ColorLayer*>
|
2014-08-20 19:16:41 +04:00
|
|
|
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
|
|
|
|
if (!layer) {
|
|
|
|
layer = aManager->CreateColorLayer();
|
|
|
|
if (!layer)
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-09-25 04:16:45 +03:00
|
|
|
layer->SetColor(Color());
|
2014-08-20 19:16:41 +04:00
|
|
|
layer->SetMixBlendMode(gfx::CompositionOp::OP_SOURCE);
|
|
|
|
|
|
|
|
bool snap;
|
|
|
|
nsRect bounds = GetBounds(aBuilder, &snap);
|
|
|
|
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
layer->SetBounds(bounds.ToNearestPixels(appUnitsPerDevPixel)); // XXX Do we need to respect the parent layer's scale here?
|
|
|
|
|
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
nsRect
|
2012-04-10 15:24:18 +04:00
|
|
|
nsDisplayOutline::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
|
|
|
*aSnap = false;
|
2010-11-17 05:20:25 +03:00
|
|
|
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder,
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* aCtx) {
|
2006-01-26 05:29:17 +03:00
|
|
|
// TODO join outlines together
|
2010-08-13 14:01:58 +04:00
|
|
|
nsPoint offset = ToReferenceFrame();
|
2007-03-31 01:11:41 +04:00
|
|
|
nsCSSRendering::PaintOutline(mFrame->PresContext(), *aCtx, mFrame,
|
2009-09-07 04:35:14 +04:00
|
|
|
mVisibleRect,
|
|
|
|
nsRect(offset, mFrame->GetSize()),
|
2013-02-16 09:38:33 +04:00
|
|
|
mFrame->StyleContext());
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2014-06-03 16:48:16 +04:00
|
|
|
nsDisplayOutline::IsInvisibleInRect(const nsRect& aRect)
|
|
|
|
{
|
2013-02-17 01:51:02 +04:00
|
|
|
const nsStyleOutline* outline = mFrame->StyleOutline();
|
2010-08-13 14:01:58 +04:00
|
|
|
nsRect borderBox(ToReferenceFrame(), mFrame->GetSize());
|
2014-06-03 16:48:16 +04:00
|
|
|
if (borderBox.Contains(aRect) &&
|
2008-10-01 09:50:52 +04:00
|
|
|
!nsLayoutUtils::HasNonZeroCorner(outline->mOutlineRadius)) {
|
2008-09-13 07:45:37 +04:00
|
|
|
if (outline->mOutlineOffset >= 0) {
|
2014-06-03 16:48:16 +04:00
|
|
|
// aRect is entirely inside the border-rect, and the outline isn't
|
|
|
|
// rendered inside the border-rect, so the outline is not visible.
|
|
|
|
return true;
|
2006-09-20 01:58:52 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-03 16:48:16 +04:00
|
|
|
return false;
|
2006-09-20 01:58:52 +04:00
|
|
|
}
|
|
|
|
|
2010-10-11 22:03:12 +04:00
|
|
|
void
|
|
|
|
nsDisplayEventReceiver::HitTest(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aRect,
|
|
|
|
HitTestState* aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames)
|
|
|
|
{
|
|
|
|
if (!RoundedBorderIntersectsRect(mFrame, ToReferenceFrame(), aRect)) {
|
|
|
|
// aRect doesn't intersect our border-radius curve.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aOutFrames->AppendElement(mFrame);
|
|
|
|
}
|
|
|
|
|
2013-12-16 15:22:11 +04:00
|
|
|
void
|
|
|
|
nsDisplayLayerEventRegions::AddFrame(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aBuilder->FindReferenceFrameFor(aFrame) == aBuilder->FindReferenceFrameFor(mFrame),
|
|
|
|
"Reference frame mismatch");
|
2015-02-03 18:52:51 +03:00
|
|
|
if (aBuilder->IsInsidePointerEventsNoneDoc()) {
|
|
|
|
// Somewhere up the parent document chain is a subdocument with pointer-
|
2016-10-05 15:27:02 +03:00
|
|
|
// events:none set on it.
|
2015-02-03 18:52:51 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-01-15 18:37:54 +03:00
|
|
|
if (!aFrame->GetParent()) {
|
|
|
|
MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::viewportFrame);
|
2015-06-08 21:30:40 +03:00
|
|
|
// Viewport frames are never event targets, other frames, like canvas frames,
|
|
|
|
// are the event targets for any regions viewport frames may cover.
|
|
|
|
return;
|
2015-01-15 18:37:54 +03:00
|
|
|
}
|
2016-03-10 01:29:41 +03:00
|
|
|
|
2016-04-12 08:52:41 +03:00
|
|
|
uint8_t pointerEvents =
|
|
|
|
aFrame->StyleUserInterface()->GetEffectivePointerEvents(aFrame);
|
2013-12-16 15:22:11 +04:00
|
|
|
if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-10 01:29:41 +03:00
|
|
|
bool simpleRegions = aFrame->HasAnyStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
|
|
|
|
if (!simpleRegions) {
|
|
|
|
if (!aFrame->StyleVisibility()->IsVisible()) {
|
|
|
|
return;
|
|
|
|
}
|
2014-11-25 23:26:48 +03:00
|
|
|
}
|
2013-12-16 15:22:11 +04:00
|
|
|
// XXX handle other pointerEvents values for SVG
|
2015-02-05 16:25:49 +03:00
|
|
|
|
2013-12-16 15:22:11 +04:00
|
|
|
// XXX Do something clever here for the common case where the border box
|
|
|
|
// is obviously entirely inside mHitRegion.
|
2015-02-05 16:25:49 +03:00
|
|
|
nsRect borderBox;
|
|
|
|
if (nsLayoutUtils::GetScrollableFrameFor(aFrame)) {
|
|
|
|
// If the frame is content of a scrollframe, then we need to pick up the
|
|
|
|
// area corresponding to the overflow rect as well. Otherwise the parts of
|
|
|
|
// the overflow that are not occupied by descendants get skipped and the
|
|
|
|
// APZ code sends touch events to the content underneath instead.
|
|
|
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1127773#c15.
|
|
|
|
borderBox = aFrame->GetScrollableOverflowRect();
|
|
|
|
} else {
|
|
|
|
borderBox = nsRect(nsPoint(0, 0), aFrame->GetSize());
|
|
|
|
}
|
|
|
|
borderBox += aBuilder->ToReferenceFrame(aFrame);
|
|
|
|
|
2016-03-10 01:29:41 +03:00
|
|
|
bool borderBoxHasRoundedCorners = false;
|
|
|
|
if (!simpleRegions) {
|
|
|
|
if (nsLayoutUtils::HasNonZeroCorner(aFrame->StyleBorder()->mBorderRadius)) {
|
|
|
|
borderBoxHasRoundedCorners = true;
|
|
|
|
} else {
|
|
|
|
aFrame->AddStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-16 15:22:11 +04:00
|
|
|
const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
|
|
|
|
if (clip) {
|
|
|
|
borderBox = clip->ApplyNonRoundedIntersection(borderBox);
|
|
|
|
if (clip->GetRoundedRectCount() > 0) {
|
|
|
|
borderBoxHasRoundedCorners = true;
|
|
|
|
}
|
|
|
|
}
|
2016-03-10 01:29:41 +03:00
|
|
|
|
2013-12-16 15:22:11 +04:00
|
|
|
if (borderBoxHasRoundedCorners ||
|
|
|
|
(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
|
|
|
mMaybeHitRegion.Or(mMaybeHitRegion, borderBox);
|
|
|
|
} else {
|
|
|
|
mHitRegion.Or(mHitRegion, borderBox);
|
|
|
|
}
|
2015-10-20 12:39:34 +03:00
|
|
|
|
|
|
|
if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
|
|
|
|
aBuilder->GetAncestorHasApzAwareEventHandler())
|
|
|
|
{
|
|
|
|
// Scrollbars may be painted into a layer below the actual layer they will
|
|
|
|
// scroll, and therefore wheel events may be dispatched to the outer frame
|
|
|
|
// instead of the intended scrollframe. To address this, we force a d-t-c
|
|
|
|
// region on scrollbar frames that won't be placed in their own layer. See
|
|
|
|
// bug 1213324 for details.
|
2013-12-16 15:22:11 +04:00
|
|
|
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
|
2015-10-17 09:50:09 +03:00
|
|
|
} else if (aFrame->GetType() == nsGkAtoms::objectFrame) {
|
|
|
|
// If the frame is a plugin frame and wants to handle wheel events as
|
|
|
|
// default action, we should add the frame to dispatch-to-content region.
|
|
|
|
nsPluginFrame* pluginFrame = do_QueryFrame(aFrame);
|
|
|
|
if (pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
|
|
|
|
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, borderBox);
|
|
|
|
}
|
2013-12-16 15:22:11 +04:00
|
|
|
}
|
2015-03-24 16:13:24 +03:00
|
|
|
|
|
|
|
// Touch action region
|
|
|
|
|
2016-07-21 06:29:17 +03:00
|
|
|
nsIFrame* touchActionFrame = aFrame;
|
|
|
|
nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(aFrame);
|
|
|
|
if (scrollFrame) {
|
|
|
|
touchActionFrame = do_QueryFrame(scrollFrame);
|
|
|
|
}
|
|
|
|
uint32_t touchAction = nsLayoutUtils::GetTouchActionFromFrame(touchActionFrame);
|
2016-07-21 02:02:09 +03:00
|
|
|
if (touchAction != NS_STYLE_TOUCH_ACTION_AUTO) {
|
|
|
|
// If this frame has touch-action areas, and there were already
|
|
|
|
// touch-action areas from some other element on this same event regions,
|
|
|
|
// then all we know is that there are multiple elements with touch-action
|
|
|
|
// properties. In particular, we don't know what the relationship is
|
|
|
|
// between those elements in terms of DOM ancestry, and so we don't know
|
|
|
|
// how to combine the regions properly. Instead, we just add all the areas
|
|
|
|
// to the dispatch-to-content region, so that the APZ knows to check with
|
|
|
|
// the main thread. XXX we need to come up with a better way to do this,
|
|
|
|
// see bug 1287829.
|
|
|
|
bool alreadyHadRegions = !mNoActionRegion.IsEmpty() ||
|
|
|
|
!mHorizontalPanRegion.IsEmpty() ||
|
|
|
|
!mVerticalPanRegion.IsEmpty();
|
|
|
|
if (touchAction & NS_STYLE_TOUCH_ACTION_NONE) {
|
|
|
|
mNoActionRegion.OrWith(borderBox);
|
|
|
|
} else {
|
|
|
|
if ((touchAction & NS_STYLE_TOUCH_ACTION_PAN_X)) {
|
|
|
|
mHorizontalPanRegion.OrWith(borderBox);
|
|
|
|
}
|
|
|
|
if ((touchAction & NS_STYLE_TOUCH_ACTION_PAN_Y)) {
|
|
|
|
mVerticalPanRegion.OrWith(borderBox);
|
|
|
|
}
|
2015-03-24 16:13:24 +03:00
|
|
|
}
|
2016-07-21 02:02:09 +03:00
|
|
|
if (alreadyHadRegions) {
|
|
|
|
mDispatchToContentHitRegion.OrWith(CombinedTouchActionRegion());
|
2015-03-24 16:13:24 +03:00
|
|
|
}
|
|
|
|
}
|
2013-12-16 15:22:11 +04:00
|
|
|
}
|
|
|
|
|
2014-11-20 07:24:15 +03:00
|
|
|
void
|
|
|
|
nsDisplayLayerEventRegions::AddInactiveScrollPort(const nsRect& aRect)
|
|
|
|
{
|
2015-10-07 22:08:53 +03:00
|
|
|
mHitRegion.Or(mHitRegion, aRect);
|
2014-11-20 07:24:15 +03:00
|
|
|
mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aRect);
|
|
|
|
}
|
|
|
|
|
2016-06-03 17:20:38 +03:00
|
|
|
bool
|
|
|
|
nsDisplayLayerEventRegions::IsEmpty() const
|
|
|
|
{
|
|
|
|
// If the hit region and maybe-hit region are empty, then the rest
|
|
|
|
// must be empty too.
|
|
|
|
if (mHitRegion.IsEmpty() && mMaybeHitRegion.IsEmpty()) {
|
|
|
|
MOZ_ASSERT(mDispatchToContentHitRegion.IsEmpty());
|
|
|
|
MOZ_ASSERT(mNoActionRegion.IsEmpty());
|
|
|
|
MOZ_ASSERT(mHorizontalPanRegion.IsEmpty());
|
|
|
|
MOZ_ASSERT(mVerticalPanRegion.IsEmpty());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-21 02:02:09 +03:00
|
|
|
nsRegion
|
|
|
|
nsDisplayLayerEventRegions::CombinedTouchActionRegion()
|
|
|
|
{
|
|
|
|
nsRegion result;
|
|
|
|
result.Or(mHorizontalPanRegion, mVerticalPanRegion);
|
|
|
|
result.OrWith(mNoActionRegion);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-05-31 03:01:04 +03:00
|
|
|
int32_t
|
|
|
|
nsDisplayLayerEventRegions::ZIndex() const
|
|
|
|
{
|
|
|
|
return mOverrideZIndex ? *mOverrideZIndex : nsDisplayItem::ZIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayLayerEventRegions::SetOverrideZIndex(int32_t aZIndex)
|
|
|
|
{
|
|
|
|
mOverrideZIndex = Some(aZIndex);
|
|
|
|
}
|
|
|
|
|
2014-11-25 16:45:20 +03:00
|
|
|
void
|
|
|
|
nsDisplayLayerEventRegions::WriteDebugInfo(std::stringstream& aStream)
|
|
|
|
{
|
|
|
|
if (!mHitRegion.IsEmpty()) {
|
|
|
|
AppendToString(aStream, mHitRegion, " (hitRegion ", ")");
|
|
|
|
}
|
|
|
|
if (!mMaybeHitRegion.IsEmpty()) {
|
|
|
|
AppendToString(aStream, mMaybeHitRegion, " (maybeHitRegion ", ")");
|
|
|
|
}
|
|
|
|
if (!mDispatchToContentHitRegion.IsEmpty()) {
|
|
|
|
AppendToString(aStream, mDispatchToContentHitRegion, " (dispatchToContentRegion ", ")");
|
|
|
|
}
|
2016-07-21 06:29:17 +03:00
|
|
|
if (!mNoActionRegion.IsEmpty()) {
|
|
|
|
AppendToString(aStream, mNoActionRegion, " (noActionRegion ", ")");
|
|
|
|
}
|
|
|
|
if (!mHorizontalPanRegion.IsEmpty()) {
|
|
|
|
AppendToString(aStream, mHorizontalPanRegion, " (horizPanRegion ", ")");
|
|
|
|
}
|
|
|
|
if (!mVerticalPanRegion.IsEmpty()) {
|
|
|
|
AppendToString(aStream, mVerticalPanRegion, " (vertPanRegion ", ")");
|
|
|
|
}
|
2014-11-25 16:45:20 +03:00
|
|
|
}
|
|
|
|
|
2014-08-06 09:19:25 +04:00
|
|
|
nsDisplayCaret::nsDisplayCaret(nsDisplayListBuilder* aBuilder,
|
2014-08-06 09:19:28 +04:00
|
|
|
nsIFrame* aCaretFrame)
|
2014-08-06 09:19:25 +04:00
|
|
|
: nsDisplayItem(aBuilder, aCaretFrame)
|
2014-08-06 09:19:28 +04:00
|
|
|
, mCaret(aBuilder->GetCaret())
|
|
|
|
, mBounds(aBuilder->GetCaretRect() + ToReferenceFrame())
|
2014-08-06 09:19:25 +04:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayCaret);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayCaret::~nsDisplayCaret()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayCaret);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsDisplayCaret::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
|
|
|
{
|
2014-08-06 09:19:28 +04:00
|
|
|
*aSnap = true;
|
2014-08-06 09:19:25 +04:00
|
|
|
// The caret returns a rect in the coordinates of mFrame.
|
2014-08-06 09:19:28 +04:00
|
|
|
return mBounds;
|
2014-08-06 09:19:25 +04:00
|
|
|
}
|
|
|
|
|
2006-04-18 03:16:46 +04:00
|
|
|
void
|
|
|
|
nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* aCtx) {
|
2006-04-18 03:16:46 +04:00
|
|
|
// Note: Because we exist, we know that the caret is visible, so we don't
|
|
|
|
// need to check for the caret's visibility.
|
2016-01-06 03:08:17 +03:00
|
|
|
mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
|
2006-04-18 03:16:46 +04:00
|
|
|
}
|
|
|
|
|
2015-04-21 01:57:51 +03:00
|
|
|
nsDisplayBorder::nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
|
|
|
: nsDisplayItem(aBuilder, aFrame)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayBorder);
|
|
|
|
|
2016-11-24 08:11:30 +03:00
|
|
|
mBounds = CalculateBounds(*mFrame->StyleBorder()).GetBounds();
|
2015-04-21 01:57:51 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2014-06-03 16:48:16 +04:00
|
|
|
nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect)
|
|
|
|
{
|
2007-09-28 02:52:32 +04:00
|
|
|
nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
|
2010-08-13 14:01:58 +04:00
|
|
|
ToReferenceFrame();
|
2008-07-17 10:30:25 +04:00
|
|
|
const nsStyleBorder *styleBorder;
|
2014-06-03 16:48:16 +04:00
|
|
|
if (paddingRect.Contains(aRect) &&
|
2013-02-17 01:51:02 +04:00
|
|
|
!(styleBorder = mFrame->StyleBorder())->IsBorderImageLoaded() &&
|
2008-10-01 09:50:52 +04:00
|
|
|
!nsLayoutUtils::HasNonZeroCorner(styleBorder->mBorderRadius)) {
|
2014-06-03 16:48:16 +04:00
|
|
|
// aRect is entirely inside the content rect, and no part
|
2006-09-20 01:58:52 +04:00
|
|
|
// of the border is rendered inside the content rect, so we are not
|
|
|
|
// visible
|
2008-07-17 10:30:25 +04:00
|
|
|
// Skip this if there's a border-image (which draws a background
|
|
|
|
// too) or if there is a border-radius (which makes the border draw
|
|
|
|
// further in).
|
2014-06-03 16:48:16 +04:00
|
|
|
return true;
|
2006-09-20 01:58:52 +04:00
|
|
|
}
|
|
|
|
|
2014-06-03 16:48:16 +04:00
|
|
|
return false;
|
2006-09-20 01:58:52 +04:00
|
|
|
}
|
2016-03-09 08:14:20 +03:00
|
|
|
|
|
|
|
nsDisplayItemGeometry*
|
2012-08-29 09:39:01 +04:00
|
|
|
nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
|
|
|
return new nsDisplayBorderGeometry(this, aBuilder);
|
|
|
|
}
|
2006-09-20 01:58:52 +04:00
|
|
|
|
2012-08-29 09:39:01 +04:00
|
|
|
void
|
|
|
|
nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
|
|
|
{
|
|
|
|
const nsDisplayBorderGeometry* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry);
|
|
|
|
bool snap;
|
2015-10-23 05:54:48 +03:00
|
|
|
|
2012-08-29 09:39:01 +04:00
|
|
|
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
|
|
|
|
!geometry->mContentRect.IsEqualInterior(GetContentRect())) {
|
|
|
|
// We can probably get away with only invalidating the difference
|
|
|
|
// between the border and padding rects, but the XUL ui at least
|
|
|
|
// is apparently painting a background with this?
|
|
|
|
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
|
|
|
|
}
|
2015-10-23 05:54:48 +03:00
|
|
|
|
|
|
|
if (aBuilder->ShouldSyncDecodeImages() &&
|
|
|
|
geometry->ShouldInvalidateToSyncDecodeImages()) {
|
|
|
|
aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
|
|
|
|
}
|
2012-08-29 09:39:01 +04:00
|
|
|
}
|
2016-03-09 08:14:20 +03:00
|
|
|
|
2016-11-24 08:11:30 +03:00
|
|
|
LayerState
|
|
|
|
nsDisplayBorder::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
|
|
|
if (!gfxPrefs::LayersAllowBorderLayers()) {
|
|
|
|
return LAYER_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPoint offset = ToReferenceFrame();
|
|
|
|
Maybe<nsCSSBorderRenderer> br =
|
|
|
|
nsCSSRendering::CreateBorderRenderer(mFrame->PresContext(),
|
|
|
|
nullptr,
|
|
|
|
mFrame,
|
|
|
|
nsRect(),
|
|
|
|
nsRect(offset, mFrame->GetSize()),
|
|
|
|
mFrame->StyleContext(),
|
|
|
|
mFrame->GetSkipSides());
|
|
|
|
if (!br) {
|
|
|
|
return LAYER_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasCompositeColors;
|
|
|
|
if (!br->AllBordersSolid(&hasCompositeColors) || hasCompositeColors) {
|
|
|
|
return LAYER_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't support this yet as we don't copy the values to
|
|
|
|
// the layer, and BasicBorderLayer doesn't support it yet.
|
|
|
|
if (!br->mNoBorderRadius) {
|
|
|
|
return LAYER_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We copy these values correctly to the layer, but BasicBorderLayer
|
|
|
|
// won't render them
|
|
|
|
if (!br->AreBorderSideFinalStylesSame(eSideBitsAll) ||
|
|
|
|
!br->AllBordersSameWidth()) {
|
|
|
|
return LAYER_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_FOR_CSS_SIDES(i) {
|
|
|
|
if (br->mBorderStyles[i] == NS_STYLE_BORDER_STYLE_SOLID) {
|
|
|
|
mColors[i] = ToDeviceColor(br->mBorderColors[i]);
|
|
|
|
mWidths[i] = br->mBorderWidths[i];
|
|
|
|
} else {
|
|
|
|
mWidths[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mRect = ViewAs<LayerPixel>(br->mOuterRect);
|
|
|
|
return LAYER_INACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayBorder::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
|
|
|
{
|
|
|
|
RefPtr<BorderLayer> layer = static_cast<BorderLayer*>
|
|
|
|
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
|
|
|
|
if (!layer) {
|
|
|
|
layer = aManager->CreateBorderLayer();
|
|
|
|
if (!layer)
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
layer->SetRect(mRect);
|
|
|
|
layer->SetCornerRadii({ LayerSize(), LayerSize(), LayerSize(), LayerSize() });
|
|
|
|
layer->SetColors(mColors);
|
|
|
|
layer->SetWidths(mWidths);
|
|
|
|
layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
|
|
|
|
aContainerParameters.mOffset.y, 0));
|
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
void
|
|
|
|
nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* aCtx) {
|
2010-08-13 14:01:58 +04:00
|
|
|
nsPoint offset = ToReferenceFrame();
|
2015-10-23 05:54:48 +03:00
|
|
|
|
|
|
|
PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
|
|
|
|
? PaintBorderFlags::SYNC_DECODE_IMAGES
|
|
|
|
: PaintBorderFlags();
|
|
|
|
|
|
|
|
image::DrawResult result =
|
|
|
|
nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame,
|
|
|
|
mVisibleRect,
|
|
|
|
nsRect(offset, mFrame->GetSize()),
|
|
|
|
mFrame->StyleContext(),
|
|
|
|
flags,
|
|
|
|
mFrame->GetSkipSides());
|
|
|
|
|
|
|
|
nsDisplayBorderGeometry::UpdateDrawResult(this, result);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2011-01-04 13:39:47 +03:00
|
|
|
nsRect
|
2012-04-10 15:24:18 +04:00
|
|
|
nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
2011-01-04 13:39:47 +03:00
|
|
|
{
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = true;
|
2015-04-21 01:57:51 +03:00
|
|
|
return mBounds;
|
2014-03-03 19:37:08 +04:00
|
|
|
}
|
|
|
|
|
2016-11-24 08:11:30 +03:00
|
|
|
nsRegion
|
2014-03-03 19:37:08 +04:00
|
|
|
nsDisplayBorder::CalculateBounds(const nsStyleBorder& aStyleBorder)
|
|
|
|
{
|
2013-12-09 03:01:30 +04:00
|
|
|
nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
|
2014-03-03 19:37:08 +04:00
|
|
|
if (aStyleBorder.IsBorderImageLoaded()) {
|
|
|
|
borderBounds.Inflate(aStyleBorder.GetImageOutset());
|
2013-12-09 03:01:30 +04:00
|
|
|
return borderBounds;
|
|
|
|
} else {
|
2014-03-03 19:37:08 +04:00
|
|
|
nsMargin border = aStyleBorder.GetComputedBorder();
|
2016-11-24 08:11:30 +03:00
|
|
|
nsRegion result;
|
2013-12-09 03:01:30 +04:00
|
|
|
if (border.top > 0) {
|
|
|
|
result = nsRect(borderBounds.X(), borderBounds.Y(), borderBounds.Width(), border.top);
|
|
|
|
}
|
|
|
|
if (border.right > 0) {
|
2016-11-24 08:11:30 +03:00
|
|
|
result.OrWith(nsRect(borderBounds.XMost() - border.right, borderBounds.Y(), border.right, borderBounds.Height()));
|
2013-12-09 03:01:30 +04:00
|
|
|
}
|
|
|
|
if (border.bottom > 0) {
|
2016-11-24 08:11:30 +03:00
|
|
|
result.OrWith(nsRect(borderBounds.X(), borderBounds.YMost() - border.bottom, borderBounds.Width(), border.bottom));
|
2013-12-09 03:01:30 +04:00
|
|
|
}
|
|
|
|
if (border.left > 0) {
|
2016-11-24 08:11:30 +03:00
|
|
|
result.OrWith(nsRect(borderBounds.X(), borderBounds.Y(), border.left, borderBounds.Height()));
|
2013-12-09 03:01:30 +04:00
|
|
|
}
|
|
|
|
|
2015-04-20 03:48:37 +03:00
|
|
|
nscoord radii[8];
|
|
|
|
if (mFrame->GetBorderRadii(radii)) {
|
|
|
|
if (border.left > 0 || border.top > 0) {
|
|
|
|
nsSize cornerSize(radii[NS_CORNER_TOP_LEFT_X], radii[NS_CORNER_TOP_LEFT_Y]);
|
2016-11-24 08:11:30 +03:00
|
|
|
result.OrWith(nsRect(borderBounds.TopLeft(), cornerSize));
|
2015-04-20 03:48:37 +03:00
|
|
|
}
|
|
|
|
if (border.top > 0 || border.right > 0) {
|
|
|
|
nsSize cornerSize(radii[NS_CORNER_TOP_RIGHT_X], radii[NS_CORNER_TOP_RIGHT_Y]);
|
2016-11-24 08:11:30 +03:00
|
|
|
result.OrWith(nsRect(borderBounds.TopRight() - nsPoint(cornerSize.width, 0), cornerSize));
|
2015-04-20 03:48:37 +03:00
|
|
|
}
|
|
|
|
if (border.right > 0 || border.bottom > 0) {
|
|
|
|
nsSize cornerSize(radii[NS_CORNER_BOTTOM_RIGHT_X], radii[NS_CORNER_BOTTOM_RIGHT_Y]);
|
2016-11-24 08:11:30 +03:00
|
|
|
result.OrWith(nsRect(borderBounds.BottomRight() - nsPoint(cornerSize.width, cornerSize.height), cornerSize));
|
2015-04-20 03:48:37 +03:00
|
|
|
}
|
|
|
|
if (border.bottom > 0 || border.left > 0) {
|
|
|
|
nsSize cornerSize(radii[NS_CORNER_BOTTOM_LEFT_X], radii[NS_CORNER_BOTTOM_LEFT_Y]);
|
2016-11-24 08:11:30 +03:00
|
|
|
result.OrWith(nsRect(borderBounds.BottomLeft() - nsPoint(0, cornerSize.height), cornerSize));
|
2015-04-20 03:48:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-09 03:01:30 +04:00
|
|
|
return result;
|
|
|
|
}
|
2011-01-04 13:39:47 +03:00
|
|
|
}
|
|
|
|
|
2009-12-01 02:14:04 +03:00
|
|
|
// Given a region, compute a conservative approximation to it as a list
|
|
|
|
// of rectangles that aren't vertically adjacent (i.e., vertically
|
|
|
|
// adjacent or overlapping rectangles are combined).
|
|
|
|
// Right now this is only approximate, some vertically overlapping rectangles
|
|
|
|
// aren't guaranteed to be combined.
|
|
|
|
static void
|
|
|
|
ComputeDisjointRectangles(const nsRegion& aRegion,
|
|
|
|
nsTArray<nsRect>* aRects) {
|
|
|
|
nscoord accumulationMargin = nsPresContext::CSSPixelsToAppUnits(25);
|
|
|
|
nsRect accumulated;
|
2016-01-19 04:20:59 +03:00
|
|
|
|
|
|
|
for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
|
|
|
|
const nsRect& r = iter.Get();
|
|
|
|
if (accumulated.IsEmpty()) {
|
|
|
|
accumulated = r;
|
2009-12-01 02:14:04 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-01-19 04:20:59 +03:00
|
|
|
if (accumulated.YMost() >= r.y - accumulationMargin) {
|
|
|
|
accumulated.UnionRect(accumulated, r);
|
|
|
|
} else {
|
2009-12-01 02:14:04 +03:00
|
|
|
aRects->AppendElement(accumulated);
|
2016-01-19 04:20:59 +03:00
|
|
|
accumulated = r;
|
2009-12-01 02:14:04 +03:00
|
|
|
}
|
2016-01-19 04:20:59 +03:00
|
|
|
}
|
2009-12-01 02:14:04 +03:00
|
|
|
|
2016-01-19 04:20:59 +03:00
|
|
|
// Finish the in-flight rectangle, if there is one.
|
|
|
|
if (!accumulated.IsEmpty()) {
|
|
|
|
aRects->AppendElement(accumulated);
|
2009-12-01 02:14:04 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-08 04:57:47 +04:00
|
|
|
void
|
2009-02-10 11:45:13 +03:00
|
|
|
nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* aCtx) {
|
2010-08-13 14:01:58 +04:00
|
|
|
nsPoint offset = ToReferenceFrame();
|
2013-04-18 00:16:14 +04:00
|
|
|
nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
|
2009-12-01 02:14:04 +03:00
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsRect,10> rects;
|
2009-12-01 02:14:04 +03:00
|
|
|
ComputeDisjointRectangles(mVisibleRegion, &rects);
|
|
|
|
|
2014-05-24 01:12:29 +04:00
|
|
|
PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint",
|
|
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < rects.Length(); ++i) {
|
2009-12-01 02:14:04 +03:00
|
|
|
nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
|
2013-11-18 13:32:09 +04:00
|
|
|
borderRect, rects[i], mOpacity);
|
2009-12-01 02:14:04 +03:00
|
|
|
}
|
2008-07-08 04:57:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
2012-04-10 15:24:18 +04:00
|
|
|
nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
|
|
|
*aSnap = false;
|
2012-12-12 00:36:54 +04:00
|
|
|
return mBounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsDisplayBoxShadowOuter::GetBoundsInternal() {
|
|
|
|
return nsLayoutUtils::GetBoxShadowRectForFrame(mFrame, mFrame->GetSize()) +
|
|
|
|
ToReferenceFrame();
|
2008-07-08 04:57:47 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2014-06-03 16:48:16 +04:00
|
|
|
nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect& aRect)
|
|
|
|
{
|
2010-08-13 14:01:58 +04:00
|
|
|
nsPoint origin = ToReferenceFrame();
|
2009-04-24 13:24:44 +04:00
|
|
|
nsRect frameRect(origin, mFrame->GetSize());
|
2014-06-03 16:48:16 +04:00
|
|
|
if (!frameRect.Contains(aRect))
|
|
|
|
return false;
|
2009-04-24 13:24:44 +04:00
|
|
|
|
|
|
|
// the visible region is entirely inside the border-rect, and box shadows
|
|
|
|
// never render within the border-rect (unless there's a border radius).
|
|
|
|
nscoord twipsRadii[8];
|
2011-09-29 10:19:26 +04:00
|
|
|
bool hasBorderRadii = mFrame->GetBorderRadii(twipsRadii);
|
2009-04-24 13:24:44 +04:00
|
|
|
if (!hasBorderRadii)
|
2014-06-03 16:48:16 +04:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return RoundedRectContainsRect(frameRect, twipsRadii, aRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion) {
|
|
|
|
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2014-06-03 16:48:16 +04:00
|
|
|
}
|
2009-01-30 10:03:46 +03:00
|
|
|
|
2014-06-03 16:48:16 +04:00
|
|
|
// Store the actual visible region
|
|
|
|
mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
|
|
|
|
return true;
|
2009-01-30 10:03:46 +03:00
|
|
|
}
|
|
|
|
|
2013-08-23 05:47:54 +04:00
|
|
|
void
|
|
|
|
nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
|
|
|
{
|
2014-07-21 17:59:10 +04:00
|
|
|
const nsDisplayBoxShadowOuterGeometry* geometry =
|
|
|
|
static_cast<const nsDisplayBoxShadowOuterGeometry*>(aGeometry);
|
2013-08-23 05:47:54 +04:00
|
|
|
bool snap;
|
|
|
|
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
|
2014-07-21 17:59:10 +04:00
|
|
|
!geometry->mBorderRect.IsEqualInterior(GetBorderRect()) ||
|
|
|
|
mOpacity != geometry->mOpacity) {
|
2013-08-23 05:47:54 +04:00
|
|
|
nsRegion oldShadow, newShadow;
|
|
|
|
nscoord dontCare[8];
|
|
|
|
bool hasBorderRadius = mFrame->GetBorderRadii(dontCare);
|
|
|
|
if (hasBorderRadius) {
|
|
|
|
// If we have rounded corners then we need to invalidate the frame area
|
|
|
|
// too since we paint into it.
|
|
|
|
oldShadow = geometry->mBounds;
|
|
|
|
newShadow = GetBounds(aBuilder, &snap);
|
|
|
|
} else {
|
2015-07-21 17:54:44 +03:00
|
|
|
oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
|
|
|
|
newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
|
2013-08-23 05:47:54 +04:00
|
|
|
}
|
|
|
|
aInvalidRegion->Or(oldShadow, newShadow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-10 11:45:13 +03:00
|
|
|
void
|
|
|
|
nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* aCtx) {
|
2010-08-13 14:01:58 +04:00
|
|
|
nsPoint offset = ToReferenceFrame();
|
2009-12-01 02:14:04 +03:00
|
|
|
nsRect borderRect = nsRect(offset, mFrame->GetSize());
|
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsRect,10> rects;
|
2009-12-01 02:14:04 +03:00
|
|
|
ComputeDisjointRectangles(mVisibleRegion, &rects);
|
|
|
|
|
2014-05-24 01:12:29 +04:00
|
|
|
PROFILER_LABEL("nsDisplayBoxShadowInner", "Paint",
|
|
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
|
2014-10-20 13:55:48 +04:00
|
|
|
DrawTarget* drawTarget = aCtx->GetDrawTarget();
|
|
|
|
gfxContext* gfx = aCtx->ThebesContext();
|
|
|
|
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < rects.Length(); ++i) {
|
2014-10-20 13:55:48 +04:00
|
|
|
gfx->Save();
|
2014-10-22 15:29:06 +04:00
|
|
|
gfx->Clip(NSRectToSnappedRect(rects[i], appUnitsPerDevPixel, *drawTarget));
|
2016-01-06 03:08:17 +03:00
|
|
|
nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame, borderRect);
|
2014-10-20 13:55:48 +04:00
|
|
|
gfx->Restore();
|
2009-12-01 02:14:04 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2009-12-01 02:14:04 +03:00
|
|
|
nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion) {
|
|
|
|
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2011-01-28 01:58:50 +03:00
|
|
|
}
|
2009-12-01 02:14:04 +03:00
|
|
|
|
|
|
|
// Store the actual visible region
|
|
|
|
mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2009-02-10 11:45:13 +03:00
|
|
|
}
|
|
|
|
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList)
|
2016-02-26 15:38:12 +03:00
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList,
|
|
|
|
aBuilder->ClipState().GetCurrentInnermostScrollClip())
|
|
|
|
{}
|
|
|
|
|
|
|
|
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
|
|
|
const DisplayItemScrollClip* aScrollClip)
|
|
|
|
: nsDisplayItem(aBuilder, aFrame, aScrollClip)
|
2014-03-20 06:12:46 +04:00
|
|
|
, mOverrideZIndex(0)
|
2014-07-24 03:07:18 +04:00
|
|
|
, mHasZIndexOverride(false)
|
2014-03-20 06:12:46 +04:00
|
|
|
{
|
2014-06-09 08:48:01 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayWrapList);
|
|
|
|
|
2014-12-22 06:09:32 +03:00
|
|
|
mBaseVisibleRect = mVisibleRect;
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
mList.AppendToTop(aList);
|
2012-04-19 06:40:43 +04:00
|
|
|
UpdateBounds(aBuilder);
|
2012-10-25 09:32:25 +04:00
|
|
|
|
|
|
|
if (!aFrame || !aFrame->IsTransformed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-17 04:31:00 +03:00
|
|
|
// If we're a transformed frame, then we need to find out if we're inside
|
|
|
|
// the nsDisplayTransform or outside of it. Frames inside the transform
|
|
|
|
// need mReferenceFrame == mFrame, outside needs the next ancestor
|
|
|
|
// reference frame.
|
|
|
|
// If we're inside the transform, then the nsDisplayItem constructor
|
|
|
|
// will have done the right thing.
|
|
|
|
// If we're outside the transform, then we should have only one child
|
|
|
|
// (since nsDisplayTransform wraps all actual content), and that child
|
|
|
|
// will have the correct reference frame set (since nsDisplayTransform
|
|
|
|
// handles this explictly).
|
|
|
|
nsDisplayItem *i = mList.GetBottom();
|
|
|
|
if (i && (!i->GetAbove() || i->GetType() == TYPE_TRANSFORM) &&
|
|
|
|
i->Frame() == mFrame) {
|
|
|
|
mReferenceFrame = i->ReferenceFrame();
|
|
|
|
mToReferenceFrame = i->ToReferenceFrame();
|
2012-10-25 09:32:25 +04:00
|
|
|
}
|
2014-08-07 20:33:18 +04:00
|
|
|
mVisibleRect = aBuilder->GetDirtyRect() +
|
|
|
|
aBuilder->GetCurrentFrameOffsetToReferenceFrame();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayItem* aItem)
|
2014-03-20 06:12:46 +04:00
|
|
|
: nsDisplayItem(aBuilder, aFrame)
|
|
|
|
, mOverrideZIndex(0)
|
2014-07-24 03:07:18 +04:00
|
|
|
, mHasZIndexOverride(false)
|
2014-03-20 06:12:46 +04:00
|
|
|
{
|
2014-06-09 08:48:01 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayWrapList);
|
|
|
|
|
2014-12-22 06:09:32 +03:00
|
|
|
mBaseVisibleRect = mVisibleRect;
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
mList.AppendToTop(aItem);
|
2012-04-19 06:40:43 +04:00
|
|
|
UpdateBounds(aBuilder);
|
2016-03-09 08:14:20 +03:00
|
|
|
|
2012-10-25 09:32:25 +04:00
|
|
|
if (!aFrame || !aFrame->IsTransformed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-17 04:31:00 +03:00
|
|
|
// See the previous nsDisplayWrapList constructor
|
|
|
|
if (aItem->Frame() == aFrame) {
|
|
|
|
mReferenceFrame = aItem->ReferenceFrame();
|
|
|
|
mToReferenceFrame = aItem->ToReferenceFrame();
|
2012-10-25 09:32:25 +04:00
|
|
|
}
|
2014-08-07 20:33:18 +04:00
|
|
|
mVisibleRect = aBuilder->GetDirtyRect() +
|
|
|
|
aBuilder->GetCurrentFrameOffsetToReferenceFrame();
|
2014-07-17 19:24:47 +04:00
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
nsDisplayWrapList::~nsDisplayWrapList() {
|
|
|
|
mList.DeleteAll();
|
2014-06-09 08:48:01 +04:00
|
|
|
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayWrapList);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2010-04-08 04:31:26 +04:00
|
|
|
void
|
|
|
|
nsDisplayWrapList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
|
|
|
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
|
|
|
|
mList.HitTest(aBuilder, aRect, aState, aOutFrames);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
2012-04-10 15:24:18 +04:00
|
|
|
nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
|
|
|
|
*aSnap = false;
|
2012-04-13 15:44:06 +04:00
|
|
|
return mBounds;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2009-09-07 04:35:14 +04:00
|
|
|
nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion) {
|
2013-03-04 13:56:02 +04:00
|
|
|
// Convert the passed in visible region to our appunits.
|
|
|
|
nsRegion visibleRegion;
|
|
|
|
// mVisibleRect has been clipped to GetClippedBounds
|
|
|
|
visibleRegion.And(*aVisibleRegion, mVisibleRect);
|
|
|
|
nsRegion originalVisibleRegion = visibleRegion;
|
|
|
|
|
|
|
|
bool retval =
|
2016-01-06 03:08:17 +03:00
|
|
|
mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, mVisibleRect);
|
2013-03-04 13:56:02 +04:00
|
|
|
|
|
|
|
nsRegion removed;
|
|
|
|
// removed = originalVisibleRegion - visibleRegion
|
|
|
|
removed.Sub(originalVisibleRegion, visibleRegion);
|
|
|
|
// aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
|
|
|
|
// SubtractFromVisibleRegion does)
|
|
|
|
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
|
|
|
|
|
|
|
|
return retval;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion
|
|
|
|
nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
2012-05-03 08:29:05 +04:00
|
|
|
bool* aSnap) {
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = false;
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion result;
|
|
|
|
if (mList.IsOpaque()) {
|
2012-04-13 15:44:06 +04:00
|
|
|
// Everything within GetBounds that's visible is opaque.
|
2012-04-10 15:24:18 +04:00
|
|
|
result = GetBounds(aBuilder, aSnap);
|
2011-01-03 04:48:09 +03:00
|
|
|
}
|
|
|
|
return result;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2016-05-19 11:07:52 +03:00
|
|
|
Maybe<nscolor>
|
|
|
|
nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder) {
|
|
|
|
// We could try to do something but let's conservatively just return Nothing.
|
|
|
|
return Nothing();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
|
2011-04-08 05:04:40 +04:00
|
|
|
nsRenderingContext* aCtx) {
|
2010-03-01 10:56:19 +03:00
|
|
|
NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2014-02-18 05:26:57 +04:00
|
|
|
/**
|
|
|
|
* Returns true if all descendant display items can be placed in the same
|
2014-09-26 21:06:08 +04:00
|
|
|
* PaintedLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
|
2014-02-18 05:26:57 +04:00
|
|
|
* and they all have the expected animated geometry root.
|
|
|
|
*/
|
2013-09-26 01:07:26 +04:00
|
|
|
static LayerState
|
2014-02-18 05:26:57 +04:00
|
|
|
RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters,
|
|
|
|
const nsDisplayList& aList,
|
2015-11-25 01:53:51 +03:00
|
|
|
AnimatedGeometryRoot* aExpectedAnimatedGeometryRootForChildren)
|
2013-09-26 01:07:26 +04:00
|
|
|
{
|
2012-11-14 10:26:29 +04:00
|
|
|
LayerState result = LAYER_INACTIVE;
|
2010-07-16 01:08:05 +04:00
|
|
|
for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
|
2013-09-26 01:07:26 +04:00
|
|
|
if (result == LAYER_INACTIVE &&
|
2015-11-25 01:53:51 +03:00
|
|
|
i->GetAnimatedGeometryRoot() != aExpectedAnimatedGeometryRootForChildren) {
|
2013-04-19 16:01:41 +04:00
|
|
|
result = LAYER_ACTIVE;
|
2010-07-16 01:08:05 +04:00
|
|
|
}
|
|
|
|
|
2012-05-03 18:05:55 +04:00
|
|
|
LayerState state = i->GetLayerState(aBuilder, aManager, aParameters);
|
2016-03-08 22:39:07 +03:00
|
|
|
if (state == LAYER_ACTIVE && i->GetType() == nsDisplayItem::TYPE_BLEND_MODE) {
|
|
|
|
// nsDisplayBlendMode always returns LAYER_ACTIVE to ensure that the
|
|
|
|
// blending operation happens in the intermediate surface of its parent
|
|
|
|
// display item (usually an nsDisplayBlendContainer). But this does not
|
|
|
|
// mean that it needs all its ancestor display items to become active.
|
|
|
|
// So we ignore its layer state and look at its children instead.
|
|
|
|
state = RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
|
|
|
|
*i->GetSameCoordinateSystemChildren(), i->GetAnimatedGeometryRoot());
|
|
|
|
}
|
2013-09-26 01:07:26 +04:00
|
|
|
if ((state == LAYER_ACTIVE || state == LAYER_ACTIVE_FORCE) &&
|
|
|
|
state > result) {
|
2012-11-14 10:26:29 +04:00
|
|
|
result = state;
|
2013-09-26 01:07:26 +04:00
|
|
|
}
|
2013-11-27 01:30:20 +04:00
|
|
|
if (state == LAYER_ACTIVE_EMPTY && state > result) {
|
|
|
|
result = LAYER_ACTIVE_FORCE;
|
|
|
|
}
|
2010-07-16 01:08:05 +04:00
|
|
|
if (state == LAYER_NONE) {
|
2012-11-02 16:59:03 +04:00
|
|
|
nsDisplayList* list = i->GetSameCoordinateSystemChildren();
|
2012-11-14 10:26:29 +04:00
|
|
|
if (list) {
|
2013-09-26 01:07:26 +04:00
|
|
|
LayerState childState =
|
2014-02-18 05:26:57 +04:00
|
|
|
RequiredLayerStateForChildren(aBuilder, aManager, aParameters, *list,
|
|
|
|
aExpectedAnimatedGeometryRootForChildren);
|
2012-11-14 10:26:29 +04:00
|
|
|
if (childState > result) {
|
|
|
|
result = childState;
|
|
|
|
}
|
|
|
|
}
|
2010-07-16 01:08:05 +04:00
|
|
|
}
|
|
|
|
}
|
2012-11-14 10:26:29 +04:00
|
|
|
return result;
|
2010-07-16 01:08:05 +04:00
|
|
|
}
|
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
|
2010-10-11 04:58:20 +04:00
|
|
|
{
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRect bounds;
|
2010-10-11 04:58:20 +04:00
|
|
|
for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) {
|
2011-01-03 04:48:09 +03:00
|
|
|
bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
|
2010-10-11 04:58:20 +04:00
|
|
|
}
|
2011-01-03 04:48:09 +03:00
|
|
|
return bounds;
|
2010-10-11 04:58:20 +04:00
|
|
|
}
|
|
|
|
|
2014-08-11 06:59:02 +04:00
|
|
|
void
|
|
|
|
nsDisplayWrapList::SetVisibleRect(const nsRect& aRect)
|
|
|
|
{
|
|
|
|
mVisibleRect = aRect;
|
|
|
|
}
|
|
|
|
|
2014-11-24 04:03:49 +03:00
|
|
|
void
|
|
|
|
nsDisplayWrapList::SetReferenceFrame(const nsIFrame* aFrame)
|
|
|
|
{
|
|
|
|
mReferenceFrame = aFrame;
|
|
|
|
mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
|
|
|
|
}
|
|
|
|
|
2006-01-26 05:29:17 +03:00
|
|
|
static nsresult
|
|
|
|
WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
|
|
|
nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
|
2010-08-13 13:55:54 +04:00
|
|
|
if (!aList->GetTop())
|
2006-01-26 05:29:17 +03:00
|
|
|
return NS_OK;
|
|
|
|
nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
|
|
|
|
if (!item)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
// aList was emptied
|
|
|
|
aList->AppendToTop(item);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsresult
|
|
|
|
WrapEachDisplayItem(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
|
|
|
|
nsDisplayList newList;
|
|
|
|
nsDisplayItem* item;
|
|
|
|
while ((item = aList->RemoveBottom())) {
|
|
|
|
item = aWrapper->WrapItem(aBuilder, item);
|
|
|
|
if (!item)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
newList.AppendToTop(item);
|
|
|
|
}
|
|
|
|
// aList was emptied
|
|
|
|
aList->AppendToTop(&newList);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult nsDisplayWrapper::WrapLists(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, const nsDisplayListSet& aIn, const nsDisplayListSet& aOut)
|
|
|
|
{
|
|
|
|
nsresult rv = WrapListsInPlace(aBuilder, aFrame, aIn);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (&aOut == &aIn)
|
|
|
|
return NS_OK;
|
|
|
|
aOut.BorderBackground()->AppendToTop(aIn.BorderBackground());
|
|
|
|
aOut.BlockBorderBackgrounds()->AppendToTop(aIn.BlockBorderBackgrounds());
|
|
|
|
aOut.Floats()->AppendToTop(aIn.Floats());
|
|
|
|
aOut.Content()->AppendToTop(aIn.Content());
|
|
|
|
aOut.PositionedDescendants()->AppendToTop(aIn.PositionedDescendants());
|
|
|
|
aOut.Outlines()->AppendToTop(aIn.Outlines());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult nsDisplayWrapper::WrapListsInPlace(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, const nsDisplayListSet& aLists)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
if (WrapBorderBackground()) {
|
|
|
|
// Our border-backgrounds are in-flow
|
|
|
|
rv = WrapDisplayList(aBuilder, aFrame, aLists.BorderBackground(), this);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
// Our block border-backgrounds are in-flow
|
|
|
|
rv = WrapDisplayList(aBuilder, aFrame, aLists.BlockBorderBackgrounds(), this);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// The floats are not in flow
|
|
|
|
rv = WrapEachDisplayItem(aBuilder, aLists.Floats(), this);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Our child content is in flow
|
|
|
|
rv = WrapDisplayList(aBuilder, aFrame, aLists.Content(), this);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// The positioned descendants may not be in-flow
|
|
|
|
rv = WrapEachDisplayItem(aBuilder, aLists.PositionedDescendants(), this);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// The outlines may not be in-flow
|
|
|
|
return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
|
|
|
|
}
|
|
|
|
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
|
2015-10-15 05:15:16 +03:00
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
Bug 1238564 - Set the innermost possible scroll clip on opacity items during creation. r=mattwoodrow
Always use an ancestor scroll clip of all direct children, or the original
scroll clip if the children don't share the same scroll clip tree.
Unfortunately this requires another pass over the stacking context display list.
Also, fix clips, scroll clips and creation order of blend items:
If a clipped mix-blend-mode item contains absolute / fixed positioned items,
those items should not be clipped, same for blend container items.
When a transform item contains blend modes, create the blend container inside
the transform.
Don't do tree comparisons on scroll clips from different scroll clip trees.
If the inner scroll clip is nullptr, because it was cleared, it will look like
it's the ancestor of the outer non-nullptr scroll clip.
These changes don't look very related, but it was very hard to get tests passing
with only some of the changes and not the others, and after having spent two
weeks on this patch I'm not thrilled about going back and checking exactly which
change was necessary to fix which test failure.
MozReview-Commit-ID: IKGciUBrdNa
--HG--
extra : rebase_source : e570f16ecedd80cba16051f0e1ac66764bc95815
extra : histedit_source : fcfbcbc254aaf93594d9d80c117d6ec945805993
2016-03-04 23:05:58 +03:00
|
|
|
const DisplayItemScrollClip* aScrollClip,
|
2016-08-10 06:15:28 +03:00
|
|
|
bool aForEventsAndPluginsOnly)
|
Bug 1238564 - Set the innermost possible scroll clip on opacity items during creation. r=mattwoodrow
Always use an ancestor scroll clip of all direct children, or the original
scroll clip if the children don't share the same scroll clip tree.
Unfortunately this requires another pass over the stacking context display list.
Also, fix clips, scroll clips and creation order of blend items:
If a clipped mix-blend-mode item contains absolute / fixed positioned items,
those items should not be clipped, same for blend container items.
When a transform item contains blend modes, create the blend container inside
the transform.
Don't do tree comparisons on scroll clips from different scroll clip trees.
If the inner scroll clip is nullptr, because it was cleared, it will look like
it's the ancestor of the outer non-nullptr scroll clip.
These changes don't look very related, but it was very hard to get tests passing
with only some of the changes and not the others, and after having spent two
weeks on this patch I'm not thrilled about going back and checking exactly which
change was necessary to fix which test failure.
MozReview-Commit-ID: IKGciUBrdNa
--HG--
extra : rebase_source : e570f16ecedd80cba16051f0e1ac66764bc95815
extra : histedit_source : fcfbcbc254aaf93594d9d80c117d6ec945805993
2016-03-04 23:05:58 +03:00
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
|
2016-04-12 08:52:43 +03:00
|
|
|
, mOpacity(aFrame->StyleEffects()->mOpacity)
|
2016-08-10 06:15:28 +03:00
|
|
|
, mForEventsAndPluginsOnly(aForEventsAndPluginsOnly)
|
2015-10-15 05:15:16 +03:00
|
|
|
{
|
2006-01-29 21:48:58 +03:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayOpacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayOpacity::~nsDisplayOpacity() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayOpacity);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
2006-01-29 21:48:58 +03:00
|
|
|
#endif
|
2006-01-26 05:29:17 +03:00
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
2012-05-03 08:29:05 +04:00
|
|
|
bool* aSnap) {
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = false;
|
2014-06-12 19:34:35 +04:00
|
|
|
// The only time where mOpacity == 1.0 should be when we have will-change.
|
|
|
|
// We could report this as opaque then but when the will-change value starts
|
|
|
|
// animating the element would become non opaque and could cause repaints.
|
2011-01-03 04:48:09 +03:00
|
|
|
return nsRegion();
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2010-03-01 10:56:19 +03:00
|
|
|
// nsDisplayOpacity uses layers for rendering
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
|
2011-06-22 16:11:27 +04:00
|
|
|
LayerManager* aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aContainerParameters) {
|
2015-11-03 06:49:22 +03:00
|
|
|
ContainerLayerParameters params = aContainerParameters;
|
2016-08-10 06:15:28 +03:00
|
|
|
params.mForEventsAndPluginsOnly = mForEventsAndPluginsOnly;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Layer> container = aManager->GetLayerBuilder()->
|
2014-06-09 08:48:00 +04:00
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
2015-11-03 06:49:22 +03:00
|
|
|
params, nullptr,
|
2015-02-25 19:47:22 +03:00
|
|
|
FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
|
2012-07-31 21:28:21 +04:00
|
|
|
if (!container)
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2006-02-16 02:21:12 +03:00
|
|
|
|
2014-06-12 19:34:35 +04:00
|
|
|
container->SetOpacity(mOpacity);
|
2014-03-05 08:13:21 +04:00
|
|
|
nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
|
|
|
|
this, mFrame,
|
|
|
|
eCSSProperty_opacity);
|
2012-07-31 21:28:21 +04:00
|
|
|
return container.forget();
|
2010-03-01 10:56:19 +03:00
|
|
|
}
|
2006-02-16 02:21:12 +03:00
|
|
|
|
2011-10-27 00:10:48 +04:00
|
|
|
/**
|
|
|
|
* This doesn't take into account layer scaling --- the layer may be
|
|
|
|
* rendered at a higher (or lower) resolution, affecting the retained layer
|
|
|
|
* size --- but this should be good enough.
|
|
|
|
*/
|
|
|
|
static bool
|
2016-06-08 08:12:20 +03:00
|
|
|
IsItemTooSmallForActiveLayer(nsIFrame* aFrame)
|
2011-10-27 00:10:48 +04:00
|
|
|
{
|
2016-06-08 08:12:20 +03:00
|
|
|
nsIntRect visibleDevPixels = aFrame->GetVisualOverflowRectRelativeToSelf().ToOutsidePixels(
|
|
|
|
aFrame->PresContext()->AppUnitsPerDevPixel());
|
2011-10-27 00:10:48 +04:00
|
|
|
static const int MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS = 16;
|
|
|
|
return visibleDevPixels.Size() <
|
|
|
|
nsIntSize(MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS, MIN_ACTIVE_LAYER_SIZE_DEV_PIXELS);
|
|
|
|
}
|
|
|
|
|
2016-05-07 11:37:58 +03:00
|
|
|
static void
|
2016-06-08 08:12:20 +03:00
|
|
|
SetAnimationPerformanceWarningForTooSmallItem(nsIFrame* aFrame,
|
2016-08-10 02:28:19 +03:00
|
|
|
nsCSSPropertyID aProperty)
|
2016-05-07 11:37:58 +03:00
|
|
|
{
|
|
|
|
// We use ToNearestPixels() here since ToOutsidePixels causes some sort of
|
|
|
|
// errors. See https://bugzilla.mozilla.org/show_bug.cgi?id=1258904#c19
|
2016-06-08 08:12:20 +03:00
|
|
|
nsIntRect visibleDevPixels = aFrame->GetVisualOverflowRectRelativeToSelf().ToNearestPixels(
|
|
|
|
aFrame->PresContext()->AppUnitsPerDevPixel());
|
2016-05-07 11:37:58 +03:00
|
|
|
|
|
|
|
// Set performance warning only if the visible dev pixels is not empty
|
|
|
|
// because dev pixels is empty if the frame has 'preserve-3d' style.
|
|
|
|
if (visibleDevPixels.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-08 08:12:20 +03:00
|
|
|
EffectCompositor::SetPerformanceWarning(aFrame, aProperty,
|
2016-05-07 11:37:58 +03:00
|
|
|
AnimationPerformanceWarning(
|
|
|
|
AnimationPerformanceWarning::Type::ContentTooSmall,
|
|
|
|
{ visibleDevPixels.Width(), visibleDevPixels.Height() }));
|
|
|
|
}
|
|
|
|
|
2016-06-08 08:12:20 +03:00
|
|
|
/* static */ bool
|
|
|
|
nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
2013-11-18 13:32:09 +04:00
|
|
|
{
|
2016-06-08 08:12:20 +03:00
|
|
|
if (ActiveLayerTracker::IsStyleAnimated(aBuilder, aFrame,
|
2016-05-07 11:37:57 +03:00
|
|
|
eCSSProperty_opacity) ||
|
2016-06-08 08:12:20 +03:00
|
|
|
EffectCompositor::HasAnimationsForCompositor(aFrame,
|
2015-12-10 00:28:10 +03:00
|
|
|
eCSSProperty_opacity)) {
|
2016-06-08 08:12:20 +03:00
|
|
|
if (!IsItemTooSmallForActiveLayer(aFrame)) {
|
2016-05-07 11:37:57 +03:00
|
|
|
return true;
|
|
|
|
}
|
2016-06-08 08:12:20 +03:00
|
|
|
SetAnimationPerformanceWarningForTooSmallItem(aFrame, eCSSProperty_opacity);
|
2012-07-31 21:28:21 +04:00
|
|
|
}
|
2013-11-18 13:32:09 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-20 04:04:09 +03:00
|
|
|
void
|
2014-06-12 19:34:35 +04:00
|
|
|
nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder,
|
|
|
|
float aOpacity,
|
|
|
|
const DisplayItemClip* aClip)
|
|
|
|
{
|
2015-02-20 04:04:09 +03:00
|
|
|
NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
|
2014-06-12 19:34:35 +04:00
|
|
|
mOpacity = mOpacity * aOpacity;
|
|
|
|
if (aClip) {
|
|
|
|
IntersectClip(aBuilder, *aClip);
|
|
|
|
}
|
2015-02-20 04:04:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayOpacity::CanApplyOpacity() const
|
|
|
|
{
|
2014-06-12 19:34:35 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-18 13:32:09 +04:00
|
|
|
bool
|
|
|
|
nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
2016-06-08 08:12:20 +03:00
|
|
|
if (NeedsActiveLayer(aBuilder, mFrame) || mOpacity == 0.0) {
|
2015-11-11 05:17:30 +03:00
|
|
|
// If our opacity is zero then we'll discard all descendant display items
|
|
|
|
// except for layer event regions, so there's no point in doing this
|
|
|
|
// optimization (and if we do do it, then invalidations of those descendants
|
|
|
|
// might trigger repainting).
|
2013-11-18 13:32:09 +04:00
|
|
|
return false;
|
2015-11-11 05:17:30 +03:00
|
|
|
}
|
2013-11-18 13:32:09 +04:00
|
|
|
|
|
|
|
nsDisplayItem* child = mList.GetBottom();
|
2015-02-20 04:04:09 +03:00
|
|
|
// Only try folding our opacity down if we have at most three children
|
|
|
|
// that don't overlap and can all apply the opacity to themselves.
|
|
|
|
if (!child) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
struct {
|
|
|
|
nsDisplayItem* item;
|
|
|
|
nsRect bounds;
|
|
|
|
} children[3];
|
|
|
|
bool snap;
|
|
|
|
uint32_t numChildren = 0;
|
|
|
|
for (; numChildren < ArrayLength(children) && child; numChildren++, child = child->GetAbove()) {
|
2015-10-23 01:22:54 +03:00
|
|
|
if (child->GetType() == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
|
|
|
|
numChildren--;
|
|
|
|
continue;
|
|
|
|
}
|
2015-02-20 04:04:09 +03:00
|
|
|
if (!child->CanApplyOpacity()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
children[numChildren].item = child;
|
|
|
|
children[numChildren].bounds = child->GetBounds(aBuilder, &snap);
|
|
|
|
}
|
|
|
|
if (child) {
|
|
|
|
// we have a fourth (or more) child
|
2013-11-18 13:32:09 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-20 04:04:09 +03:00
|
|
|
for (uint32_t i = 0; i < numChildren; i++) {
|
|
|
|
for (uint32_t j = i+1; j < numChildren; j++) {
|
|
|
|
if (children[i].bounds.Intersects(children[j].bounds)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < numChildren; i++) {
|
|
|
|
children[i].item->ApplyOpacity(aBuilder, mOpacity, mClip);
|
|
|
|
}
|
|
|
|
return true;
|
2013-11-18 13:32:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsDisplayItem::LayerState
|
|
|
|
nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters) {
|
2015-10-15 05:15:16 +03:00
|
|
|
// If we only created this item so that we'd get correct nsDisplayEventRegions for child
|
|
|
|
// frames, then force us to inactive to avoid unnecessary layerization changes for content
|
|
|
|
// that won't ever be painted.
|
2016-08-10 06:15:28 +03:00
|
|
|
if (mForEventsAndPluginsOnly) {
|
2015-10-15 05:15:16 +03:00
|
|
|
MOZ_ASSERT(mOpacity == 0);
|
|
|
|
return LAYER_INACTIVE;
|
|
|
|
}
|
|
|
|
|
2016-06-08 08:12:20 +03:00
|
|
|
if (NeedsActiveLayer(aBuilder, mFrame)) {
|
2016-05-07 11:37:57 +03:00
|
|
|
// Returns LAYER_ACTIVE_FORCE to avoid flatterning the layer for async
|
|
|
|
// animations.
|
|
|
|
return LAYER_ACTIVE_FORCE;
|
|
|
|
}
|
2013-11-18 13:32:09 +04:00
|
|
|
|
2015-11-25 01:53:51 +03:00
|
|
|
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, GetAnimatedGeometryRoot());
|
2010-07-16 01:08:05 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2011-05-13 20:40:46 +04:00
|
|
|
nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion) {
|
2006-01-26 05:29:17 +03:00
|
|
|
// Our children are translucent so we should not allow them to subtract
|
|
|
|
// area from aVisibleRegion. We do need to find out what is visible under
|
|
|
|
// our children in the temporary compositing buffer, because if our children
|
|
|
|
// paint our entire bounds opaquely then we don't need an alpha channel in
|
|
|
|
// the temporary compositing buffer.
|
2013-03-04 13:56:02 +04:00
|
|
|
nsRect bounds = GetClippedBounds(aBuilder);
|
2010-03-01 10:56:19 +03:00
|
|
|
nsRegion visibleUnderChildren;
|
|
|
|
visibleUnderChildren.And(*aVisibleRegion, bounds);
|
|
|
|
return
|
2014-06-23 08:24:51 +04:00
|
|
|
nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2016-01-06 03:08:17 +03:00
|
|
|
bool nsDisplayOpacity::TryMerge(nsDisplayItem* aItem) {
|
2006-01-26 05:29:17 +03:00
|
|
|
if (aItem->GetType() != TYPE_OPACITY)
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2006-01-26 05:29:17 +03:00
|
|
|
// items for the same content element should be merged into a single
|
|
|
|
// compositing group
|
|
|
|
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
|
2013-04-19 16:02:13 +04:00
|
|
|
if (aItem->Frame()->GetContent() != mFrame->GetContent())
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2013-03-04 13:56:02 +04:00
|
|
|
if (aItem->GetClip() != GetClip())
|
|
|
|
return false;
|
2015-12-22 18:54:19 +03:00
|
|
|
if (aItem->ScrollClip() != ScrollClip())
|
|
|
|
return false;
|
2012-04-17 09:44:32 +04:00
|
|
|
MergeFromTrackingMergedFrames(static_cast<nsDisplayOpacity*>(aItem));
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2006-01-26 05:29:17 +03:00
|
|
|
}
|
|
|
|
|
2014-01-27 02:07:08 +04:00
|
|
|
void
|
2014-11-25 16:45:19 +03:00
|
|
|
nsDisplayOpacity::WriteDebugInfo(std::stringstream& aStream)
|
2014-01-27 02:07:08 +04:00
|
|
|
{
|
2014-11-25 16:45:19 +03:00
|
|
|
aStream << " (opacity " << mOpacity << ")";
|
2014-01-27 02:07:08 +04:00
|
|
|
}
|
|
|
|
|
2016-03-06 01:04:02 +03:00
|
|
|
nsDisplayBlendMode::nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
|
Bug 1238564 - Set the innermost possible scroll clip on opacity items during creation. r=mattwoodrow
Always use an ancestor scroll clip of all direct children, or the original
scroll clip if the children don't share the same scroll clip tree.
Unfortunately this requires another pass over the stacking context display list.
Also, fix clips, scroll clips and creation order of blend items:
If a clipped mix-blend-mode item contains absolute / fixed positioned items,
those items should not be clipped, same for blend container items.
When a transform item contains blend modes, create the blend container inside
the transform.
Don't do tree comparisons on scroll clips from different scroll clip trees.
If the inner scroll clip is nullptr, because it was cleared, it will look like
it's the ancestor of the outer non-nullptr scroll clip.
These changes don't look very related, but it was very hard to get tests passing
with only some of the changes and not the others, and after having spent two
weeks on this patch I'm not thrilled about going back and checking exactly which
change was necessary to fix which test failure.
MozReview-Commit-ID: IKGciUBrdNa
--HG--
extra : rebase_source : e570f16ecedd80cba16051f0e1ac66764bc95815
extra : histedit_source : fcfbcbc254aaf93594d9d80c117d6ec945805993
2016-03-04 23:05:58 +03:00
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
2016-03-06 00:39:25 +03:00
|
|
|
uint8_t aBlendMode,
|
2016-03-08 22:22:36 +03:00
|
|
|
const DisplayItemScrollClip* aScrollClip,
|
|
|
|
uint32_t aIndex)
|
Bug 1238564 - Set the innermost possible scroll clip on opacity items during creation. r=mattwoodrow
Always use an ancestor scroll clip of all direct children, or the original
scroll clip if the children don't share the same scroll clip tree.
Unfortunately this requires another pass over the stacking context display list.
Also, fix clips, scroll clips and creation order of blend items:
If a clipped mix-blend-mode item contains absolute / fixed positioned items,
those items should not be clipped, same for blend container items.
When a transform item contains blend modes, create the blend container inside
the transform.
Don't do tree comparisons on scroll clips from different scroll clip trees.
If the inner scroll clip is nullptr, because it was cleared, it will look like
it's the ancestor of the outer non-nullptr scroll clip.
These changes don't look very related, but it was very hard to get tests passing
with only some of the changes and not the others, and after having spent two
weeks on this patch I'm not thrilled about going back and checking exactly which
change was necessary to fix which test failure.
MozReview-Commit-ID: IKGciUBrdNa
--HG--
extra : rebase_source : e570f16ecedd80cba16051f0e1ac66764bc95815
extra : histedit_source : fcfbcbc254aaf93594d9d80c117d6ec945805993
2016-03-04 23:05:58 +03:00
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
|
2016-03-06 00:39:25 +03:00
|
|
|
, mBlendMode(aBlendMode)
|
2016-03-08 22:22:36 +03:00
|
|
|
, mIndex(aIndex)
|
Bug 1238564 - Set the innermost possible scroll clip on opacity items during creation. r=mattwoodrow
Always use an ancestor scroll clip of all direct children, or the original
scroll clip if the children don't share the same scroll clip tree.
Unfortunately this requires another pass over the stacking context display list.
Also, fix clips, scroll clips and creation order of blend items:
If a clipped mix-blend-mode item contains absolute / fixed positioned items,
those items should not be clipped, same for blend container items.
When a transform item contains blend modes, create the blend container inside
the transform.
Don't do tree comparisons on scroll clips from different scroll clip trees.
If the inner scroll clip is nullptr, because it was cleared, it will look like
it's the ancestor of the outer non-nullptr scroll clip.
These changes don't look very related, but it was very hard to get tests passing
with only some of the changes and not the others, and after having spent two
weeks on this patch I'm not thrilled about going back and checking exactly which
change was necessary to fix which test failure.
MozReview-Commit-ID: IKGciUBrdNa
--HG--
extra : rebase_source : e570f16ecedd80cba16051f0e1ac66764bc95815
extra : histedit_source : fcfbcbc254aaf93594d9d80c117d6ec945805993
2016-03-04 23:05:58 +03:00
|
|
|
{
|
2016-03-06 01:04:02 +03:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayBlendMode);
|
2013-09-15 07:40:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
2016-03-06 01:04:02 +03:00
|
|
|
nsDisplayBlendMode::~nsDisplayBlendMode() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayBlendMode);
|
2013-09-15 07:40:11 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-03-06 01:04:02 +03:00
|
|
|
nsRegion nsDisplayBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
2013-09-15 07:40:11 +04:00
|
|
|
bool* aSnap) {
|
|
|
|
*aSnap = false;
|
|
|
|
// We are never considered opaque
|
|
|
|
return nsRegion();
|
|
|
|
}
|
|
|
|
|
2014-05-09 13:49:27 +04:00
|
|
|
LayerState
|
2016-03-06 01:04:02 +03:00
|
|
|
nsDisplayBlendMode::GetLayerState(nsDisplayListBuilder* aBuilder,
|
2014-05-09 13:49:27 +04:00
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
2016-02-23 21:11:21 +03:00
|
|
|
return LAYER_ACTIVE;
|
2014-05-09 13:49:27 +04:00
|
|
|
}
|
|
|
|
|
2016-03-06 01:04:02 +03:00
|
|
|
// nsDisplayBlendMode uses layers for rendering
|
2013-09-15 07:40:11 +04:00
|
|
|
already_AddRefed<Layer>
|
2016-03-06 01:04:02 +03:00
|
|
|
nsDisplayBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder,
|
2013-09-15 07:40:11 +04:00
|
|
|
LayerManager* aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aContainerParameters) {
|
|
|
|
ContainerLayerParameters newContainerParameters = aContainerParameters;
|
2013-09-16 03:48:14 +04:00
|
|
|
newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Layer> container = aManager->GetLayerBuilder()->
|
2014-06-09 08:48:00 +04:00
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
2013-09-16 03:48:14 +04:00
|
|
|
newContainerParameters, nullptr);
|
2013-09-15 07:40:11 +04:00
|
|
|
if (!container) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-09-16 03:48:14 +04:00
|
|
|
|
2016-03-06 00:39:25 +03:00
|
|
|
container->SetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mBlendMode));
|
2013-09-16 03:48:14 +04:00
|
|
|
|
2013-09-15 07:40:11 +04:00
|
|
|
return container.forget();
|
|
|
|
}
|
|
|
|
|
2016-03-06 01:04:02 +03:00
|
|
|
bool nsDisplayBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion) {
|
2013-09-15 07:40:11 +04:00
|
|
|
// Our children are need their backdrop so we should not allow them to subtract
|
|
|
|
// area from aVisibleRegion. We do need to find out what is visible under
|
|
|
|
// our children in the temporary compositing buffer, because if our children
|
|
|
|
// paint our entire bounds opaquely then we don't need an alpha channel in
|
|
|
|
// the temporary compositing buffer.
|
|
|
|
nsRect bounds = GetClippedBounds(aBuilder);
|
|
|
|
nsRegion visibleUnderChildren;
|
|
|
|
visibleUnderChildren.And(*aVisibleRegion, bounds);
|
2014-06-23 08:24:51 +04:00
|
|
|
return nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren);
|
2013-09-15 07:40:11 +04:00
|
|
|
}
|
|
|
|
|
2016-03-06 01:04:02 +03:00
|
|
|
bool nsDisplayBlendMode::TryMerge(nsDisplayItem* aItem) {
|
|
|
|
if (aItem->GetType() != TYPE_BLEND_MODE)
|
2013-09-15 07:40:11 +04:00
|
|
|
return false;
|
2016-03-08 22:22:36 +03:00
|
|
|
nsDisplayBlendMode* item = static_cast<nsDisplayBlendMode*>(aItem);
|
2013-09-15 07:40:11 +04:00
|
|
|
// items for the same content element should be merged into a single
|
|
|
|
// compositing group
|
2016-03-08 22:22:36 +03:00
|
|
|
if (item->Frame()->GetContent() != mFrame->GetContent())
|
2013-09-15 07:40:11 +04:00
|
|
|
return false;
|
2016-03-08 22:22:36 +03:00
|
|
|
if (item->mIndex != 0 || mIndex != 0)
|
|
|
|
return false; // don't merge background-blend-mode items
|
|
|
|
if (item->GetClip() != GetClip())
|
2013-09-15 07:40:11 +04:00
|
|
|
return false;
|
2016-03-08 22:22:36 +03:00
|
|
|
if (item->ScrollClip() != ScrollClip())
|
2015-12-22 18:54:19 +03:00
|
|
|
return false;
|
2016-03-08 22:22:36 +03:00
|
|
|
MergeFromTrackingMergedFrames(item);
|
2013-09-15 07:40:11 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-10 03:48:59 +03:00
|
|
|
/* static */ nsDisplayBlendContainer*
|
|
|
|
nsDisplayBlendContainer::CreateForMixBlendMode(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
|
|
|
const DisplayItemScrollClip* aScrollClip)
|
|
|
|
{
|
|
|
|
return new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, aList, aScrollClip, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ nsDisplayBlendContainer*
|
|
|
|
nsDisplayBlendContainer::CreateForBackgroundBlendMode(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
|
|
|
const DisplayItemScrollClip* aScrollClip)
|
|
|
|
{
|
|
|
|
return new (aBuilder) nsDisplayBlendContainer(aBuilder, aFrame, aList, aScrollClip, true);
|
|
|
|
}
|
|
|
|
|
2013-09-15 07:30:00 +04:00
|
|
|
nsDisplayBlendContainer::nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
2016-05-10 03:48:59 +03:00
|
|
|
const DisplayItemScrollClip* aScrollClip,
|
|
|
|
bool aIsForBackground)
|
Bug 1238564 - Set the innermost possible scroll clip on opacity items during creation. r=mattwoodrow
Always use an ancestor scroll clip of all direct children, or the original
scroll clip if the children don't share the same scroll clip tree.
Unfortunately this requires another pass over the stacking context display list.
Also, fix clips, scroll clips and creation order of blend items:
If a clipped mix-blend-mode item contains absolute / fixed positioned items,
those items should not be clipped, same for blend container items.
When a transform item contains blend modes, create the blend container inside
the transform.
Don't do tree comparisons on scroll clips from different scroll clip trees.
If the inner scroll clip is nullptr, because it was cleared, it will look like
it's the ancestor of the outer non-nullptr scroll clip.
These changes don't look very related, but it was very hard to get tests passing
with only some of the changes and not the others, and after having spent two
weeks on this patch I'm not thrilled about going back and checking exactly which
change was necessary to fix which test failure.
MozReview-Commit-ID: IKGciUBrdNa
--HG--
extra : rebase_source : e570f16ecedd80cba16051f0e1ac66764bc95815
extra : histedit_source : fcfbcbc254aaf93594d9d80c117d6ec945805993
2016-03-04 23:05:58 +03:00
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
|
2016-05-10 03:48:59 +03:00
|
|
|
, mIsForBackground(aIsForBackground)
|
2014-05-09 13:49:27 +04:00
|
|
|
{
|
2013-09-15 07:30:00 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayBlendContainer);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayBlendContainer::~nsDisplayBlendContainer() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayBlendContainer);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// nsDisplayBlendContainer uses layers for rendering
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aContainerParameters) {
|
2013-10-22 16:31:00 +04:00
|
|
|
// turn off anti-aliasing in the parent stacking context because it changes
|
|
|
|
// how the group is initialized.
|
2013-09-27 10:01:16 +04:00
|
|
|
ContainerLayerParameters newContainerParameters = aContainerParameters;
|
2013-10-22 16:31:00 +04:00
|
|
|
newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Layer> container = aManager->GetLayerBuilder()->
|
2014-06-09 08:48:00 +04:00
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
2013-10-22 16:31:00 +04:00
|
|
|
newContainerParameters, nullptr);
|
2013-09-15 07:30:00 +04:00
|
|
|
if (!container) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2016-03-09 08:14:20 +03:00
|
|
|
|
2013-09-15 07:30:00 +04:00
|
|
|
container->SetForceIsolatedGroup(true);
|
|
|
|
return container.forget();
|
|
|
|
}
|
|
|
|
|
2015-10-22 23:14:22 +03:00
|
|
|
LayerState
|
|
|
|
nsDisplayBlendContainer::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
2016-03-08 22:39:07 +03:00
|
|
|
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, GetAnimatedGeometryRoot());
|
2015-10-22 23:14:22 +03:00
|
|
|
}
|
|
|
|
|
2016-01-06 03:08:17 +03:00
|
|
|
bool nsDisplayBlendContainer::TryMerge(nsDisplayItem* aItem) {
|
2013-09-15 07:30:00 +04:00
|
|
|
if (aItem->GetType() != TYPE_BLEND_CONTAINER)
|
|
|
|
return false;
|
|
|
|
// items for the same content element should be merged into a single
|
|
|
|
// compositing group
|
|
|
|
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity
|
|
|
|
if (aItem->Frame()->GetContent() != mFrame->GetContent())
|
|
|
|
return false;
|
|
|
|
if (aItem->GetClip() != GetClip())
|
|
|
|
return false;
|
2015-12-22 18:54:19 +03:00
|
|
|
if (aItem->ScrollClip() != ScrollClip())
|
|
|
|
return false;
|
2013-09-15 07:30:00 +04:00
|
|
|
MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
|
2012-08-29 09:47:18 +04:00
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
2015-04-13 06:03:02 +03:00
|
|
|
uint32_t aFlags, ViewID aScrollTarget,
|
2016-06-30 19:09:08 +03:00
|
|
|
float aScrollbarThumbRatio,
|
|
|
|
bool aForceActive)
|
2012-08-29 09:47:18 +04:00
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList)
|
2013-12-10 07:14:53 +04:00
|
|
|
, mFlags(aFlags)
|
2015-04-13 06:03:02 +03:00
|
|
|
, mScrollTarget(aScrollTarget)
|
|
|
|
, mScrollbarThumbRatio(aScrollbarThumbRatio)
|
2016-06-30 19:09:08 +03:00
|
|
|
, mForceActive(aForceActive)
|
2015-04-13 06:03:02 +03:00
|
|
|
{
|
2010-07-16 01:08:03 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayOwnLayer);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayOwnLayer::~nsDisplayOwnLayer() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayOwnLayer);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-06-30 19:09:08 +03:00
|
|
|
LayerState
|
|
|
|
nsDisplayOwnLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
|
|
|
if (mForceActive) {
|
|
|
|
return mozilla::LAYER_ACTIVE_FORCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, mAnimatedGeometryRoot);
|
|
|
|
}
|
|
|
|
|
2010-07-16 01:08:03 +04:00
|
|
|
// nsDisplayOpacity uses layers for rendering
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
2011-06-22 16:11:27 +04:00
|
|
|
LayerManager* aManager,
|
2015-04-13 06:03:02 +03:00
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
|
2014-06-09 08:48:00 +04:00
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
2015-02-25 19:47:22 +03:00
|
|
|
aContainerParameters, nullptr,
|
|
|
|
FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
|
2013-12-10 07:14:53 +04:00
|
|
|
if (mFlags & VERTICAL_SCROLLBAR) {
|
2015-04-13 06:03:02 +03:00
|
|
|
layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL, mScrollbarThumbRatio);
|
2013-12-10 07:14:53 +04:00
|
|
|
}
|
|
|
|
if (mFlags & HORIZONTAL_SCROLLBAR) {
|
2015-04-13 06:03:02 +03:00
|
|
|
layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::HORIZONTAL, mScrollbarThumbRatio);
|
2013-12-10 07:14:53 +04:00
|
|
|
}
|
2015-01-14 10:55:17 +03:00
|
|
|
if (mFlags & SCROLLBAR_CONTAINER) {
|
|
|
|
layer->SetIsScrollbarContainer();
|
|
|
|
}
|
2012-08-29 09:47:18 +04:00
|
|
|
|
|
|
|
if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) {
|
2013-08-14 15:33:03 +04:00
|
|
|
mFrame->PresContext()->SetNotifySubDocInvalidationData(layer);
|
2012-08-29 09:47:18 +04:00
|
|
|
}
|
2010-07-16 01:08:03 +04:00
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
2014-02-28 02:01:53 +04:00
|
|
|
nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
|
|
|
uint32_t aFlags)
|
2014-04-12 03:39:22 +04:00
|
|
|
: nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags)
|
|
|
|
, mScrollParentId(aBuilder->GetCurrentScrollParentId())
|
|
|
|
{
|
2014-02-28 02:01:53 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplaySubDocument);
|
2015-02-11 00:28:07 +03:00
|
|
|
mForceDispatchToContentRegion =
|
|
|
|
aBuilder->IsBuildingLayerEventRegions() &&
|
|
|
|
nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresContext()->PresShell());
|
2014-02-28 02:01:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplaySubDocument::~nsDisplaySubDocument() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplaySubDocument);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters) {
|
2014-08-08 01:12:01 +04:00
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
|
|
|
|
ContainerLayerParameters params = aContainerParameters;
|
|
|
|
if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
|
|
|
|
rootScrollFrame->GetContent() &&
|
2015-12-17 01:22:23 +03:00
|
|
|
nsLayoutUtils::HasCriticalDisplayPort(rootScrollFrame->GetContent())) {
|
2016-03-09 08:14:20 +03:00
|
|
|
params.mInLowPrecisionDisplayPort = true;
|
2014-08-08 01:12:01 +04:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Layer> layer = nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, params);
|
2015-02-25 21:36:19 +03:00
|
|
|
layer->AsContainerLayer()->SetEventRegionsOverride(mForceDispatchToContentRegion
|
|
|
|
? EventRegionsOverride::ForceDispatchToContent
|
|
|
|
: EventRegionsOverride::NoOverride);
|
2015-02-11 00:28:07 +03:00
|
|
|
return layer.forget();
|
2014-08-31 07:29:24 +04:00
|
|
|
}
|
2014-02-28 02:01:53 +04:00
|
|
|
|
2016-03-29 02:14:52 +03:00
|
|
|
UniquePtr<ScrollMetadata>
|
|
|
|
nsDisplaySubDocument::ComputeScrollMetadata(Layer* aLayer,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
2014-08-31 07:29:24 +04:00
|
|
|
{
|
2014-02-28 02:01:53 +04:00
|
|
|
if (!(mFlags & GENERATE_SCROLLABLE_LAYER)) {
|
2016-03-29 02:14:52 +03:00
|
|
|
return UniquePtr<ScrollMetadata>(nullptr);
|
2014-02-28 02:01:53 +04:00
|
|
|
}
|
|
|
|
|
2014-08-31 07:29:24 +04:00
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
|
|
|
|
bool isRootContentDocument = presContext->IsRootContentDocument();
|
2014-11-21 21:50:41 +03:00
|
|
|
nsIPresShell* presShell = presContext->PresShell();
|
2015-02-27 23:36:31 +03:00
|
|
|
ContainerLayerParameters params(
|
2015-03-07 02:07:59 +03:00
|
|
|
aContainerParameters.mXScale * presShell->GetResolution(),
|
|
|
|
aContainerParameters.mYScale * presShell->GetResolution(),
|
2015-02-27 23:36:31 +03:00
|
|
|
nsIntPoint(), aContainerParameters);
|
2014-08-31 07:29:24 +04:00
|
|
|
if ((mFlags & GENERATE_SCROLLABLE_LAYER) &&
|
|
|
|
rootScrollFrame->GetContent() &&
|
2015-12-17 01:22:23 +03:00
|
|
|
nsLayoutUtils::HasCriticalDisplayPort(rootScrollFrame->GetContent())) {
|
2014-08-31 07:29:24 +04:00
|
|
|
params.mInLowPrecisionDisplayPort = true;
|
2014-09-02 02:20:13 +04:00
|
|
|
}
|
2014-08-31 07:29:24 +04:00
|
|
|
|
2014-08-31 07:29:24 +04:00
|
|
|
nsRect viewport = mFrame->GetRect() -
|
|
|
|
mFrame->GetPosition() +
|
|
|
|
mFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
|
|
|
|
2016-03-29 02:14:52 +03:00
|
|
|
return MakeUnique<ScrollMetadata>(
|
|
|
|
nsLayoutUtils::ComputeScrollMetadata(
|
2015-02-13 04:49:10 +03:00
|
|
|
mFrame, rootScrollFrame, rootScrollFrame->GetContent(), ReferenceFrame(),
|
2015-05-26 22:40:24 +03:00
|
|
|
aLayer, mScrollParentId, viewport, Nothing(),
|
2015-02-13 04:49:10 +03:00
|
|
|
isRootContentDocument, params));
|
2014-02-28 02:01:53 +04:00
|
|
|
}
|
|
|
|
|
2014-10-21 01:32:11 +04:00
|
|
|
static bool
|
2016-01-08 03:27:48 +03:00
|
|
|
UseDisplayPortForViewport(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
|
2014-10-21 01:32:11 +04:00
|
|
|
{
|
|
|
|
return aBuilder->IsPaintingToWindow() &&
|
2016-01-08 03:27:48 +03:00
|
|
|
nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext());
|
2014-10-21 01:32:11 +04:00
|
|
|
}
|
|
|
|
|
2014-02-28 02:01:54 +04:00
|
|
|
nsRect
|
|
|
|
nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
|
|
|
{
|
2014-10-21 01:32:11 +04:00
|
|
|
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
|
2014-02-28 02:01:54 +04:00
|
|
|
|
2014-02-28 02:01:54 +04:00
|
|
|
if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) {
|
|
|
|
*aSnap = false;
|
|
|
|
return mFrame->GetRect() + aBuilder->ToReferenceFrame(mFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsDisplayOwnLayer::GetBounds(aBuilder, aSnap);
|
|
|
|
}
|
|
|
|
|
2014-02-28 02:01:54 +04:00
|
|
|
bool
|
|
|
|
nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion* aVisibleRegion)
|
2014-02-28 02:01:54 +04:00
|
|
|
{
|
2016-01-08 03:27:48 +03:00
|
|
|
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
|
2014-02-28 02:01:54 +04:00
|
|
|
|
|
|
|
if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) {
|
2014-06-23 08:24:51 +04:00
|
|
|
return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion);
|
2014-02-28 02:01:54 +04:00
|
|
|
}
|
|
|
|
|
2016-01-08 03:27:48 +03:00
|
|
|
nsRect displayport;
|
|
|
|
nsIFrame* rootScrollFrame = mFrame->PresContext()->PresShell()->GetRootScrollFrame();
|
|
|
|
MOZ_ASSERT(rootScrollFrame);
|
2016-01-08 03:27:49 +03:00
|
|
|
Unused << nsLayoutUtils::GetDisplayPort(rootScrollFrame->GetContent(), &displayport,
|
|
|
|
RelativeTo::ScrollFrame);
|
2016-01-08 03:27:48 +03:00
|
|
|
|
2014-02-28 02:01:54 +04:00
|
|
|
nsRegion childVisibleRegion;
|
|
|
|
// The visible region for the children may be much bigger than the hole we
|
|
|
|
// are viewing the children from, so that the compositor process has enough
|
|
|
|
// content to asynchronously pan while content is being refreshed.
|
|
|
|
childVisibleRegion = displayport + mFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
|
|
|
|
|
|
|
nsRect boundedRect =
|
|
|
|
childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder));
|
|
|
|
bool visible = mList.ComputeVisibilityForSublist(
|
2016-01-06 03:08:17 +03:00
|
|
|
aBuilder, &childVisibleRegion, boundedRect);
|
2014-07-24 07:13:23 +04:00
|
|
|
|
|
|
|
// If APZ is enabled then don't allow this computation to influence
|
|
|
|
// aVisibleRegion, on the assumption that the layer can be asynchronously
|
|
|
|
// scrolled so we'll definitely need all the content under it.
|
2015-06-04 23:51:10 +03:00
|
|
|
if (!nsLayoutUtils::UsesAsyncScrolling(mFrame)) {
|
2014-07-24 07:13:23 +04:00
|
|
|
bool snap;
|
|
|
|
nsRect bounds = GetBounds(aBuilder, &snap);
|
|
|
|
nsRegion removed;
|
|
|
|
removed.Sub(bounds, childVisibleRegion);
|
|
|
|
|
|
|
|
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
|
|
|
|
}
|
2014-02-28 02:01:54 +04:00
|
|
|
|
|
|
|
return visible;
|
|
|
|
}
|
|
|
|
|
2014-02-28 02:01:54 +04:00
|
|
|
bool
|
|
|
|
nsDisplaySubDocument::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
2014-10-21 01:32:11 +04:00
|
|
|
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
|
2014-02-28 02:01:54 +04:00
|
|
|
|
2014-02-28 02:01:54 +04:00
|
|
|
if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsDisplayOwnLayer::ShouldBuildLayerEvenIfInvisible(aBuilder);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRegion
|
|
|
|
nsDisplaySubDocument::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
|
|
|
{
|
2014-10-21 01:32:11 +04:00
|
|
|
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
|
2014-02-28 02:01:54 +04:00
|
|
|
|
2014-02-28 02:01:54 +04:00
|
|
|
if ((mFlags & GENERATE_SCROLLABLE_LAYER) && usingDisplayPort) {
|
|
|
|
*aSnap = false;
|
|
|
|
return nsRegion();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsDisplayOwnLayer::GetOpaqueRegion(aBuilder, aSnap);
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:27:15 +04:00
|
|
|
nsDisplayResolution::nsDisplayResolution(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
|
|
|
uint32_t aFlags)
|
2014-02-28 02:01:53 +04:00
|
|
|
: nsDisplaySubDocument(aBuilder, aFrame, aList, aFlags) {
|
2013-10-29 17:27:15 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayResolution);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayResolution::~nsDisplayResolution() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayResolution);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-11-27 05:51:13 +03:00
|
|
|
void
|
|
|
|
nsDisplayResolution::HitTest(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsRect& aRect,
|
|
|
|
HitTestState* aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames)
|
|
|
|
{
|
|
|
|
nsIPresShell* presShell = mFrame->PresContext()->PresShell();
|
|
|
|
nsRect rect = aRect.RemoveResolution(presShell->ScaleToResolution() ? presShell->GetResolution () : 1.0f);
|
|
|
|
mList.HitTest(aBuilder, rect, aState, aOutFrames);
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:27:15 +04:00
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayResolution::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aContainerParameters) {
|
2013-10-29 17:27:15 +04:00
|
|
|
nsIPresShell* presShell = mFrame->PresContext()->PresShell();
|
2013-09-27 10:01:16 +04:00
|
|
|
ContainerLayerParameters containerParameters(
|
2015-03-07 02:07:59 +03:00
|
|
|
presShell->GetResolution(), presShell->GetResolution(), nsIntPoint(),
|
2013-10-29 17:27:15 +04:00
|
|
|
aContainerParameters);
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Layer> layer = nsDisplaySubDocument::BuildLayer(
|
2013-10-29 17:27:15 +04:00
|
|
|
aBuilder, aManager, containerParameters);
|
2015-03-07 02:07:59 +03:00
|
|
|
layer->SetPostScale(1.0f / presShell->GetResolution(),
|
|
|
|
1.0f / presShell->GetResolution());
|
2015-01-03 04:06:14 +03:00
|
|
|
layer->AsContainerLayer()->SetScaleToResolution(
|
2015-03-07 02:07:59 +03:00
|
|
|
presShell->ScaleToResolution(), presShell->GetResolution());
|
2013-10-29 17:27:15 +04:00
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
2016-01-26 03:36:48 +03:00
|
|
|
nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsDisplayList* aList)
|
|
|
|
: nsDisplayOwnLayer(aBuilder, aFrame, aList)
|
|
|
|
, mIndex(0)
|
|
|
|
, mIsFixedBackground(false)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayFixedPosition);
|
|
|
|
Init(aBuilder);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsDisplayList* aList,
|
|
|
|
uint32_t aIndex)
|
|
|
|
: nsDisplayOwnLayer(aBuilder, aFrame, aList)
|
|
|
|
, mIndex(aIndex)
|
|
|
|
, mIsFixedBackground(true)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayFixedPosition);
|
|
|
|
Init(aBuilder);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayFixedPosition::Init(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
|
|
|
mAnimatedGeometryRootForScrollMetadata = mAnimatedGeometryRoot;
|
|
|
|
if (ShouldFixToViewport(aBuilder)) {
|
|
|
|
mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ nsDisplayFixedPosition*
|
|
|
|
nsDisplayFixedPosition::CreateForFixedBackground(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsDisplayBackgroundImage* aImage,
|
|
|
|
uint32_t aIndex)
|
|
|
|
{
|
|
|
|
// Clear clipping on the child item, since we will apply it to the
|
|
|
|
// fixed position item as well.
|
|
|
|
aImage->SetClip(aBuilder, DisplayItemClip());
|
|
|
|
aImage->SetScrollClip(nullptr);
|
|
|
|
|
|
|
|
nsDisplayList temp;
|
|
|
|
temp.AppendToTop(aImage);
|
|
|
|
|
|
|
|
return new (aBuilder) nsDisplayFixedPosition(aBuilder, aFrame, &temp, aIndex + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayFixedPosition::~nsDisplayFixedPosition() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayFixedPosition);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters) {
|
|
|
|
RefPtr<Layer> layer =
|
|
|
|
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
|
|
|
|
|
|
|
|
layer->SetIsFixedPosition(true);
|
|
|
|
|
2016-08-22 20:32:57 +03:00
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
nsIFrame* fixedFrame = mIsFixedBackground ? presContext->PresShell()->GetRootFrame() : mFrame;
|
2016-01-26 03:36:48 +03:00
|
|
|
|
|
|
|
const nsIFrame* viewportFrame = fixedFrame->GetParent();
|
|
|
|
// anchorRect will be in the container's coordinate system (aLayer's parent layer).
|
|
|
|
// This is the same as the display items' reference frame.
|
|
|
|
nsRect anchorRect;
|
|
|
|
if (viewportFrame) {
|
|
|
|
// Fixed position frames are reflowed into the scroll-port size if one has
|
|
|
|
// been set.
|
|
|
|
if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
|
|
|
|
anchorRect.SizeTo(presContext->PresShell()->GetScrollPositionClampingScrollPortSize());
|
|
|
|
} else {
|
|
|
|
anchorRect.SizeTo(viewportFrame->GetSize());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// A display item directly attached to the viewport.
|
|
|
|
// For background-attachment:fixed items, the anchor point is always the
|
|
|
|
// top-left of the viewport currently.
|
|
|
|
viewportFrame = fixedFrame;
|
|
|
|
}
|
|
|
|
// The anchorRect top-left is always the viewport top-left.
|
|
|
|
anchorRect.MoveTo(viewportFrame->GetOffsetToCrossDoc(ReferenceFrame()));
|
|
|
|
|
|
|
|
nsLayoutUtils::SetFixedPositionLayerData(layer,
|
2016-05-05 03:07:42 +03:00
|
|
|
viewportFrame, anchorRect, fixedFrame, presContext, aContainerParameters);
|
2016-01-26 03:36:48 +03:00
|
|
|
|
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool nsDisplayFixedPosition::TryMerge(nsDisplayItem* aItem) {
|
|
|
|
if (aItem->GetType() != TYPE_FIXED_POSITION)
|
|
|
|
return false;
|
|
|
|
// Items with the same fixed position frame can be merged.
|
|
|
|
nsDisplayFixedPosition* other = static_cast<nsDisplayFixedPosition*>(aItem);
|
|
|
|
if (other->mFrame != mFrame)
|
|
|
|
return false;
|
|
|
|
if (aItem->GetClip() != GetClip())
|
|
|
|
return false;
|
|
|
|
MergeFromTrackingMergedFrames(other);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-13 05:56:57 +04:00
|
|
|
nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsDisplayList* aList)
|
2013-09-27 10:02:03 +04:00
|
|
|
: nsDisplayOwnLayer(aBuilder, aFrame, aList)
|
2014-01-04 09:14:27 +04:00
|
|
|
{
|
2013-09-13 05:56:57 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayStickyPosition::~nsDisplayStickyPosition() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayStickyPosition);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aContainerParameters) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Layer> layer =
|
2013-09-13 05:56:57 +04:00
|
|
|
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
|
|
|
|
|
|
|
|
StickyScrollContainer* stickyScrollContainer = StickyScrollContainer::
|
|
|
|
GetStickyScrollContainerForFrame(mFrame);
|
|
|
|
if (!stickyScrollContainer) {
|
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame());
|
|
|
|
nsPresContext* presContext = scrollFrame->PresContext();
|
|
|
|
|
|
|
|
// Sticky position frames whose scroll frame is the root scroll frame are
|
|
|
|
// reflowed into the scroll-port size if one has been set.
|
|
|
|
nsSize scrollFrameSize = scrollFrame->GetSize();
|
|
|
|
if (scrollFrame == presContext->PresShell()->GetRootScrollFrame() &&
|
|
|
|
presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
|
|
|
|
scrollFrameSize = presContext->PresShell()->
|
|
|
|
GetScrollPositionClampingScrollPortSize();
|
|
|
|
}
|
|
|
|
|
2013-12-17 15:30:21 +04:00
|
|
|
nsLayoutUtils::SetFixedPositionLayerData(layer, scrollFrame,
|
|
|
|
nsRect(scrollFrame->GetOffsetToCrossDoc(ReferenceFrame()), scrollFrameSize),
|
2016-05-05 03:07:42 +03:00
|
|
|
mFrame, presContext, aContainerParameters);
|
2013-09-13 05:56:57 +04:00
|
|
|
|
|
|
|
ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(
|
|
|
|
stickyScrollContainer->ScrollFrame()->GetScrolledFrame()->GetContent());
|
|
|
|
|
|
|
|
float factor = presContext->AppUnitsPerDevPixel();
|
|
|
|
nsRect outer;
|
|
|
|
nsRect inner;
|
|
|
|
stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
|
|
|
|
LayerRect stickyOuter(NSAppUnitsToFloatPixels(outer.x, factor) *
|
|
|
|
aContainerParameters.mXScale,
|
|
|
|
NSAppUnitsToFloatPixels(outer.y, factor) *
|
|
|
|
aContainerParameters.mYScale,
|
|
|
|
NSAppUnitsToFloatPixels(outer.width, factor) *
|
|
|
|
aContainerParameters.mXScale,
|
|
|
|
NSAppUnitsToFloatPixels(outer.height, factor) *
|
|
|
|
aContainerParameters.mYScale);
|
|
|
|
LayerRect stickyInner(NSAppUnitsToFloatPixels(inner.x, factor) *
|
|
|
|
aContainerParameters.mXScale,
|
|
|
|
NSAppUnitsToFloatPixels(inner.y, factor) *
|
|
|
|
aContainerParameters.mYScale,
|
|
|
|
NSAppUnitsToFloatPixels(inner.width, factor) *
|
|
|
|
aContainerParameters.mXScale,
|
|
|
|
NSAppUnitsToFloatPixels(inner.height, factor) *
|
|
|
|
aContainerParameters.mYScale);
|
|
|
|
layer->SetStickyPositionData(scrollId, stickyOuter, stickyInner);
|
|
|
|
|
|
|
|
return layer.forget();
|
|
|
|
}
|
|
|
|
|
2016-01-06 03:08:17 +03:00
|
|
|
bool nsDisplayStickyPosition::TryMerge(nsDisplayItem* aItem) {
|
2013-09-27 10:02:03 +04:00
|
|
|
if (aItem->GetType() != TYPE_STICKY_POSITION)
|
|
|
|
return false;
|
|
|
|
// Items with the same fixed position frame can be merged.
|
|
|
|
nsDisplayStickyPosition* other = static_cast<nsDisplayStickyPosition*>(aItem);
|
2014-01-04 09:14:27 +04:00
|
|
|
if (other->mFrame != mFrame)
|
2013-09-27 10:02:03 +04:00
|
|
|
return false;
|
|
|
|
if (aItem->GetClip() != GetClip())
|
|
|
|
return false;
|
2015-12-22 18:54:19 +03:00
|
|
|
if (aItem->ScrollClip() != ScrollClip())
|
|
|
|
return false;
|
2013-09-27 10:02:03 +04:00
|
|
|
MergeFromTrackingMergedFrames(other);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-04-21 06:48:10 +03:00
|
|
|
nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
|
|
|
|
nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aScrolledFrame,
|
|
|
|
nsIFrame* aScrollFrame)
|
|
|
|
: nsDisplayWrapList(aBuilder, aScrollFrame)
|
2011-05-02 05:53:01 +04:00
|
|
|
, mScrollFrame(aScrollFrame)
|
|
|
|
, mScrolledFrame(aScrolledFrame)
|
2014-04-12 03:39:22 +04:00
|
|
|
, mScrollParentId(aBuilder->GetCurrentScrollParentId())
|
2011-01-13 20:45:14 +03:00
|
|
|
{
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
2015-04-21 06:48:10 +03:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayScrollInfoLayer);
|
2011-01-13 20:45:14 +03:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-05-02 05:53:01 +04:00
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
2015-04-21 06:48:10 +03:00
|
|
|
nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer()
|
2011-05-02 05:53:01 +04:00
|
|
|
{
|
2015-04-21 06:48:10 +03:00
|
|
|
MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
|
2011-05-02 05:53:01 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-04-21 06:48:10 +03:00
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayScrollInfoLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
2014-06-23 08:23:58 +04:00
|
|
|
{
|
2015-04-21 06:48:10 +03:00
|
|
|
// In general for APZ with event-regions we no longer have a need for
|
|
|
|
// scrollinfo layers. However, in some cases, there might be content that
|
|
|
|
// cannot be layerized, and so needs to scroll synchronously. To handle those
|
2015-04-30 21:54:48 +03:00
|
|
|
// cases, we still want to generate scrollinfo layers.
|
2014-06-23 08:23:58 +04:00
|
|
|
|
2014-08-08 01:12:01 +04:00
|
|
|
ContainerLayerParameters params = aContainerParameters;
|
|
|
|
if (mScrolledFrame->GetContent() &&
|
2015-12-17 01:22:23 +03:00
|
|
|
nsLayoutUtils::HasCriticalDisplayPort(mScrolledFrame->GetContent())) {
|
2014-08-31 07:29:24 +04:00
|
|
|
params.mInLowPrecisionDisplayPort = true;
|
2014-08-08 01:12:01 +04:00
|
|
|
}
|
|
|
|
|
2014-08-31 07:29:24 +04:00
|
|
|
return aManager->GetLayerBuilder()->
|
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
2015-02-25 19:47:22 +03:00
|
|
|
params, nullptr,
|
|
|
|
FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
|
2011-01-13 20:45:14 +03:00
|
|
|
}
|
|
|
|
|
2015-04-21 06:48:10 +03:00
|
|
|
LayerState
|
|
|
|
nsDisplayScrollInfoLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
2015-04-30 21:54:48 +03:00
|
|
|
return LAYER_ACTIVE_EMPTY;
|
2015-04-21 06:48:10 +03:00
|
|
|
}
|
|
|
|
|
2016-03-29 02:14:52 +03:00
|
|
|
UniquePtr<ScrollMetadata>
|
|
|
|
nsDisplayScrollInfoLayer::ComputeScrollMetadata(Layer* aLayer,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
2014-06-23 08:23:58 +04:00
|
|
|
{
|
2014-08-31 07:29:24 +04:00
|
|
|
ContainerLayerParameters params = aContainerParameters;
|
|
|
|
if (mScrolledFrame->GetContent() &&
|
2015-12-17 01:22:23 +03:00
|
|
|
nsLayoutUtils::HasCriticalDisplayPort(mScrolledFrame->GetContent())) {
|
2016-03-09 08:14:20 +03:00
|
|
|
params.mInLowPrecisionDisplayPort = true;
|
2014-08-31 07:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRect viewport = mScrollFrame->GetRect() -
|
|
|
|
mScrollFrame->GetPosition() +
|
|
|
|
mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
|
|
|
|
2016-03-29 02:14:52 +03:00
|
|
|
ScrollMetadata metadata = nsLayoutUtils::ComputeScrollMetadata(
|
2015-02-13 04:49:10 +03:00
|
|
|
mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(),
|
|
|
|
ReferenceFrame(), aLayer,
|
2015-12-21 17:36:36 +03:00
|
|
|
mScrollParentId, viewport, Nothing(), false, params);
|
2016-03-29 02:14:52 +03:00
|
|
|
metadata.GetMetrics().SetIsScrollInfoLayer(true);
|
2015-12-21 17:36:36 +03:00
|
|
|
|
2016-03-29 02:14:52 +03:00
|
|
|
return UniquePtr<ScrollMetadata>(new ScrollMetadata(metadata));
|
2014-06-23 08:23:58 +04:00
|
|
|
}
|
|
|
|
|
2015-09-05 03:17:50 +03:00
|
|
|
|
2011-05-02 05:53:01 +04:00
|
|
|
|
2014-01-27 02:09:06 +04:00
|
|
|
void
|
2015-04-21 06:48:10 +03:00
|
|
|
nsDisplayScrollInfoLayer::WriteDebugInfo(std::stringstream& aStream)
|
2014-01-27 02:09:06 +04:00
|
|
|
{
|
2014-11-25 16:45:19 +03:00
|
|
|
aStream << " (scrollframe " << mScrollFrame
|
|
|
|
<< " scrolledFrame " << mScrolledFrame << ")";
|
2014-01-27 02:09:06 +04:00
|
|
|
}
|
|
|
|
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
2012-08-29 09:47:18 +04:00
|
|
|
int32_t aAPD, int32_t aParentAPD,
|
|
|
|
uint32_t aFlags)
|
2014-02-28 02:01:53 +04:00
|
|
|
: nsDisplaySubDocument(aBuilder, aFrame, aList, aFlags)
|
2012-08-29 09:47:18 +04:00
|
|
|
, mAPD(aAPD), mParentAPD(aParentAPD) {
|
2010-07-19 06:23:48 +04:00
|
|
|
MOZ_COUNT_CTOR(nsDisplayZoom);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayZoom::~nsDisplayZoom() {
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayZoom);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-04-10 15:24:18 +04:00
|
|
|
nsRect nsDisplayZoom::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
2010-07-19 06:23:48 +04:00
|
|
|
{
|
2014-03-07 03:40:31 +04:00
|
|
|
nsRect bounds = nsDisplaySubDocument::GetBounds(aBuilder, aSnap);
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = false;
|
2015-03-27 00:44:40 +03:00
|
|
|
return bounds.ScaleToOtherAppUnitsRoundOut(mAPD, mParentAPD);
|
2010-07-19 06:23:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void nsDisplayZoom::HitTest(nsDisplayListBuilder *aBuilder,
|
|
|
|
const nsRect& aRect,
|
|
|
|
HitTestState *aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames)
|
|
|
|
{
|
|
|
|
nsRect rect;
|
|
|
|
// A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
|
|
|
|
// rect as well instead of possibly rounding the width or height to zero.
|
|
|
|
if (aRect.width == 1 && aRect.height == 1) {
|
2015-03-27 00:44:40 +03:00
|
|
|
rect.MoveTo(aRect.TopLeft().ScaleToOtherAppUnits(mParentAPD, mAPD));
|
2010-07-19 06:23:48 +04:00
|
|
|
rect.width = rect.height = 1;
|
|
|
|
} else {
|
2015-03-27 00:44:40 +03:00
|
|
|
rect = aRect.ScaleToOtherAppUnitsRoundOut(mParentAPD, mAPD);
|
2010-07-19 06:23:48 +04:00
|
|
|
}
|
|
|
|
mList.HitTest(aBuilder, rect, aState, aOutFrames);
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion *aVisibleRegion)
|
2010-07-19 06:23:48 +04:00
|
|
|
{
|
|
|
|
// Convert the passed in visible region to our appunits.
|
2013-03-04 13:56:02 +04:00
|
|
|
nsRegion visibleRegion;
|
|
|
|
// mVisibleRect has been clipped to GetClippedBounds
|
|
|
|
visibleRegion.And(*aVisibleRegion, mVisibleRect);
|
2015-03-27 00:44:40 +03:00
|
|
|
visibleRegion = visibleRegion.ScaleToOtherAppUnitsRoundOut(mParentAPD, mAPD);
|
2010-07-19 06:23:48 +04:00
|
|
|
nsRegion originalVisibleRegion = visibleRegion;
|
|
|
|
|
2010-08-28 03:15:08 +04:00
|
|
|
nsRect transformedVisibleRect =
|
2015-03-27 00:44:40 +03:00
|
|
|
mVisibleRect.ScaleToOtherAppUnitsRoundOut(mParentAPD, mAPD);
|
2014-03-07 03:40:31 +04:00
|
|
|
bool retval;
|
|
|
|
// If we are to generate a scrollable layer we call
|
|
|
|
// nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments
|
|
|
|
// for ComputeVisibility, it does all it's calculations in the child APD.
|
2014-10-21 01:32:11 +04:00
|
|
|
bool usingDisplayPort = UseDisplayPortForViewport(aBuilder, mFrame);
|
2014-03-07 03:40:31 +04:00
|
|
|
if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) {
|
|
|
|
retval =
|
|
|
|
mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion,
|
2014-06-23 08:24:51 +04:00
|
|
|
transformedVisibleRect);
|
2014-03-07 03:40:31 +04:00
|
|
|
} else {
|
|
|
|
retval =
|
2014-06-23 08:24:51 +04:00
|
|
|
nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion);
|
2014-03-07 03:40:31 +04:00
|
|
|
}
|
2010-07-19 06:23:48 +04:00
|
|
|
|
|
|
|
nsRegion removed;
|
|
|
|
// removed = originalVisibleRegion - visibleRegion
|
|
|
|
removed.Sub(originalVisibleRegion, visibleRegion);
|
|
|
|
// Convert removed region to parent appunits.
|
2015-03-27 00:44:40 +03:00
|
|
|
removed = removed.ScaleToOtherAppUnitsRoundIn(mAPD, mParentAPD);
|
2010-07-19 06:23:48 +04:00
|
|
|
// aVisibleRegion = aVisibleRegion - removed (modulo any simplifications
|
|
|
|
// SubtractFromVisibleRegion does)
|
2011-05-13 20:40:46 +04:00
|
|
|
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed);
|
2010-07-19 06:23:48 +04:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
2008-09-13 13:42:11 +04:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////
|
|
|
|
// nsDisplayTransform Implementation
|
|
|
|
//
|
|
|
|
|
2015-04-28 21:55:42 +03:00
|
|
|
// Write #define UNIFIED_CONTINUATIONS here and in
|
|
|
|
// TransformReferenceBox::Initialize to have the transform property try
|
2008-09-13 13:42:11 +04:00
|
|
|
// to transform content with continuations as one unified block instead of
|
|
|
|
// several smaller ones. This is currently disabled because it doesn't work
|
2009-07-27 12:47:02 +04:00
|
|
|
// correctly, since when the frames are initially being reflowed, their
|
2008-09-13 13:42:11 +04:00
|
|
|
// continuations all compute their bounding rects independently of each other
|
|
|
|
// and consequently get the wrong value. Write #define DEBUG_HIT here to have
|
|
|
|
// the nsDisplayTransform class dump out a bunch of information about hit
|
|
|
|
// detection.
|
|
|
|
#undef UNIFIED_CONTINUATIONS
|
|
|
|
#undef DEBUG_HIT
|
|
|
|
|
2014-07-15 15:47:46 +04:00
|
|
|
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame *aFrame, nsDisplayList *aList,
|
|
|
|
const nsRect& aChildrenVisibleRect,
|
|
|
|
ComputeTransformFunction aTransformGetter,
|
2015-09-17 04:31:00 +03:00
|
|
|
uint32_t aIndex)
|
2012-09-20 03:14:07 +04:00
|
|
|
: nsDisplayItem(aBuilder, aFrame)
|
|
|
|
, mStoredList(aBuilder, aFrame, aList)
|
|
|
|
, mTransformGetter(aTransformGetter)
|
2016-01-21 07:02:31 +03:00
|
|
|
, mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot)
|
|
|
|
, mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot)
|
2014-07-15 15:47:46 +04:00
|
|
|
, mChildrenVisibleRect(aChildrenVisibleRect)
|
2012-09-20 03:14:07 +04:00
|
|
|
, mIndex(aIndex)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mNoExtendContext(false)
|
2015-10-18 13:13:00 +03:00
|
|
|
, mIsTransformSeparator(false)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mTransformPreserves3DInited(false)
|
2016-11-23 20:49:35 +03:00
|
|
|
, mAllowAsyncAnimation(false)
|
2012-09-20 03:14:07 +04:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayTransform);
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(aFrame, "Must have a frame!");
|
2014-07-29 16:09:35 +04:00
|
|
|
Init(aBuilder);
|
2012-09-20 03:14:07 +04:00
|
|
|
}
|
|
|
|
|
2014-06-09 08:47:59 +04:00
|
|
|
void
|
|
|
|
nsDisplayTransform::SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
2015-11-03 11:03:47 +03:00
|
|
|
if (mFrame == aBuilder->RootReferenceFrame()) {
|
|
|
|
return;
|
|
|
|
}
|
2015-09-17 04:31:00 +03:00
|
|
|
nsIFrame *outerFrame = nsLayoutUtils::GetCrossDocParentFrame(mFrame);
|
2014-06-09 08:47:59 +04:00
|
|
|
mReferenceFrame =
|
2015-09-17 04:31:00 +03:00
|
|
|
aBuilder->FindReferenceFrameFor(outerFrame);
|
2014-06-09 08:47:59 +04:00
|
|
|
mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame);
|
2015-11-15 21:32:31 +03:00
|
|
|
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(mFrame)) {
|
|
|
|
// This is an odd special case. If we are both IsFixedPosFrameInDisplayPort
|
|
|
|
// and transformed that we are our own AGR parent.
|
|
|
|
// We want our frame to be our AGR because FrameLayerBuilder uses our AGR to
|
|
|
|
// determine if we are inside a fixed pos subtree. If we use the outer AGR
|
|
|
|
// from outside the fixed pos subtree FLB can't tell that we are fixed pos.
|
2015-11-25 01:53:51 +03:00
|
|
|
mAnimatedGeometryRoot = mAnimatedGeometryRootForChildren;
|
2015-12-31 08:00:47 +03:00
|
|
|
} else if (mFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY &&
|
|
|
|
IsStickyFrameActive(aBuilder, mFrame, nullptr)) {
|
|
|
|
// Similar to the IsFixedPosFrameInDisplayPort case we are our own AGR.
|
|
|
|
// We are inside the sticky position, so our AGR is the sticky positioned
|
|
|
|
// frame, which is our AGR, not the parent AGR.
|
|
|
|
mAnimatedGeometryRoot = mAnimatedGeometryRootForChildren;
|
2015-11-26 23:57:31 +03:00
|
|
|
} else if (mAnimatedGeometryRoot->mParentAGR) {
|
2016-01-21 07:02:31 +03:00
|
|
|
mAnimatedGeometryRootForScrollMetadata = mAnimatedGeometryRoot->mParentAGR;
|
|
|
|
if (!MayBeAnimated(aBuilder)) {
|
|
|
|
// If we're an animated transform then we want the same AGR as our children
|
|
|
|
// so that FrameLayerBuilder knows that this layer moves with the transform
|
|
|
|
// and won't compute occlusions. If we're not animated then use our parent
|
|
|
|
// AGR so that inactive transform layers can go in the same PaintedLayer as
|
|
|
|
// surrounding content.
|
|
|
|
mAnimatedGeometryRoot = mAnimatedGeometryRoot->mParentAGR;
|
|
|
|
}
|
2015-11-15 21:32:31 +03:00
|
|
|
}
|
2014-06-09 08:47:59 +04:00
|
|
|
mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame;
|
|
|
|
}
|
|
|
|
|
2014-07-29 16:09:35 +04:00
|
|
|
void
|
|
|
|
nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
2015-10-18 13:13:00 +03:00
|
|
|
mHasBounds = false;
|
2014-07-29 16:09:35 +04:00
|
|
|
mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip());
|
2014-08-11 06:59:02 +04:00
|
|
|
mStoredList.SetVisibleRect(mChildrenVisibleRect);
|
2014-07-29 16:09:35 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 15:47:46 +04:00
|
|
|
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame *aFrame, nsDisplayList *aList,
|
|
|
|
const nsRect& aChildrenVisibleRect,
|
2016-05-18 06:12:44 +03:00
|
|
|
uint32_t aIndex,
|
2016-11-23 20:49:35 +03:00
|
|
|
bool aAllowAsyncAnimation)
|
2012-09-20 03:14:07 +04:00
|
|
|
: nsDisplayItem(aBuilder, aFrame)
|
|
|
|
, mStoredList(aBuilder, aFrame, aList)
|
|
|
|
, mTransformGetter(nullptr)
|
2016-01-21 07:02:31 +03:00
|
|
|
, mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot)
|
|
|
|
, mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot)
|
2014-07-15 15:47:46 +04:00
|
|
|
, mChildrenVisibleRect(aChildrenVisibleRect)
|
2012-09-20 03:14:07 +04:00
|
|
|
, mIndex(aIndex)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mNoExtendContext(false)
|
2015-10-18 13:13:00 +03:00
|
|
|
, mIsTransformSeparator(false)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mTransformPreserves3DInited(false)
|
2016-11-23 20:49:35 +03:00
|
|
|
, mAllowAsyncAnimation(aAllowAsyncAnimation)
|
2012-09-16 14:32:59 +04:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayTransform);
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(aFrame, "Must have a frame!");
|
2014-06-09 08:47:59 +04:00
|
|
|
SetReferenceFrameToAncestor(aBuilder);
|
2014-07-29 16:09:35 +04:00
|
|
|
Init(aBuilder);
|
2015-10-18 13:13:00 +03:00
|
|
|
UpdateBoundsFor3D(aBuilder);
|
2012-09-16 14:32:59 +04:00
|
|
|
}
|
|
|
|
|
2014-07-15 15:47:46 +04:00
|
|
|
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame *aFrame, nsDisplayItem *aItem,
|
|
|
|
const nsRect& aChildrenVisibleRect,
|
|
|
|
uint32_t aIndex)
|
2014-02-27 06:57:45 +04:00
|
|
|
: nsDisplayItem(aBuilder, aFrame)
|
|
|
|
, mStoredList(aBuilder, aFrame, aItem)
|
|
|
|
, mTransformGetter(nullptr)
|
2016-01-21 07:02:31 +03:00
|
|
|
, mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot)
|
|
|
|
, mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot)
|
2014-07-15 15:47:46 +04:00
|
|
|
, mChildrenVisibleRect(aChildrenVisibleRect)
|
2014-02-27 06:57:45 +04:00
|
|
|
, mIndex(aIndex)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mNoExtendContext(false)
|
2015-10-18 13:13:00 +03:00
|
|
|
, mIsTransformSeparator(false)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mTransformPreserves3DInited(false)
|
2016-11-23 20:49:35 +03:00
|
|
|
, mAllowAsyncAnimation(false)
|
2014-02-27 06:57:45 +04:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayTransform);
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(aFrame, "Must have a frame!");
|
2014-06-09 08:47:59 +04:00
|
|
|
SetReferenceFrameToAncestor(aBuilder);
|
2014-07-29 16:09:35 +04:00
|
|
|
Init(aBuilder);
|
2014-02-27 06:57:45 +04:00
|
|
|
}
|
|
|
|
|
2015-09-17 04:31:00 +03:00
|
|
|
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame *aFrame, nsDisplayList *aList,
|
|
|
|
const nsRect& aChildrenVisibleRect,
|
|
|
|
const Matrix4x4& aTransform,
|
|
|
|
uint32_t aIndex)
|
|
|
|
: nsDisplayItem(aBuilder, aFrame)
|
|
|
|
, mStoredList(aBuilder, aFrame, aList)
|
|
|
|
, mTransform(aTransform)
|
|
|
|
, mTransformGetter(nullptr)
|
2016-01-21 07:02:31 +03:00
|
|
|
, mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot)
|
|
|
|
, mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mChildrenVisibleRect(aChildrenVisibleRect)
|
|
|
|
, mIndex(aIndex)
|
|
|
|
, mNoExtendContext(false)
|
2015-10-18 13:13:00 +03:00
|
|
|
, mIsTransformSeparator(true)
|
2015-09-17 04:31:00 +03:00
|
|
|
, mTransformPreserves3DInited(false)
|
2016-11-23 20:49:35 +03:00
|
|
|
, mAllowAsyncAnimation(false)
|
2015-09-17 04:31:00 +03:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayTransform);
|
|
|
|
MOZ_ASSERT(aFrame, "Must have a frame!");
|
|
|
|
Init(aBuilder);
|
2015-10-18 13:13:00 +03:00
|
|
|
UpdateBoundsFor3D(aBuilder);
|
2015-09-17 04:31:00 +03:00
|
|
|
}
|
|
|
|
|
2015-09-27 12:19:13 +03:00
|
|
|
/* Returns the delta specified by the transform-origin property.
|
2008-09-13 13:42:11 +04:00
|
|
|
* This is a positive delta, meaning that it indicates the direction to move
|
2012-07-31 21:28:21 +04:00
|
|
|
* to get from (0, 0) of the frame to the transform origin. This function is
|
|
|
|
* called off the main thread.
|
2008-09-13 13:42:11 +04:00
|
|
|
*/
|
2014-08-29 22:47:30 +04:00
|
|
|
/* static */ Point3D
|
2013-10-24 16:46:00 +04:00
|
|
|
nsDisplayTransform::GetDeltaToTransformOrigin(const nsIFrame* aFrame,
|
|
|
|
float aAppUnitsPerPixel,
|
|
|
|
const nsRect* aBoundsOverride)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
|
2015-09-17 04:31:00 +03:00
|
|
|
NS_PRECONDITION(aFrame->IsTransformed() ||
|
2016-07-08 07:01:31 +03:00
|
|
|
aFrame->BackfaceIsHidden() ||
|
2015-09-17 04:31:00 +03:00
|
|
|
aFrame->Combines3DTransformWithAncestors(),
|
2012-05-17 08:05:09 +04:00
|
|
|
"Shouldn't get a delta for an untransformed frame!");
|
2008-09-13 13:42:11 +04:00
|
|
|
|
2014-02-27 06:57:45 +04:00
|
|
|
if (!aFrame->IsTransformed()) {
|
2014-08-29 22:47:30 +04:00
|
|
|
return Point3D();
|
2014-02-27 06:57:45 +04:00
|
|
|
}
|
|
|
|
|
2015-09-27 12:19:13 +03:00
|
|
|
/* For both of the coordinates, if the value of transform is a
|
2008-09-13 13:42:11 +04:00
|
|
|
* percentage, it's relative to the size of the frame. Otherwise, if it's
|
|
|
|
* a distance, it's already computed for us!
|
|
|
|
*/
|
2015-03-20 07:12:17 +03:00
|
|
|
const nsStyleDisplay* display = aFrame->StyleDisplay();
|
2015-05-25 00:40:37 +03:00
|
|
|
// We don't use aBoundsOverride for SVG since we need to account for
|
|
|
|
// refBox.X/Y(). This happens to work because ReflowSVG sets the frame's
|
|
|
|
// mRect before calling FinishAndStoreOverflow so we don't need the override.
|
2015-04-28 21:55:42 +03:00
|
|
|
TransformReferenceBox refBox;
|
2015-05-25 00:40:37 +03:00
|
|
|
if (aBoundsOverride &&
|
|
|
|
!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
2015-04-28 21:55:42 +03:00
|
|
|
refBox.Init(aBoundsOverride->Size());
|
|
|
|
} else {
|
|
|
|
refBox.Init(aFrame);
|
|
|
|
}
|
2008-09-13 13:42:11 +04:00
|
|
|
|
2015-04-28 21:55:42 +03:00
|
|
|
/* Allows us to access dimension getters by index. */
|
2015-05-25 00:40:37 +03:00
|
|
|
float coords[2];
|
2015-04-28 21:55:42 +03:00
|
|
|
TransformReferenceBox::DimensionGetter dimensionGetter[] =
|
|
|
|
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
|
2015-05-25 00:40:37 +03:00
|
|
|
TransformReferenceBox::DimensionGetter offsetGetter[] =
|
|
|
|
{ &TransformReferenceBox::X, &TransformReferenceBox::Y };
|
2008-09-13 13:42:11 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint8_t index = 0; index < 2; ++index) {
|
2015-09-27 12:19:13 +03:00
|
|
|
/* If the transform-origin specifies a percentage, take the percentage
|
2008-09-13 13:42:11 +04:00
|
|
|
* of the size of the box.
|
|
|
|
*/
|
2015-03-20 07:12:17 +03:00
|
|
|
const nsStyleCoord &coord = display->mTransformOrigin[index];
|
2013-11-11 06:23:56 +04:00
|
|
|
if (coord.GetUnit() == eStyleUnit_Calc) {
|
|
|
|
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
|
|
|
coords[index] =
|
2015-04-28 21:55:42 +03:00
|
|
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
2013-11-11 06:23:56 +04:00
|
|
|
calc->mPercent +
|
|
|
|
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
|
|
|
} else if (coord.GetUnit() == eStyleUnit_Percent) {
|
2012-07-31 21:28:21 +04:00
|
|
|
coords[index] =
|
2015-04-28 21:55:42 +03:00
|
|
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
2013-11-11 06:23:56 +04:00
|
|
|
coord.GetPercentValue();
|
2010-09-15 19:11:26 +04:00
|
|
|
} else {
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
2013-11-11 06:23:56 +04:00
|
|
|
coords[index] =
|
|
|
|
NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
|
|
|
|
}
|
2015-05-25 00:40:37 +03:00
|
|
|
|
|
|
|
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
|
|
|
|
// SVG frames (unlike other frames) have a reference box that can be (and
|
|
|
|
// typically is) offset from the TopLeft() of the frame. We need to
|
|
|
|
// account for that here.
|
|
|
|
coords[index] +=
|
|
|
|
NSAppUnitsToFloatPixels((refBox.*offsetGetter[index])(), aAppUnitsPerPixel);
|
2012-05-17 08:05:09 +04:00
|
|
|
}
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
2011-08-03 07:04:23 +04:00
|
|
|
|
2015-05-25 00:40:37 +03:00
|
|
|
return Point3D(coords[0], coords[1],
|
|
|
|
NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
|
|
|
|
aAppUnitsPerPixel));
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
/* static */ bool
|
|
|
|
nsDisplayTransform::ComputePerspectiveMatrix(const nsIFrame* aFrame,
|
|
|
|
float aAppUnitsPerPixel,
|
|
|
|
Matrix4x4& aOutMatrix)
|
2011-08-03 07:04:24 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
|
2015-09-17 04:31:00 +03:00
|
|
|
NS_PRECONDITION(aFrame->IsTransformed() ||
|
2016-07-08 07:01:31 +03:00
|
|
|
aFrame->BackfaceIsHidden() ||
|
2015-09-17 04:31:00 +03:00
|
|
|
aFrame->Combines3DTransformWithAncestors(),
|
2012-05-17 08:05:09 +04:00
|
|
|
"Shouldn't get a delta for an untransformed frame!");
|
2015-11-26 12:32:36 +03:00
|
|
|
NS_PRECONDITION(aOutMatrix.IsIdentity(), "Must have a blank output matrix");
|
2011-08-03 07:04:24 +04:00
|
|
|
|
2014-02-27 06:57:45 +04:00
|
|
|
if (!aFrame->IsTransformed()) {
|
2015-11-26 12:32:36 +03:00
|
|
|
return false;
|
2014-02-27 06:57:45 +04:00
|
|
|
}
|
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
/* Find our containing block, which is the element that provides the
|
|
|
|
* value for perspective we need to use
|
2011-08-03 07:04:24 +04:00
|
|
|
*/
|
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
//TODO: Is it possible that the cbFrame's bounds haven't been set correctly yet
|
|
|
|
// (similar to the aBoundsOverride case for GetResultingTransformMatrix)?
|
2015-09-14 21:17:40 +03:00
|
|
|
nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
|
|
|
|
if (!cbFrame) {
|
2015-11-26 12:32:36 +03:00
|
|
|
return false;
|
2012-09-18 02:34:21 +04:00
|
|
|
}
|
2015-11-26 12:32:36 +03:00
|
|
|
|
|
|
|
/* Grab the values for perspective and perspective-origin (if present) */
|
|
|
|
|
|
|
|
const nsStyleDisplay* cbDisplay = cbFrame->StyleDisplay();
|
|
|
|
if (cbDisplay->mChildPerspective.GetUnit() != eStyleUnit_Coord) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nscoord perspective = cbDisplay->mChildPerspective.GetCoordValue();
|
2016-08-12 07:51:10 +03:00
|
|
|
if (perspective < 0) {
|
2015-12-09 18:47:08 +03:00
|
|
|
return true;
|
2015-11-26 12:32:36 +03:00
|
|
|
}
|
|
|
|
|
2015-09-14 21:17:40 +03:00
|
|
|
TransformReferenceBox refBox(cbFrame);
|
2011-08-03 07:04:24 +04:00
|
|
|
|
|
|
|
/* Allows us to access named variables by index. */
|
2015-11-26 12:32:36 +03:00
|
|
|
Point3D perspectiveOrigin;
|
|
|
|
gfx::Float* coords[2] = {&perspectiveOrigin.x, &perspectiveOrigin.y};
|
2015-04-28 21:55:42 +03:00
|
|
|
TransformReferenceBox::DimensionGetter dimensionGetter[] =
|
|
|
|
{ &TransformReferenceBox::Width, &TransformReferenceBox::Height };
|
2011-08-03 07:04:24 +04:00
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
/* For both of the coordinates, if the value of perspective-origin is a
|
|
|
|
* percentage, it's relative to the size of the frame. Otherwise, if it's
|
|
|
|
* a distance, it's already computed for us!
|
|
|
|
*/
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint8_t index = 0; index < 2; ++index) {
|
2015-11-26 12:32:36 +03:00
|
|
|
/* If the -transform-origin specifies a percentage, take the percentage
|
2011-08-03 07:04:24 +04:00
|
|
|
* of the size of the box.
|
|
|
|
*/
|
2015-11-26 12:32:36 +03:00
|
|
|
const nsStyleCoord &coord = cbDisplay->mPerspectiveOrigin[index];
|
2011-08-03 07:04:24 +04:00
|
|
|
if (coord.GetUnit() == eStyleUnit_Calc) {
|
|
|
|
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
|
2012-02-17 10:08:33 +04:00
|
|
|
*coords[index] =
|
2015-04-28 21:55:42 +03:00
|
|
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
2012-02-17 10:08:33 +04:00
|
|
|
calc->mPercent +
|
|
|
|
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
|
2011-08-03 07:04:24 +04:00
|
|
|
} else if (coord.GetUnit() == eStyleUnit_Percent) {
|
2012-02-17 10:08:33 +04:00
|
|
|
*coords[index] =
|
2015-04-28 21:55:42 +03:00
|
|
|
NSAppUnitsToFloatPixels((refBox.*dimensionGetter[index])(), aAppUnitsPerPixel) *
|
2011-08-03 07:04:24 +04:00
|
|
|
coord.GetPercentValue();
|
|
|
|
} else {
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
|
2012-02-17 10:08:33 +04:00
|
|
|
*coords[index] =
|
|
|
|
NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
|
2011-08-03 07:04:24 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-26 12:32:35 +03:00
|
|
|
/* GetOffsetTo computes the offset required to move from 0,0 in cbFrame to 0,0
|
|
|
|
* in aFrame. Although we actually want the inverse of this, it's faster to
|
|
|
|
* compute this way.
|
|
|
|
*/
|
|
|
|
nsPoint frameToCbOffset = -aFrame->GetOffsetTo(cbFrame);
|
|
|
|
Point3D frameToCbGfxOffset(
|
|
|
|
NSAppUnitsToFloatPixels(frameToCbOffset.x, aAppUnitsPerPixel),
|
|
|
|
NSAppUnitsToFloatPixels(frameToCbOffset.y, aAppUnitsPerPixel),
|
2014-08-29 22:47:30 +04:00
|
|
|
0.0f);
|
2012-02-15 13:28:22 +04:00
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
/* Move the perspective origin to be relative to aFrame, instead of relative
|
|
|
|
* to the containing block which is how it was specified in the style system.
|
|
|
|
*/
|
|
|
|
perspectiveOrigin += frameToCbGfxOffset;
|
|
|
|
|
2016-08-12 07:51:10 +03:00
|
|
|
Float perspectivePx = std::max(NSAppUnitsToFloatPixels(perspective,
|
|
|
|
aAppUnitsPerPixel),
|
|
|
|
std::numeric_limits<Float>::epsilon());
|
|
|
|
aOutMatrix._34 = -1.0 / perspectivePx;
|
2015-11-26 12:32:36 +03:00
|
|
|
aOutMatrix.ChangeBasis(perspectiveOrigin);
|
|
|
|
return true;
|
2011-08-03 07:04:24 +04:00
|
|
|
}
|
|
|
|
|
2012-09-18 02:34:21 +04:00
|
|
|
nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame* aFrame,
|
|
|
|
float aAppUnitsPerPixel,
|
|
|
|
const nsRect* aBoundsOverride)
|
|
|
|
: mFrame(aFrame)
|
2015-03-20 07:12:17 +03:00
|
|
|
, mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform)
|
2013-10-24 16:46:00 +04:00
|
|
|
, mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride))
|
2012-09-18 02:34:21 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-09-27 12:19:13 +03:00
|
|
|
/* Wraps up the transform matrix in a change-of-basis matrix pair that
|
2008-09-13 13:42:11 +04:00
|
|
|
* translates from local coordinate space to transform coordinate space, then
|
|
|
|
* hands it back.
|
|
|
|
*/
|
2015-07-11 03:05:47 +03:00
|
|
|
Matrix4x4
|
2012-09-18 02:34:21 +04:00
|
|
|
nsDisplayTransform::GetResultingTransformMatrix(const FrameTransformProperties& aProperties,
|
|
|
|
const nsPoint& aOrigin,
|
|
|
|
float aAppUnitsPerPixel,
|
2015-11-26 12:32:35 +03:00
|
|
|
uint32_t aFlags,
|
2016-06-03 05:22:57 +03:00
|
|
|
const nsRect* aBoundsOverride)
|
2012-09-18 02:34:21 +04:00
|
|
|
{
|
|
|
|
return GetResultingTransformMatrixInternal(aProperties, aOrigin, aAppUnitsPerPixel,
|
2016-06-03 05:22:57 +03:00
|
|
|
aFlags, aBoundsOverride);
|
2012-09-18 02:34:21 +04:00
|
|
|
}
|
2016-03-09 08:14:20 +03:00
|
|
|
|
2015-07-11 03:05:47 +03:00
|
|
|
Matrix4x4
|
2008-09-13 13:42:11 +04:00
|
|
|
nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
|
2012-07-31 21:28:21 +04:00
|
|
|
const nsPoint& aOrigin,
|
2012-02-17 10:08:33 +04:00
|
|
|
float aAppUnitsPerPixel,
|
2015-11-26 12:32:35 +03:00
|
|
|
uint32_t aFlags,
|
2016-06-03 05:22:57 +03:00
|
|
|
const nsRect* aBoundsOverride)
|
2015-09-17 04:31:00 +03:00
|
|
|
{
|
|
|
|
FrameTransformProperties props(aFrame,
|
|
|
|
aAppUnitsPerPixel,
|
|
|
|
aBoundsOverride);
|
|
|
|
|
|
|
|
return GetResultingTransformMatrixInternal(props, aOrigin, aAppUnitsPerPixel,
|
2016-06-03 05:22:57 +03:00
|
|
|
aFlags, aBoundsOverride);
|
2012-09-16 14:32:59 +04:00
|
|
|
}
|
|
|
|
|
2015-07-11 03:05:47 +03:00
|
|
|
Matrix4x4
|
2012-09-18 02:34:21 +04:00
|
|
|
nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
|
2012-09-16 14:32:59 +04:00
|
|
|
const nsPoint& aOrigin,
|
|
|
|
float aAppUnitsPerPixel,
|
2015-11-26 12:32:35 +03:00
|
|
|
uint32_t aFlags,
|
2016-06-03 05:22:57 +03:00
|
|
|
const nsRect* aBoundsOverride)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2012-09-18 02:34:21 +04:00
|
|
|
const nsIFrame *frame = aProperties.mFrame;
|
2015-11-26 12:32:36 +03:00
|
|
|
NS_ASSERTION(frame || !(aFlags & INCLUDE_PERSPECTIVE), "Must have a frame to compute perspective!");
|
2016-06-03 06:37:31 +03:00
|
|
|
|
2015-04-28 21:55:42 +03:00
|
|
|
// Get the underlying transform matrix:
|
|
|
|
|
2015-05-25 00:40:37 +03:00
|
|
|
// We don't use aBoundsOverride for SVG since we need to account for
|
|
|
|
// refBox.X/Y(). This happens to work because ReflowSVG sets the frame's
|
|
|
|
// mRect before calling FinishAndStoreOverflow so we don't need the override.
|
2015-04-28 21:55:42 +03:00
|
|
|
TransformReferenceBox refBox;
|
2015-05-25 00:40:37 +03:00
|
|
|
if (aBoundsOverride &&
|
|
|
|
(!frame || !(frame->GetStateBits() & NS_FRAME_SVG_LAYOUT))) {
|
2015-04-28 21:55:42 +03:00
|
|
|
refBox.Init(aBoundsOverride->Size());
|
|
|
|
} else {
|
|
|
|
refBox.Init(frame);
|
|
|
|
}
|
2008-09-13 13:42:11 +04:00
|
|
|
|
|
|
|
/* Get the matrix, then change its basis to factor in the origin. */
|
2015-06-23 04:48:18 +03:00
|
|
|
RuleNodeCacheConditions dummy;
|
2016-02-02 03:45:09 +03:00
|
|
|
bool dummyBool;
|
2015-07-11 03:05:47 +03:00
|
|
|
Matrix4x4 result;
|
2012-05-17 08:05:09 +04:00
|
|
|
// Call IsSVGTransformed() regardless of the value of
|
|
|
|
// disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
|
2014-08-01 16:31:48 +04:00
|
|
|
Matrix svgTransform, transformFromSVGParent;
|
2012-05-17 08:05:09 +04:00
|
|
|
bool hasSVGTransforms =
|
2012-09-18 02:34:21 +04:00
|
|
|
frame && frame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
|
2015-05-25 00:40:37 +03:00
|
|
|
bool hasTransformFromSVGParent =
|
|
|
|
hasSVGTransforms && !transformFromSVGParent.IsIdentity();
|
2011-08-27 04:01:46 +04:00
|
|
|
/* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
|
2012-09-18 02:34:21 +04:00
|
|
|
if (aProperties.mTransformList) {
|
2013-12-12 06:09:44 +04:00
|
|
|
result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
|
2013-02-16 09:38:33 +04:00
|
|
|
frame ? frame->StyleContext() : nullptr,
|
2012-09-18 02:34:21 +04:00
|
|
|
frame ? frame->PresContext() : nullptr,
|
2016-02-02 03:45:09 +03:00
|
|
|
dummy, refBox, aAppUnitsPerPixel,
|
|
|
|
&dummyBool);
|
2012-05-17 08:05:09 +04:00
|
|
|
} else if (hasSVGTransforms) {
|
2012-07-18 17:15:13 +04:00
|
|
|
// Correct the translation components for zoom:
|
2012-09-18 02:34:21 +04:00
|
|
|
float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /
|
2012-07-18 17:15:13 +04:00
|
|
|
aAppUnitsPerPixel;
|
2013-12-30 03:35:53 +04:00
|
|
|
svgTransform._31 *= pixelsPerCSSPx;
|
|
|
|
svgTransform._32 *= pixelsPerCSSPx;
|
2015-07-11 03:05:47 +03:00
|
|
|
result = Matrix4x4::From2D(svgTransform);
|
2011-08-27 04:01:46 +04:00
|
|
|
}
|
2011-08-03 07:04:22 +04:00
|
|
|
|
2015-05-25 00:40:37 +03:00
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
Matrix4x4 perspectiveMatrix;
|
|
|
|
bool hasPerspective = aFlags & INCLUDE_PERSPECTIVE;
|
|
|
|
if (hasPerspective) {
|
|
|
|
hasPerspective = ComputePerspectiveMatrix(frame, aAppUnitsPerPixel,
|
|
|
|
perspectiveMatrix);
|
|
|
|
}
|
2015-10-23 02:49:34 +03:00
|
|
|
|
2015-05-25 00:40:37 +03:00
|
|
|
if (!hasSVGTransforms || !hasTransformFromSVGParent) {
|
|
|
|
// This is a simplification of the following |else| block, the
|
|
|
|
// simplification being possible because we don't need to apply
|
|
|
|
// mToTransformOrigin between two transforms.
|
2016-06-03 05:22:25 +03:00
|
|
|
result.ChangeBasis(aProperties.mToTransformOrigin);
|
2015-05-12 13:26:37 +03:00
|
|
|
} else {
|
2015-05-25 00:40:37 +03:00
|
|
|
Point3D refBoxOffset(NSAppUnitsToFloatPixels(refBox.X(), aAppUnitsPerPixel),
|
|
|
|
NSAppUnitsToFloatPixels(refBox.Y(), aAppUnitsPerPixel),
|
|
|
|
0);
|
|
|
|
// We have both a transform and children-only transform. The
|
|
|
|
// 'transform-origin' must apply between the two, so we need to apply it
|
|
|
|
// now before we apply transformFromSVGParent. Since mToTransformOrigin is
|
|
|
|
// relative to the frame's TopLeft(), we need to convert it to SVG user
|
|
|
|
// space by subtracting refBoxOffset. (Then after applying
|
|
|
|
// transformFromSVGParent we have to reapply refBoxOffset below.)
|
|
|
|
result.ChangeBasis(aProperties.mToTransformOrigin - refBoxOffset);
|
|
|
|
|
|
|
|
// Now apply the children-only transforms, converting the translation
|
|
|
|
// components to device pixels:
|
|
|
|
float pixelsPerCSSPx =
|
|
|
|
frame->PresContext()->AppUnitsPerCSSPixel() / aAppUnitsPerPixel;
|
|
|
|
transformFromSVGParent._31 *= pixelsPerCSSPx;
|
|
|
|
transformFromSVGParent._32 *= pixelsPerCSSPx;
|
2015-07-11 03:05:47 +03:00
|
|
|
result = result * Matrix4x4::From2D(transformFromSVGParent);
|
2015-05-25 00:40:37 +03:00
|
|
|
|
|
|
|
// Similar to the code in the |if| block above, but since we've accounted
|
|
|
|
// for mToTransformOrigin so we don't include that. We also need to reapply
|
|
|
|
// refBoxOffset.
|
2016-06-03 05:22:25 +03:00
|
|
|
result.ChangeBasis(refBoxOffset);
|
2015-05-12 13:26:37 +03:00
|
|
|
}
|
|
|
|
|
2015-10-23 02:49:34 +03:00
|
|
|
if (hasPerspective) {
|
2015-11-26 12:32:36 +03:00
|
|
|
result = result * perspectiveMatrix;
|
2016-06-03 06:37:31 +03:00
|
|
|
}
|
|
|
|
|
2015-11-26 12:32:35 +03:00
|
|
|
if ((aFlags & INCLUDE_PRESERVE3D_ANCESTORS) &&
|
|
|
|
frame && frame->Combines3DTransformWithAncestors()) {
|
2014-05-13 15:37:55 +04:00
|
|
|
// Include the transform set on our parent
|
|
|
|
NS_ASSERTION(frame->GetParent() &&
|
|
|
|
frame->GetParent()->IsTransformed() &&
|
2015-09-17 04:31:00 +03:00
|
|
|
frame->GetParent()->Extend3DContext(),
|
2014-05-13 15:37:55 +04:00
|
|
|
"Preserve3D mismatch!");
|
|
|
|
FrameTransformProperties props(frame->GetParent(),
|
|
|
|
aAppUnitsPerPixel,
|
|
|
|
nullptr);
|
2014-08-20 09:43:26 +04:00
|
|
|
|
2016-06-03 06:37:31 +03:00
|
|
|
uint32_t flags = aFlags & (INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE);
|
2016-06-03 05:23:27 +03:00
|
|
|
|
|
|
|
// If this frame isn't transformed (but we exist for backface-visibility),
|
|
|
|
// then we're not a reference frame so no offset to origin will be added.
|
|
|
|
// Otherwise we need to manually translate into our parent's coordinate
|
|
|
|
// space.
|
|
|
|
if (frame->IsTransformed()) {
|
|
|
|
nsLayoutUtils::PostTranslate(result, frame->GetPosition(), aAppUnitsPerPixel, !hasSVGTransforms);
|
2015-11-26 12:32:35 +03:00
|
|
|
}
|
2015-07-11 03:05:47 +03:00
|
|
|
Matrix4x4 parent =
|
2014-05-13 15:37:55 +04:00
|
|
|
GetResultingTransformMatrixInternal(props,
|
2016-06-03 05:23:27 +03:00
|
|
|
nsPoint(0, 0),
|
2015-11-26 12:32:35 +03:00
|
|
|
aAppUnitsPerPixel, flags,
|
2016-06-03 05:22:57 +03:00
|
|
|
nullptr);
|
2015-02-02 02:12:14 +03:00
|
|
|
result = result * parent;
|
2011-08-27 04:01:46 +04:00
|
|
|
}
|
|
|
|
|
2016-06-03 05:23:27 +03:00
|
|
|
if (aFlags & OFFSET_BY_ORIGIN) {
|
|
|
|
nsLayoutUtils::PostTranslate(result, aOrigin, aAppUnitsPerPixel, !hasSVGTransforms);
|
|
|
|
}
|
|
|
|
|
2014-05-13 15:37:55 +04:00
|
|
|
return result;
|
2011-08-03 07:04:22 +04:00
|
|
|
}
|
|
|
|
|
2011-12-19 01:57:35 +04:00
|
|
|
bool
|
2012-08-26 05:27:28 +04:00
|
|
|
nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
2014-10-22 05:54:32 +04:00
|
|
|
if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_opacity)) {
|
2012-08-26 05:27:28 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-04 11:54:25 +03:00
|
|
|
EffectCompositor::SetPerformanceWarning(
|
2016-08-27 06:55:36 +03:00
|
|
|
mFrame, eCSSProperty_opacity,
|
2016-03-04 11:54:25 +03:00
|
|
|
AnimationPerformanceWarning(
|
|
|
|
AnimationPerformanceWarning::Type::OpacityFrameInactive));
|
2016-03-04 09:07:04 +03:00
|
|
|
|
2012-08-26 05:27:28 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
2016-11-23 20:49:35 +03:00
|
|
|
return mAllowAsyncAnimation;
|
2012-08-26 05:27:28 +04:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:31:20 +03:00
|
|
|
static nsRect ComputePartialPrerenderArea(const nsRect& aDirtyRect,
|
|
|
|
const nsRect& aOverflow,
|
|
|
|
const nsSize& aPrerenderSize)
|
|
|
|
{
|
|
|
|
// Simple calculation for now: center the pre-render area on the dirty rect,
|
|
|
|
// and clamp to the overflow area. Later we can do more advanced things like
|
|
|
|
// redistributing from one axis to another, or from one side to another.
|
|
|
|
nscoord xExcess = aPrerenderSize.width - aDirtyRect.width;
|
|
|
|
nscoord yExcess = aPrerenderSize.height - aDirtyRect.height;
|
|
|
|
nsRect result = aDirtyRect;
|
|
|
|
result.Inflate(xExcess / 2, yExcess / 2);
|
|
|
|
return result.MoveInsideAndClamp(aOverflow);
|
|
|
|
}
|
|
|
|
|
2016-11-23 20:58:59 +03:00
|
|
|
/* static */ auto
|
2011-12-19 01:57:35 +04:00
|
|
|
nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
|
2016-11-24 00:50:47 +03:00
|
|
|
nsIFrame* aFrame,
|
|
|
|
nsRect* aDirtyRect) -> PrerenderDecision
|
2012-08-26 05:27:28 +04:00
|
|
|
{
|
2013-03-19 17:08:29 +04:00
|
|
|
// Elements whose transform has been modified recently, or which
|
|
|
|
// have a compositor-animated transform, can be prerendered. An element
|
|
|
|
// might have only just had its transform animated in which case
|
2014-03-22 01:59:58 +04:00
|
|
|
// the ActiveLayerManager may not have been notified yet.
|
2014-10-22 05:55:55 +04:00
|
|
|
if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
|
2015-12-10 00:28:10 +03:00
|
|
|
!EffectCompositor::HasAnimationsForCompositor(aFrame,
|
|
|
|
eCSSProperty_transform)) {
|
2016-03-04 11:54:25 +03:00
|
|
|
EffectCompositor::SetPerformanceWarning(
|
|
|
|
aFrame, eCSSProperty_transform,
|
|
|
|
AnimationPerformanceWarning(
|
|
|
|
AnimationPerformanceWarning::Type::TransformFrameInactive));
|
|
|
|
|
2016-11-23 20:58:59 +03:00
|
|
|
return NoPrerender;
|
2012-08-26 05:27:28 +04:00
|
|
|
}
|
|
|
|
|
2016-12-09 03:44:19 +03:00
|
|
|
// If the incoming dirty rect already contains the entire overflow area,
|
|
|
|
// we are already rendering the entire content.
|
|
|
|
nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
|
|
|
|
if (aDirtyRect->Contains(overflow)) {
|
|
|
|
return FullPrerender;
|
|
|
|
}
|
|
|
|
|
2016-12-10 04:23:42 +03:00
|
|
|
float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
|
|
|
|
float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
|
|
|
|
uint32_t absoluteLimitX = gfxPrefs::AnimationPrerenderAbsoluteLimitX();
|
|
|
|
uint32_t absoluteLimitY = gfxPrefs::AnimationPrerenderAbsoluteLimitY();
|
2012-09-16 14:32:59 +04:00
|
|
|
nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
|
2016-12-10 04:23:42 +03:00
|
|
|
// Only prerender if the transformed frame's size is <= a multiple of the
|
|
|
|
// reference frame size (~viewport), and less than an absolute limit.
|
|
|
|
// Both the ratio and the absolute limit are configurable.
|
|
|
|
nsSize relativeLimit(nscoord(refSize.width * viewportRatioX),
|
|
|
|
nscoord(refSize.height * viewportRatioY));
|
|
|
|
nsSize absoluteLimit(aFrame->PresContext()->DevPixelsToAppUnits(absoluteLimitX),
|
|
|
|
aFrame->PresContext()->DevPixelsToAppUnits(absoluteLimitY));
|
|
|
|
nsSize maxSize = Min(relativeLimit, absoluteLimit);
|
2016-06-03 13:12:39 +03:00
|
|
|
gfxSize scale = nsLayoutUtils::GetTransformToAncestorScale(aFrame);
|
2016-11-24 00:50:47 +03:00
|
|
|
nsSize frameSize = nsSize(overflow.Size().width * scale.width,
|
|
|
|
overflow.Size().height * scale.height);
|
2016-12-10 04:23:42 +03:00
|
|
|
if (frameSize <= maxSize) {
|
|
|
|
*aDirtyRect = overflow;
|
|
|
|
return FullPrerender;
|
2016-12-14 22:31:20 +03:00
|
|
|
} else if (gfxPrefs::PartiallyPrerenderAnimatedContent()) {
|
|
|
|
*aDirtyRect = ComputePartialPrerenderArea(*aDirtyRect, overflow, maxSize);
|
|
|
|
return PartialPrerender;
|
2012-08-26 05:27:28 +04:00
|
|
|
}
|
|
|
|
|
2016-03-04 11:54:25 +03:00
|
|
|
EffectCompositor::SetPerformanceWarning(
|
|
|
|
aFrame, eCSSProperty_transform,
|
|
|
|
AnimationPerformanceWarning(
|
|
|
|
AnimationPerformanceWarning::Type::ContentTooLarge,
|
|
|
|
{
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(frameSize.width),
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(frameSize.height),
|
2016-12-10 04:23:42 +03:00
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.width),
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(relativeLimit.height),
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(absoluteLimit.width),
|
|
|
|
nsPresContext::AppUnitsToIntCSSPixels(absoluteLimit.height),
|
2016-03-04 11:54:25 +03:00
|
|
|
}));
|
2016-11-23 20:58:59 +03:00
|
|
|
return NoPrerender;
|
2011-12-19 01:57:35 +04:00
|
|
|
}
|
|
|
|
|
2011-10-12 07:16:06 +04:00
|
|
|
/* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
|
2014-08-01 16:31:49 +04:00
|
|
|
static bool IsFrameVisible(nsIFrame* aFrame, const Matrix4x4& aMatrix)
|
2011-10-12 07:16:06 +04:00
|
|
|
{
|
|
|
|
if (aMatrix.IsSingular()) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-07-08 07:01:31 +03:00
|
|
|
if (aFrame->BackfaceIsHidden() && aMatrix.IsBackfaceVisible()) {
|
2011-10-12 07:16:06 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-08-01 16:31:48 +04:00
|
|
|
const Matrix4x4&
|
2014-01-20 10:56:55 +04:00
|
|
|
nsDisplayTransform::GetTransform()
|
2011-08-03 07:04:22 +04:00
|
|
|
{
|
2014-01-20 10:56:55 +04:00
|
|
|
if (mTransform.IsIdentity()) {
|
|
|
|
float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
|
2014-08-29 22:47:30 +04:00
|
|
|
Point3D newOrigin =
|
|
|
|
Point3D(NSAppUnitsToFloatPixels(mToReferenceFrame.x, scale),
|
|
|
|
NSAppUnitsToFloatPixels(mToReferenceFrame.y, scale),
|
|
|
|
0.0f);
|
2012-09-20 03:14:07 +04:00
|
|
|
if (mTransformGetter) {
|
2014-01-20 10:56:55 +04:00
|
|
|
mTransform = mTransformGetter(mFrame, scale);
|
2014-08-01 16:31:48 +04:00
|
|
|
mTransform.ChangeBasis(newOrigin.x, newOrigin.y, newOrigin.z);
|
2015-10-18 13:13:00 +03:00
|
|
|
} else if (!mIsTransformSeparator) {
|
2015-12-17 02:36:24 +03:00
|
|
|
DebugOnly<bool> isReference =
|
2015-09-17 04:31:00 +03:00
|
|
|
mFrame->IsTransformed() ||
|
|
|
|
mFrame->Combines3DTransformWithAncestors() || mFrame->Extend3DContext();
|
2015-12-17 02:36:24 +03:00
|
|
|
MOZ_ASSERT(isReference);
|
|
|
|
mTransform =
|
|
|
|
GetResultingTransformMatrix(mFrame, ToReferenceFrame(),
|
|
|
|
scale, INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN);
|
2012-09-20 03:14:07 +04:00
|
|
|
}
|
2011-08-03 07:04:22 +04:00
|
|
|
}
|
2011-07-23 02:28:07 +04:00
|
|
|
return mTransform;
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
Matrix4x4
|
|
|
|
nsDisplayTransform::GetTransformForRendering()
|
|
|
|
{
|
|
|
|
if (!mFrame->HasPerspective() || mTransformGetter || mIsTransformSeparator) {
|
|
|
|
return GetTransform();
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(!mTransformGetter);
|
|
|
|
|
|
|
|
float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
// Don't include perspective transform, or the offset to origin, since
|
|
|
|
// nsDisplayPerspective will handle both of those.
|
|
|
|
return GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale, 0);
|
|
|
|
}
|
|
|
|
|
2015-09-17 04:31:00 +03:00
|
|
|
const Matrix4x4&
|
2015-11-15 16:47:27 +03:00
|
|
|
nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBuilder)
|
2015-09-17 04:31:00 +03:00
|
|
|
{
|
2015-12-23 03:17:00 +03:00
|
|
|
MOZ_ASSERT(!mFrame->Extend3DContext() || IsLeafOf3DContext());
|
2015-09-17 04:31:00 +03:00
|
|
|
// XXX: should go back to fix mTransformGetter.
|
|
|
|
if (!mTransformPreserves3DInited) {
|
|
|
|
mTransformPreserves3DInited = true;
|
2015-12-23 03:17:00 +03:00
|
|
|
if (!IsLeafOf3DContext()) {
|
2015-09-17 04:31:00 +03:00
|
|
|
mTransformPreserves3D = GetTransform();
|
|
|
|
return mTransformPreserves3D;
|
|
|
|
}
|
2015-11-15 16:47:27 +03:00
|
|
|
|
|
|
|
const nsIFrame* establisher; // Establisher of the 3D rendering context.
|
2016-02-14 23:47:57 +03:00
|
|
|
for (establisher = mFrame;
|
2015-11-15 16:47:27 +03:00
|
|
|
establisher && establisher->Combines3DTransformWithAncestors();
|
|
|
|
establisher = nsLayoutUtils::GetCrossDocParentFrame(establisher)) {
|
|
|
|
}
|
|
|
|
const nsIFrame* establisherReference =
|
2016-06-03 05:23:27 +03:00
|
|
|
aBuilder->FindReferenceFrameFor(nsLayoutUtils::GetCrossDocParentFrame(establisher));
|
2015-11-15 16:47:27 +03:00
|
|
|
|
2016-06-03 05:23:27 +03:00
|
|
|
nsPoint offset = establisher->GetOffsetToCrossDoc(establisherReference);
|
2015-09-17 04:31:00 +03:00
|
|
|
float scale = mFrame->PresContext()->AppUnitsPerDevPixel();
|
2015-11-26 12:32:36 +03:00
|
|
|
uint32_t flags = INCLUDE_PRESERVE3D_ANCESTORS|INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN;
|
2015-09-17 04:31:00 +03:00
|
|
|
mTransformPreserves3D =
|
2015-11-26 12:32:35 +03:00
|
|
|
GetResultingTransformMatrix(mFrame, offset, scale, flags);
|
2015-09-17 04:31:00 +03:00
|
|
|
}
|
|
|
|
return mTransformPreserves3D;
|
|
|
|
}
|
|
|
|
|
2013-03-19 17:08:29 +04:00
|
|
|
bool
|
|
|
|
nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
2015-09-17 04:31:00 +03:00
|
|
|
// The visible rect of a Preserves-3D frame is just an intermediate
|
|
|
|
// result. It should always build a layer to make sure it is
|
|
|
|
// rendering correctly.
|
2016-05-18 06:12:44 +03:00
|
|
|
return MayBeAnimated(aBuilder) || mFrame->Combines3DTransformWithAncestors();
|
2013-03-19 17:08:29 +04:00
|
|
|
}
|
|
|
|
|
2010-08-02 07:07:04 +04:00
|
|
|
already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
|
2011-06-22 16:11:27 +04:00
|
|
|
LayerManager *aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2015-09-17 04:31:00 +03:00
|
|
|
/* For frames without transform, it would not be removed for
|
|
|
|
* backface hidden here. But, it would be removed by the init
|
|
|
|
* function of nsDisplayTransform.
|
|
|
|
*/
|
2015-11-26 12:32:36 +03:00
|
|
|
const Matrix4x4& newTransformMatrix = GetTransformForRendering();
|
2011-08-03 07:04:22 +04:00
|
|
|
|
2016-05-18 06:12:44 +03:00
|
|
|
uint32_t flags = FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
2014-06-09 08:48:00 +04:00
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mStoredList.GetChildren(),
|
2013-12-07 22:33:09 +04:00
|
|
|
aContainerParameters, &newTransformMatrix, flags);
|
2011-10-07 01:23:18 +04:00
|
|
|
|
2013-03-21 07:27:02 +04:00
|
|
|
if (!container) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2011-10-07 01:23:18 +04:00
|
|
|
// Add the preserve-3d flag for this layer, BuildContainerLayerFor clears all flags,
|
|
|
|
// so we never need to explicitely unset this flag.
|
2015-09-17 04:31:00 +03:00
|
|
|
if (mFrame->Extend3DContext() && !mNoExtendContext) {
|
2015-09-17 04:31:00 +03:00
|
|
|
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_EXTEND_3D_CONTEXT);
|
2012-12-12 09:21:23 +04:00
|
|
|
} else {
|
2015-09-17 04:31:00 +03:00
|
|
|
container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_EXTEND_3D_CONTEXT);
|
2011-10-07 01:23:18 +04:00
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2014-03-05 08:13:21 +04:00
|
|
|
nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
|
|
|
|
this, mFrame,
|
|
|
|
eCSSProperty_transform);
|
2016-11-23 20:49:35 +03:00
|
|
|
if (mAllowAsyncAnimation && MayBeAnimated(aBuilder)) {
|
2016-05-18 06:12:44 +03:00
|
|
|
// Only allow async updates to the transform if we're an animated layer, since that's what
|
|
|
|
// triggers us to set the correct AGR in the constructor and makes sure FrameLayerBuilder
|
|
|
|
// won't compute occlusions for this layer.
|
|
|
|
container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(),
|
|
|
|
/*the value is irrelevant*/nullptr);
|
2012-12-12 09:21:23 +04:00
|
|
|
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM);
|
2012-10-03 09:55:52 +04:00
|
|
|
} else {
|
|
|
|
container->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
|
2012-12-12 09:21:23 +04:00
|
|
|
container->SetContentFlags(container->GetContentFlags() & ~Layer::CONTENT_MAY_CHANGE_TRANSFORM);
|
2012-10-03 09:55:52 +04:00
|
|
|
}
|
2011-10-07 01:23:18 +04:00
|
|
|
return container.forget();
|
2010-08-02 07:07:04 +04:00
|
|
|
}
|
2008-09-13 13:42:11 +04:00
|
|
|
|
2016-01-21 07:02:31 +03:00
|
|
|
bool
|
|
|
|
nsDisplayTransform::MayBeAnimated(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
|
|
|
// Here we check if the *post-transform* bounds of this item are big enough
|
|
|
|
// to justify an active layer.
|
2016-05-07 11:37:57 +03:00
|
|
|
if (ActiveLayerTracker::IsStyleAnimated(aBuilder,
|
|
|
|
mFrame,
|
|
|
|
eCSSProperty_transform) ||
|
|
|
|
EffectCompositor::HasAnimationsForCompositor(mFrame,
|
2016-01-21 07:02:31 +03:00
|
|
|
eCSSProperty_transform)) {
|
2016-06-08 08:12:20 +03:00
|
|
|
if (!IsItemTooSmallForActiveLayer(mFrame)) {
|
2016-05-07 11:37:57 +03:00
|
|
|
return true;
|
|
|
|
}
|
2016-06-08 08:12:20 +03:00
|
|
|
SetAnimationPerformanceWarningForTooSmallItem(mFrame, eCSSProperty_transform);
|
2016-01-21 07:02:31 +03:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-02 07:07:04 +04:00
|
|
|
nsDisplayItem::LayerState
|
|
|
|
nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
|
2012-05-03 18:05:55 +04:00
|
|
|
LayerManager* aManager,
|
2013-09-27 10:01:16 +04:00
|
|
|
const ContainerLayerParameters& aParameters) {
|
2015-10-23 06:29:00 +03:00
|
|
|
// If the transform is 3d, the layer takes part in preserve-3d
|
|
|
|
// sorting, or the layer is a separator then we *always* want this
|
|
|
|
// to be an active layer.
|
|
|
|
if (!GetTransform().Is2D() || mFrame->Combines3DTransformWithAncestors() ||
|
|
|
|
mIsTransformSeparator) {
|
2012-11-14 10:26:29 +04:00
|
|
|
return LAYER_ACTIVE_FORCE;
|
|
|
|
}
|
2016-05-07 11:37:57 +03:00
|
|
|
|
2016-01-21 07:02:31 +03:00
|
|
|
if (MayBeAnimated(aBuilder)) {
|
2016-05-07 11:37:57 +03:00
|
|
|
// Returns LAYER_ACTIVE_FORCE to avoid flatterning the layer for async
|
|
|
|
// animations.
|
|
|
|
return LAYER_ACTIVE_FORCE;
|
2012-07-31 21:28:21 +04:00
|
|
|
}
|
2013-11-22 22:14:34 +04:00
|
|
|
|
2014-02-18 05:26:57 +04:00
|
|
|
// Expect the child display items to have this frame as their animated
|
|
|
|
// geometry root (since it will be their reference frame). If they have a
|
|
|
|
// different animated geometry root, we'll make this an active layer so the
|
|
|
|
// animation can be accelerated.
|
|
|
|
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
|
2015-11-25 01:53:51 +03:00
|
|
|
*mStoredList.GetChildren(), mAnimatedGeometryRootForChildren);
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
|
2014-06-23 08:24:51 +04:00
|
|
|
nsRegion *aVisibleRegion)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2009-09-07 04:35:14 +04:00
|
|
|
/* As we do this, we need to be sure to
|
|
|
|
* untransform the visible rect, since we want everything that's painting to
|
2011-07-23 02:28:51 +04:00
|
|
|
* think that it's painting in its original rectangular coordinate space.
|
|
|
|
* If we can't untransform, take the entire overflow rect */
|
|
|
|
nsRect untransformedVisibleRect;
|
2016-05-18 06:12:44 +03:00
|
|
|
if (!UntransformVisibleRect(aBuilder, &untransformedVisibleRect))
|
2011-07-23 02:28:51 +04:00
|
|
|
{
|
2012-09-16 14:32:59 +04:00
|
|
|
untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf();
|
2011-07-23 02:28:51 +04:00
|
|
|
}
|
|
|
|
nsRegion untransformedVisible = untransformedVisibleRect;
|
2011-09-07 04:20:35 +04:00
|
|
|
// Call RecomputeVisiblity instead of ComputeVisibility since
|
2010-08-28 03:15:08 +04:00
|
|
|
// nsDisplayItem::ComputeVisibility should only be called from
|
|
|
|
// nsDisplayList::ComputeVisibility (which sets mVisibleRect on the item)
|
|
|
|
mStoredList.RecomputeVisibility(aBuilder, &untransformedVisible);
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_HIT
|
|
|
|
#include <time.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* HitTest does some fun stuff with matrix transforms to obtain the answer. */
|
2010-04-08 04:31:26 +04:00
|
|
|
void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
|
|
|
|
const nsRect& aRect,
|
|
|
|
HitTestState *aState,
|
|
|
|
nsTArray<nsIFrame*> *aOutFrames)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2015-11-15 16:47:27 +03:00
|
|
|
if (aState->mInPreserves3D) {
|
|
|
|
mStoredList.HitTest(aBuilder, aRect, aState, aOutFrames);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-13 13:42:11 +04:00
|
|
|
/* Here's how this works:
|
|
|
|
* 1. Get the matrix. If it's singular, abort (clearly we didn't hit
|
|
|
|
* anything).
|
|
|
|
* 2. Invert the matrix.
|
2010-04-08 04:31:26 +04:00
|
|
|
* 3. Use it to transform the rect into the correct space.
|
|
|
|
* 4. Pass that rect down through to the list's version of HitTest.
|
2008-09-13 13:42:11 +04:00
|
|
|
*/
|
2014-01-20 10:56:55 +04:00
|
|
|
// GetTransform always operates in dev pixels.
|
2014-01-20 03:30:36 +04:00
|
|
|
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
2015-11-15 16:47:27 +03:00
|
|
|
Matrix4x4 matrix = GetAccumulatedPreserved3DTransform(aBuilder);
|
2011-07-23 02:28:07 +04:00
|
|
|
|
2015-11-15 16:47:27 +03:00
|
|
|
if (!IsFrameVisible(mFrame, matrix)) {
|
2011-10-12 07:16:06 +04:00
|
|
|
return;
|
2011-08-03 07:04:22 +04:00
|
|
|
}
|
2008-09-13 13:42:11 +04:00
|
|
|
|
|
|
|
/* We want to go from transformed-space to regular space.
|
|
|
|
* Thus we have to invert the matrix, which normally does
|
|
|
|
* the reverse operation (e.g. regular->transformed)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Now, apply the transform and pass it down the channel. */
|
2014-08-29 22:47:30 +04:00
|
|
|
matrix.Invert();
|
2010-04-08 04:31:26 +04:00
|
|
|
nsRect resultingRect;
|
|
|
|
if (aRect.width == 1 && aRect.height == 1) {
|
2011-09-08 15:15:00 +04:00
|
|
|
// Magic width/height indicating we're hit testing a point, not a rect
|
2014-08-29 22:47:30 +04:00
|
|
|
Point4D point = matrix.ProjectPoint(Point(NSAppUnitsToFloatPixels(aRect.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aRect.y, factor)));
|
2014-07-08 08:55:42 +04:00
|
|
|
if (!point.HasPositiveWCoord()) {
|
2014-02-04 03:25:23 +04:00
|
|
|
return;
|
|
|
|
}
|
2010-04-08 04:31:26 +04:00
|
|
|
|
2014-08-29 22:47:30 +04:00
|
|
|
Point point2d = point.As2DPoint();
|
2014-07-08 08:55:42 +04:00
|
|
|
|
|
|
|
resultingRect = nsRect(NSFloatPixelsToAppUnits(float(point2d.x), factor),
|
|
|
|
NSFloatPixelsToAppUnits(float(point2d.y), factor),
|
2010-04-08 04:31:26 +04:00
|
|
|
1, 1);
|
|
|
|
|
|
|
|
} else {
|
2014-08-22 17:40:02 +04:00
|
|
|
Rect originalRect(NSAppUnitsToFloatPixels(aRect.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aRect.y, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aRect.width, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aRect.height, factor));
|
2010-04-08 04:31:26 +04:00
|
|
|
|
2014-07-08 08:55:42 +04:00
|
|
|
|
|
|
|
bool snap;
|
|
|
|
nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
|
2014-08-22 17:40:02 +04:00
|
|
|
Rect childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(childBounds.y, factor),
|
|
|
|
NSAppUnitsToFloatPixels(childBounds.width, factor),
|
|
|
|
NSAppUnitsToFloatPixels(childBounds.height, factor));
|
2015-03-13 23:42:00 +03:00
|
|
|
|
|
|
|
Rect rect = matrix.ProjectRectBounds(originalRect, childGfxBounds);
|
2010-04-08 04:31:26 +04:00
|
|
|
|
|
|
|
resultingRect = nsRect(NSFloatPixelsToAppUnits(float(rect.X()), factor),
|
|
|
|
NSFloatPixelsToAppUnits(float(rect.Y()), factor),
|
|
|
|
NSFloatPixelsToAppUnits(float(rect.Width()), factor),
|
|
|
|
NSFloatPixelsToAppUnits(float(rect.Height()), factor));
|
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2014-02-04 03:25:23 +04:00
|
|
|
if (resultingRect.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-13 13:42:11 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG_HIT
|
|
|
|
printf("Frame: %p\n", dynamic_cast<void *>(mFrame));
|
2010-04-08 04:31:26 +04:00
|
|
|
printf(" Untransformed point: (%f, %f)\n", resultingRect.X(), resultingRect.Y());
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t originalFrameCount = aOutFrames.Length();
|
2008-09-13 13:42:11 +04:00
|
|
|
#endif
|
|
|
|
|
2010-04-08 04:31:26 +04:00
|
|
|
mStoredList.HitTest(aBuilder, resultingRect, aState, aOutFrames);
|
|
|
|
|
2008-09-13 13:42:11 +04:00
|
|
|
#ifdef DEBUG_HIT
|
2010-04-08 04:31:26 +04:00
|
|
|
if (originalFrameCount != aOutFrames.Length())
|
|
|
|
printf(" Hit! Time: %f, first frame: %p\n", static_cast<double>(clock()),
|
|
|
|
dynamic_cast<void *>(aOutFrames.ElementAt(0)));
|
2008-09-13 13:42:11 +04:00
|
|
|
printf("=== end of hit test ===\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-10-07 01:24:02 +04:00
|
|
|
float
|
2014-02-04 03:25:23 +04:00
|
|
|
nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder, const nsPoint& aPoint)
|
2011-10-07 01:24:02 +04:00
|
|
|
{
|
2014-01-20 10:56:55 +04:00
|
|
|
// GetTransform always operates in dev pixels.
|
2014-01-20 03:30:36 +04:00
|
|
|
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
2015-11-15 16:47:27 +03:00
|
|
|
Matrix4x4 matrix = GetAccumulatedPreserved3DTransform(aBuilder);
|
2011-10-07 01:24:02 +04:00
|
|
|
|
2015-11-15 16:47:27 +03:00
|
|
|
NS_ASSERTION(IsFrameVisible(mFrame, matrix),
|
2015-09-17 04:31:00 +03:00
|
|
|
"We can't have hit a frame that isn't visible!");
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2014-08-29 22:47:30 +04:00
|
|
|
Matrix4x4 inverse = matrix;
|
|
|
|
inverse.Invert();
|
|
|
|
Point4D point = inverse.ProjectPoint(Point(NSAppUnitsToFloatPixels(aPoint.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aPoint.y, factor)));
|
2014-02-04 03:25:23 +04:00
|
|
|
|
2014-08-29 22:47:30 +04:00
|
|
|
Point point2d = point.As2DPoint();
|
2011-10-07 01:24:02 +04:00
|
|
|
|
2016-09-08 19:26:03 +03:00
|
|
|
Point3D transformed = matrix.TransformPoint(Point3D(point2d.x, point2d.y, 0));
|
2011-10-07 01:24:02 +04:00
|
|
|
return transformed.z;
|
|
|
|
}
|
|
|
|
|
2008-09-13 13:42:11 +04:00
|
|
|
/* The bounding rectangle for the object is the overflow rectangle translated
|
|
|
|
* by the reference point.
|
|
|
|
*/
|
2015-10-18 13:13:00 +03:00
|
|
|
nsRect
|
|
|
|
nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2015-10-18 13:13:00 +03:00
|
|
|
*aSnap = false;
|
|
|
|
|
|
|
|
if (mHasBounds) {
|
|
|
|
return mBounds;
|
|
|
|
}
|
|
|
|
|
2015-10-23 06:29:00 +03:00
|
|
|
if (mFrame->Extend3DContext() && !mIsTransformSeparator) {
|
2015-10-18 13:13:00 +03:00
|
|
|
return nsRect();
|
|
|
|
}
|
|
|
|
|
2016-05-18 06:12:44 +03:00
|
|
|
nsRect untransformedBounds = mStoredList.GetBounds(aBuilder, aSnap);
|
2015-10-18 13:13:00 +03:00
|
|
|
// GetTransform always operates in dev pixels.
|
|
|
|
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
mBounds = nsLayoutUtils::MatrixTransformRect(untransformedBounds,
|
|
|
|
GetTransform(),
|
|
|
|
factor);
|
|
|
|
mHasBounds = true;
|
|
|
|
return mBounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(mFrame->Extend3DContext() || IsLeafOf3DContext());
|
|
|
|
|
2015-09-17 04:31:00 +03:00
|
|
|
/* For some cases, the transform would make an empty bounds, but it
|
|
|
|
* may be turned back again to get a non-empty bounds. We should
|
|
|
|
* not depend on transforming bounds level by level.
|
|
|
|
*
|
|
|
|
* Here, it applies accumulated transforms on the leaf frames of the
|
|
|
|
* 3d rendering context, and track and accmulate bounds at
|
|
|
|
* nsDisplayListBuilder.
|
|
|
|
*/
|
|
|
|
nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
|
|
|
|
|
|
|
|
accTransform.Accumulate(GetTransform());
|
2015-10-18 13:13:00 +03:00
|
|
|
|
|
|
|
if (!IsLeafOf3DContext()) {
|
|
|
|
// Do not dive into another 3D context.
|
|
|
|
mStoredList.DoUpdateBoundsPreserves3D(aBuilder);
|
2015-09-17 04:31:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* For Preserves3D, it is bounds of only children as leaf frames.
|
|
|
|
* For non-leaf frames, their bounds are accumulated and kept at
|
|
|
|
* nsDisplayListBuilder.
|
|
|
|
*/
|
2015-10-18 13:13:00 +03:00
|
|
|
bool snap;
|
2016-05-18 06:12:44 +03:00
|
|
|
nsRect untransformedBounds = mStoredList.GetBounds(aBuilder, &snap);
|
2014-01-20 10:56:55 +04:00
|
|
|
// GetTransform always operates in dev pixels.
|
2014-01-20 03:30:36 +04:00
|
|
|
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
2015-09-17 04:31:00 +03:00
|
|
|
nsRect rect =
|
|
|
|
nsLayoutUtils::MatrixTransformRect(untransformedBounds,
|
|
|
|
accTransform.GetCurrentTransform(),
|
|
|
|
factor);
|
|
|
|
|
2015-10-18 13:13:00 +03:00
|
|
|
aBuilder->AccumulateRect(rect);
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The transform is opaque iff the transform consists solely of scales and
|
2010-11-27 02:31:08 +03:00
|
|
|
* translations and if the underlying content is opaque. Thus if the transform
|
2008-09-13 13:42:11 +04:00
|
|
|
* is of the form
|
|
|
|
*
|
|
|
|
* |a c e|
|
|
|
|
* |b d f|
|
|
|
|
* |0 0 1|
|
|
|
|
*
|
|
|
|
* We need b and c to be zero.
|
2010-11-27 02:31:08 +03:00
|
|
|
*
|
|
|
|
* We also need to check whether the underlying opaque content completely fills
|
|
|
|
* our visible rect. We use UntransformRect which expands to the axis-aligned
|
|
|
|
* bounding rect, but that's OK since if
|
|
|
|
* mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
|
|
|
|
* certainly contains the actual (non-axis-aligned) untransformed rect.
|
2008-09-13 13:42:11 +04:00
|
|
|
*/
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
|
2012-05-03 08:29:05 +04:00
|
|
|
bool* aSnap)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = false;
|
2011-07-23 02:28:51 +04:00
|
|
|
nsRect untransformedVisible;
|
2016-05-18 06:12:44 +03:00
|
|
|
if (!UntransformVisibleRect(aBuilder, &untransformedVisible)) {
|
2011-07-23 02:28:51 +04:00
|
|
|
return nsRegion();
|
|
|
|
}
|
2012-07-31 21:28:21 +04:00
|
|
|
|
2014-08-01 16:31:48 +04:00
|
|
|
const Matrix4x4& matrix = GetTransform();
|
2012-04-10 15:24:18 +04:00
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion result;
|
2014-08-01 16:31:48 +04:00
|
|
|
Matrix matrix2d;
|
2012-04-10 15:24:18 +04:00
|
|
|
bool tmpSnap;
|
2011-07-23 02:28:51 +04:00
|
|
|
if (matrix.Is2D(&matrix2d) &&
|
|
|
|
matrix2d.PreservesAxisAlignedRectangles() &&
|
2012-05-03 08:29:05 +04:00
|
|
|
mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) {
|
2014-06-09 08:47:59 +04:00
|
|
|
result = mVisibleRect.Intersect(GetBounds(aBuilder, &tmpSnap));
|
2011-01-03 04:48:09 +03:00
|
|
|
}
|
|
|
|
return result;
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The transform is uniform if it fills the entire bounding rect and the
|
2011-01-03 04:48:09 +03:00
|
|
|
* wrapped list is uniform. See GetOpaqueRegion for discussion of why this
|
2008-09-13 13:42:11 +04:00
|
|
|
* works.
|
|
|
|
*/
|
2016-05-19 11:07:52 +03:00
|
|
|
Maybe<nscolor>
|
|
|
|
nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2011-07-23 02:28:51 +04:00
|
|
|
nsRect untransformedVisible;
|
2014-02-04 03:25:23 +04:00
|
|
|
if (!UntransformVisibleRect(aBuilder, &untransformedVisible)) {
|
2016-05-19 11:07:52 +03:00
|
|
|
return Nothing();
|
2011-07-23 02:28:51 +04:00
|
|
|
}
|
2014-08-01 16:31:48 +04:00
|
|
|
const Matrix4x4& matrix = GetTransform();
|
2011-07-23 02:28:07 +04:00
|
|
|
|
2014-08-01 16:31:48 +04:00
|
|
|
Matrix matrix2d;
|
2016-05-19 11:07:52 +03:00
|
|
|
if (matrix.Is2D(&matrix2d) &&
|
|
|
|
matrix2d.PreservesAxisAlignedRectangles() &&
|
|
|
|
mStoredList.GetVisibleRect().Contains(untransformedVisible)) {
|
|
|
|
return mStoredList.IsUniform(aBuilder);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Nothing();
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If UNIFIED_CONTINUATIONS is defined, we can merge two display lists that
|
|
|
|
* share the same underlying content. Otherwise, doing so results in graphical
|
|
|
|
* glitches.
|
|
|
|
*/
|
|
|
|
#ifndef UNIFIED_CONTINUATIONS
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2016-01-06 03:08:17 +03:00
|
|
|
nsDisplayTransform::TryMerge(nsDisplayItem *aItem)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2016-01-06 03:08:17 +03:00
|
|
|
nsDisplayTransform::TryMerge(nsDisplayItem *aItem)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aItem, "Why did you try merging with a null item?");
|
|
|
|
|
|
|
|
/* Make sure that we're dealing with two transforms. */
|
|
|
|
if (aItem->GetType() != TYPE_TRANSFORM)
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2008-09-13 13:42:11 +04:00
|
|
|
|
|
|
|
/* Check to see that both frames are part of the same content. */
|
2013-04-19 16:02:13 +04:00
|
|
|
if (aItem->Frame()->GetContent() != mFrame->GetContent())
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2008-09-13 13:42:11 +04:00
|
|
|
|
2013-03-04 13:56:02 +04:00
|
|
|
if (aItem->GetClip() != GetClip())
|
|
|
|
return false;
|
|
|
|
|
2015-12-22 18:54:19 +03:00
|
|
|
if (aItem->ScrollClip() != ScrollClip())
|
|
|
|
return false;
|
|
|
|
|
2008-09-13 13:42:11 +04:00
|
|
|
/* Now, move everything over to this frame and signal that
|
|
|
|
* we merged things!
|
|
|
|
*/
|
2014-06-09 08:47:59 +04:00
|
|
|
mStoredList.MergeFromTrackingMergedFrames(&static_cast<nsDisplayTransform*>(aItem)->mStoredList);
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2008-09-13 13:42:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* TransformRect takes in as parameters a rectangle (in app space) and returns
|
|
|
|
* the smallest rectangle (in app space) containing the transformed image of
|
|
|
|
* that rectangle. That is, it takes the four corners of the rectangle,
|
|
|
|
* transforms them according to the matrix associated with the specified frame,
|
|
|
|
* then returns the smallest rectangle containing the four transformed points.
|
|
|
|
*
|
|
|
|
* @param aUntransformedBounds The rectangle (in app units) to transform.
|
|
|
|
* @param aFrame The frame whose transformation should be applied.
|
|
|
|
* @param aOrigin The delta from the frame origin to the coordinate space origin
|
|
|
|
* @param aBoundsOverride (optional) Force the frame bounds to be the
|
|
|
|
* specified bounds.
|
|
|
|
* @return The smallest rectangle containing the image of the transformed
|
|
|
|
* rectangle.
|
|
|
|
*/
|
|
|
|
nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
|
|
|
|
const nsIFrame* aFrame,
|
2016-06-03 05:22:23 +03:00
|
|
|
const nsRect* aBoundsOverride)
|
2008-09-13 13:42:11 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
|
|
|
|
|
2014-01-20 03:30:36 +04:00
|
|
|
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
|
2015-11-26 12:32:35 +03:00
|
|
|
|
2016-06-03 05:22:23 +03:00
|
|
|
uint32_t flags = INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN|INCLUDE_PRESERVE3D_ANCESTORS;
|
2008-09-13 13:42:11 +04:00
|
|
|
return nsLayoutUtils::MatrixTransformRect
|
|
|
|
(aUntransformedBounds,
|
2016-06-03 05:22:23 +03:00
|
|
|
GetResultingTransformMatrix(aFrame, nsPoint(0, 0), factor, flags, aBoundsOverride),
|
2011-02-25 01:55:23 +03:00
|
|
|
factor);
|
|
|
|
}
|
|
|
|
|
2014-04-23 17:26:52 +04:00
|
|
|
bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds,
|
|
|
|
const nsRect &aChildBounds,
|
|
|
|
const nsIFrame* aFrame,
|
2016-06-03 05:22:23 +03:00
|
|
|
nsRect *aOutRect)
|
2014-04-23 17:26:52 +04:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
|
|
|
|
|
|
|
|
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
|
2016-06-03 05:22:23 +03:00
|
|
|
uint32_t flags = INCLUDE_PERSPECTIVE|OFFSET_BY_ORIGIN|INCLUDE_PRESERVE3D_ANCESTORS;
|
2015-11-26 12:32:35 +03:00
|
|
|
|
2016-06-03 05:22:23 +03:00
|
|
|
Matrix4x4 transform = GetResultingTransformMatrix(aFrame, nsPoint(0, 0), factor, flags);
|
2014-04-23 17:26:52 +04:00
|
|
|
if (transform.IsSingular()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-16 07:05:55 +03:00
|
|
|
RectDouble result(NSAppUnitsToFloatPixels(aTransformedBounds.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aTransformedBounds.y, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aTransformedBounds.width, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aTransformedBounds.height, factor));
|
2014-04-23 17:26:52 +04:00
|
|
|
|
2015-11-16 07:05:55 +03:00
|
|
|
RectDouble childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aChildBounds.y, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aChildBounds.width, factor),
|
|
|
|
NSAppUnitsToFloatPixels(aChildBounds.height, factor));
|
2014-04-23 17:26:52 +04:00
|
|
|
|
2015-07-11 03:05:47 +03:00
|
|
|
result = transform.Inverse().ProjectRectBounds(result, childGfxBounds);
|
2014-08-22 17:40:02 +04:00
|
|
|
*aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result), factor);
|
2014-04-23 17:26:52 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-02-04 03:25:23 +04:00
|
|
|
bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRect *aOutRect)
|
2012-02-14 13:12:49 +04:00
|
|
|
{
|
2015-07-11 03:05:47 +03:00
|
|
|
const Matrix4x4& matrix = GetTransform();
|
2014-02-04 03:25:22 +04:00
|
|
|
if (matrix.IsSingular())
|
2012-02-14 13:12:49 +04:00
|
|
|
return false;
|
|
|
|
|
2014-02-04 03:25:22 +04:00
|
|
|
// GetTransform always operates in dev pixels.
|
|
|
|
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
2015-11-16 07:05:55 +03:00
|
|
|
RectDouble result(NSAppUnitsToFloatPixels(mVisibleRect.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(mVisibleRect.y, factor),
|
|
|
|
NSAppUnitsToFloatPixels(mVisibleRect.width, factor),
|
|
|
|
NSAppUnitsToFloatPixels(mVisibleRect.height, factor));
|
2012-02-14 13:12:49 +04:00
|
|
|
|
2014-02-04 03:25:23 +04:00
|
|
|
bool snap;
|
|
|
|
nsRect childBounds = mStoredList.GetBounds(aBuilder, &snap);
|
2015-11-16 07:05:55 +03:00
|
|
|
RectDouble childGfxBounds(NSAppUnitsToFloatPixels(childBounds.x, factor),
|
|
|
|
NSAppUnitsToFloatPixels(childBounds.y, factor),
|
|
|
|
NSAppUnitsToFloatPixels(childBounds.width, factor),
|
|
|
|
NSAppUnitsToFloatPixels(childBounds.height, factor));
|
2014-02-04 03:25:23 +04:00
|
|
|
|
2012-02-14 13:12:49 +04:00
|
|
|
/* We want to untransform the matrix, so invert the transformation first! */
|
2015-07-11 03:05:47 +03:00
|
|
|
result = matrix.Inverse().ProjectRectBounds(result, childGfxBounds);
|
2012-02-14 13:12:49 +04:00
|
|
|
|
2014-08-22 17:40:02 +04:00
|
|
|
*aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(ThebesRect(result), factor);
|
2012-02-14 13:12:49 +04:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-05-22 06:36:26 +04:00
|
|
|
void
|
2014-11-25 16:45:19 +03:00
|
|
|
nsDisplayTransform::WriteDebugInfo(std::stringstream& aStream)
|
2014-05-22 06:36:26 +04:00
|
|
|
{
|
2014-11-25 16:45:19 +03:00
|
|
|
AppendToString(aStream, GetTransform());
|
2015-12-17 06:22:49 +03:00
|
|
|
if (IsTransformSeparator()) {
|
|
|
|
aStream << " transform-separator";
|
|
|
|
}
|
|
|
|
if (IsLeafOf3DContext()) {
|
|
|
|
aStream << " 3d-context-leaf";
|
|
|
|
}
|
|
|
|
if (mFrame->Extend3DContext()) {
|
|
|
|
aStream << " extends-3d-context";
|
|
|
|
}
|
|
|
|
if (mFrame->Combines3DTransformWithAncestors()) {
|
|
|
|
aStream << " combines-3d-with-ancestors";
|
|
|
|
}
|
2014-05-22 06:36:26 +04:00
|
|
|
}
|
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
nsDisplayPerspective::nsDisplayPerspective(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aTransformFrame,
|
|
|
|
nsIFrame* aPerspectiveFrame,
|
|
|
|
nsDisplayList* aList)
|
|
|
|
: nsDisplayItem(aBuilder, aPerspectiveFrame)
|
|
|
|
, mList(aBuilder, aPerspectiveFrame, aList)
|
|
|
|
, mTransformFrame(aTransformFrame)
|
|
|
|
, mIndex(aBuilder->AllocatePerspectiveItemIndex())
|
2015-12-17 06:22:49 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mList.GetChildren()->Count() == 1);
|
|
|
|
MOZ_ASSERT(mList.GetChildren()->GetTop()->GetType() == TYPE_TRANSFORM);
|
|
|
|
}
|
2015-11-26 12:32:36 +03:00
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayPerspective::BuildLayer(nsDisplayListBuilder *aBuilder,
|
|
|
|
LayerManager *aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
|
|
|
{
|
|
|
|
float appUnitsPerPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
|
|
|
|
Matrix4x4 perspectiveMatrix;
|
|
|
|
DebugOnly<bool> hasPerspective =
|
|
|
|
nsDisplayTransform::ComputePerspectiveMatrix(mTransformFrame, appUnitsPerPixel,
|
|
|
|
perspectiveMatrix);
|
|
|
|
MOZ_ASSERT(hasPerspective, "Why did we create nsDisplayPerspective?");
|
|
|
|
|
2016-04-01 04:37:15 +03:00
|
|
|
/*
|
|
|
|
* ClipListToRange can remove our child after we were created.
|
|
|
|
*/
|
|
|
|
if (!mList.GetChildren()->GetTop()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-11-26 12:32:36 +03:00
|
|
|
/*
|
|
|
|
* The resulting matrix is still in the coordinate space of the transformed
|
|
|
|
* frame. Append a translation to the reference frame coordinates.
|
|
|
|
*/
|
|
|
|
nsDisplayTransform* transform =
|
|
|
|
static_cast<nsDisplayTransform*>(mList.GetChildren()->GetTop());
|
|
|
|
|
|
|
|
Point3D newOrigin =
|
|
|
|
Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x, appUnitsPerPixel),
|
|
|
|
NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y, appUnitsPerPixel),
|
|
|
|
0.0f);
|
|
|
|
Point3D roundedOrigin(NS_round(newOrigin.x),
|
|
|
|
NS_round(newOrigin.y),
|
|
|
|
0);
|
|
|
|
|
|
|
|
perspectiveMatrix.PostTranslate(roundedOrigin);
|
|
|
|
|
|
|
|
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList.GetChildren(),
|
|
|
|
aContainerParameters, &perspectiveMatrix, 0);
|
|
|
|
|
|
|
|
if (!container) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort of a lie, but we want to pretend that the perspective layer extends a 3d context
|
|
|
|
// so that it gets its transform combined with children. Might need a better name that reflects
|
|
|
|
// this use case and isn't specific to preserve-3d.
|
|
|
|
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_EXTEND_3D_CONTEXT);
|
|
|
|
container->SetTransformIsPerspective(true);
|
|
|
|
|
|
|
|
return container.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerState
|
|
|
|
nsDisplayPerspective::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
2016-01-13 03:04:56 +03:00
|
|
|
return LAYER_ACTIVE_FORCE;
|
2015-11-26 12:32:36 +03:00
|
|
|
}
|
|
|
|
|
2016-01-27 13:34:39 +03:00
|
|
|
int32_t
|
|
|
|
nsDisplayPerspective::ZIndex() const
|
|
|
|
{
|
|
|
|
return ZIndexForFrame(mTransformFrame);
|
|
|
|
}
|
|
|
|
|
2015-02-25 17:32:28 +03:00
|
|
|
nsDisplayItemGeometry*
|
|
|
|
nsCharClipDisplayItem::AllocateGeometry(nsDisplayListBuilder* aBuilder)
|
|
|
|
{
|
|
|
|
return new nsCharClipGeometry(this, aBuilder);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsCharClipDisplayItem::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
|
|
|
{
|
|
|
|
const nsCharClipGeometry* geometry = static_cast<const nsCharClipGeometry*>(aGeometry);
|
|
|
|
|
|
|
|
bool snap;
|
|
|
|
nsRect newRect = geometry->mBounds;
|
|
|
|
nsRect oldRect = GetBounds(aBuilder, &snap);
|
2015-04-29 10:18:53 +03:00
|
|
|
if (mVisIStartEdge != geometry->mVisIStartEdge ||
|
|
|
|
mVisIEndEdge != geometry->mVisIEndEdge ||
|
2015-02-25 17:32:28 +03:00
|
|
|
!oldRect.IsEqualInterior(newRect) ||
|
|
|
|
!geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
|
|
|
|
aInvalidRegion->Or(oldRect, newRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-05 18:23:40 +03:00
|
|
|
nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
|
|
|
bool aHandleOpacity,
|
|
|
|
const DisplayItemScrollClip* aScrollClip)
|
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
|
|
|
|
, mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
|
|
|
|
, mHandleOpacity(aHandleOpacity)
|
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplaySVGEffects);
|
|
|
|
}
|
|
|
|
|
2010-08-13 14:01:13 +04:00
|
|
|
nsDisplaySVGEffects::nsDisplaySVGEffects(nsDisplayListBuilder* aBuilder,
|
2016-06-08 08:12:35 +03:00
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
2016-09-05 06:47:18 +03:00
|
|
|
bool aHandleOpacity)
|
2016-06-08 08:12:35 +03:00
|
|
|
: nsDisplayWrapList(aBuilder, aFrame, aList)
|
|
|
|
, mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
|
2016-09-05 06:47:18 +03:00
|
|
|
, mHandleOpacity(aHandleOpacity)
|
2008-09-11 04:24:16 +04:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplaySVGEffects);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplaySVGEffects::~nsDisplaySVGEffects()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(nsDisplaySVGEffects);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-01-03 04:48:09 +03:00
|
|
|
nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
2012-05-03 08:29:05 +04:00
|
|
|
bool* aSnap)
|
2008-09-11 04:24:16 +04:00
|
|
|
{
|
2012-04-10 15:24:18 +04:00
|
|
|
*aSnap = false;
|
2011-01-03 04:48:09 +03:00
|
|
|
return nsRegion();
|
2008-09-11 04:24:16 +04:00
|
|
|
}
|
|
|
|
|
2010-04-08 04:31:26 +04:00
|
|
|
void
|
|
|
|
nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
|
|
|
|
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
|
2008-09-11 04:24:16 +04:00
|
|
|
{
|
2010-04-08 04:31:26 +04:00
|
|
|
nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
|
2012-04-18 09:12:53 +04:00
|
|
|
if (nsSVGIntegrationUtils::HitTestFrameForEffects(mFrame,
|
|
|
|
rectCenter - ToReferenceFrame())) {
|
2010-04-08 04:31:26 +04:00
|
|
|
mList.HitTest(aBuilder, aRect, aState, aOutFrames);
|
|
|
|
}
|
2008-09-11 04:24:16 +04:00
|
|
|
}
|
|
|
|
|
2014-08-30 20:22:31 +04:00
|
|
|
gfxRect
|
|
|
|
nsDisplaySVGEffects::BBoxInUserSpace() const
|
|
|
|
{
|
|
|
|
return nsSVGUtils::GetBBox(mFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxPoint
|
|
|
|
nsDisplaySVGEffects::UserSpaceOffset() const
|
|
|
|
{
|
|
|
|
return nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDisplaySVGEffects::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
|
|
|
{
|
2016-10-26 10:55:32 +03:00
|
|
|
const nsDisplaySVGEffectGeometry* geometry =
|
|
|
|
static_cast<const nsDisplaySVGEffectGeometry*>(aGeometry);
|
2014-08-30 20:22:31 +04:00
|
|
|
bool snap;
|
|
|
|
nsRect bounds = GetBounds(aBuilder, &snap);
|
|
|
|
if (geometry->mFrameOffsetToReferenceFrame != ToReferenceFrame() ||
|
|
|
|
geometry->mUserSpaceOffset != UserSpaceOffset() ||
|
|
|
|
!geometry->mBBox.IsEqualInterior(BBoxInUserSpace())) {
|
|
|
|
// Filter and mask output can depend on the location of the frame's user
|
|
|
|
// space and on the frame's BBox. We need to invalidate if either of these
|
|
|
|
// change relative to the reference frame.
|
|
|
|
// Invalidations from our inactive layer manager are not enough to catch
|
|
|
|
// some of these cases because filters can produce output even if there's
|
|
|
|
// nothing in the filter input.
|
|
|
|
aInvalidRegion->Or(bounds, geometry->mBounds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
bool nsDisplaySVGEffects::ValidateSVGFrame()
|
|
|
|
{
|
|
|
|
const nsIContent* content = mFrame->GetContent();
|
|
|
|
bool hasSVGLayout = (mFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
|
|
|
if (hasSVGLayout) {
|
|
|
|
nsISVGChildFrame *svgChildFrame = do_QueryFrame(mFrame);
|
|
|
|
if (!svgChildFrame || !mFrame->GetContent()->IsSVGElement()) {
|
|
|
|
NS_ASSERTION(false, "why?");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
|
|
|
|
return false; // The SVG spec says not to draw filters for this
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-11 08:12:00 +03:00
|
|
|
static IntRect
|
|
|
|
ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
|
|
|
|
{
|
|
|
|
gfxContextMatrixAutoSaveRestore matRestore(&aCtx);
|
|
|
|
|
|
|
|
// Get the clip extents in device space.
|
|
|
|
aCtx.SetMatrix(gfxMatrix());
|
|
|
|
gfxRect clippedFrameSurfaceRect = aCtx.GetClipExtents();
|
|
|
|
clippedFrameSurfaceRect.RoundOut();
|
|
|
|
|
|
|
|
IntRect result;
|
|
|
|
ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
|
|
|
|
return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
|
|
|
|
: IntRect();
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
|
|
|
|
|
|
|
|
static nsPoint
|
|
|
|
ComputeOffsetToUserSpace(const PaintFramesParams& aParams)
|
|
|
|
{
|
|
|
|
nsIFrame* frame = aParams.frame;
|
|
|
|
nsPoint offsetToBoundingBox = aParams.builder->ToReferenceFrame(frame) -
|
|
|
|
nsSVGIntegrationUtils::GetOffsetToBoundingBox(frame);
|
|
|
|
if (!frame->IsFrameOfType(nsIFrame::eSVG)) {
|
|
|
|
// Snap the offset if the reference frame is not a SVG frame, since other
|
|
|
|
// frames will be snapped to pixel when rendering.
|
|
|
|
offsetToBoundingBox = nsPoint(
|
|
|
|
frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
|
|
|
|
frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
|
|
|
|
}
|
|
|
|
|
|
|
|
// After applying only "offsetToBoundingBox", aParams.ctx would have its
|
|
|
|
// origin at the top left corner of frame's bounding box (over all
|
|
|
|
// continuations).
|
|
|
|
// However, SVG painting needs the origin to be located at the origin of the
|
|
|
|
// SVG frame's "user space", i.e. the space in which, for example, the
|
|
|
|
// frame's BBox lives.
|
|
|
|
// SVG geometry frames and foreignObject frames apply their own offsets, so
|
|
|
|
// their position is relative to their user space. So for these frame types,
|
|
|
|
// if we want aCtx to be in user space, we first need to subtract the
|
|
|
|
// frame's position so that SVG painting can later add it again and the
|
|
|
|
// frame is painted in the right place.
|
|
|
|
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
|
|
|
|
nsPoint toUserSpace =
|
|
|
|
nsPoint(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
|
|
|
|
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
|
|
|
|
|
|
|
|
return (offsetToBoundingBox - toUserSpace);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ComputeMaskGeometry(PaintFramesParams& aParams)
|
|
|
|
{
|
|
|
|
// Properties are added lazily and may have been removed by a restyle, so
|
|
|
|
// make sure all applicable ones are set again.
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aParams.frame);
|
|
|
|
|
|
|
|
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
|
|
|
|
|
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
|
|
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
|
|
|
|
|
|
|
|
if (maskFrames.Length() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxContext& ctx = aParams.ctx;
|
|
|
|
nsIFrame* frame = aParams.frame;
|
|
|
|
|
|
|
|
nsPoint offsetToUserSpace = ComputeOffsetToUserSpace(aParams);
|
|
|
|
gfxPoint devPixelOffsetToUserSpace =
|
|
|
|
nsLayoutUtils::PointToGfxPoint(offsetToUserSpace,
|
|
|
|
frame->PresContext()->AppUnitsPerDevPixel());
|
|
|
|
|
|
|
|
gfxContextMatrixAutoSaveRestore matSR(&ctx);
|
|
|
|
ctx.SetMatrix(ctx.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
|
|
|
|
|
|
|
// Convert boaderArea and dirtyRect to user space.
|
|
|
|
int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
nsRect userSpaceBorderArea = aParams.borderArea - offsetToUserSpace;
|
|
|
|
nsRect userSpaceDirtyRect = aParams.dirtyRect - offsetToUserSpace;
|
|
|
|
|
|
|
|
// Union all mask layer rectangles in user space.
|
|
|
|
gfxRect maskInUserSpace;
|
|
|
|
for (size_t i = 0; i < maskFrames.Length() ; i++) {
|
|
|
|
nsSVGMaskFrame* maskFrame = maskFrames[i];
|
|
|
|
gfxRect currentMaskSurfaceRect;
|
|
|
|
|
|
|
|
if (maskFrame) {
|
|
|
|
currentMaskSurfaceRect = maskFrame->GetMaskArea(aParams.frame);
|
|
|
|
} else {
|
|
|
|
nsCSSRendering::ImageLayerClipState clipState;
|
|
|
|
nsCSSRendering::GetImageLayerClip(svgReset->mMask.mLayers[i],
|
|
|
|
frame,
|
|
|
|
*frame->StyleBorder(),
|
|
|
|
userSpaceBorderArea,
|
|
|
|
userSpaceDirtyRect,
|
|
|
|
false, /* aWillPaintBorder */
|
|
|
|
appUnitsPerDevPixel,
|
|
|
|
&clipState);
|
|
|
|
currentMaskSurfaceRect = clipState.mDirtyRectGfx;
|
|
|
|
}
|
|
|
|
|
|
|
|
maskInUserSpace = maskInUserSpace.Union(currentMaskSurfaceRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Save();
|
|
|
|
|
|
|
|
if (!maskInUserSpace.IsEmpty()) {
|
|
|
|
ctx.Clip(maskInUserSpace);
|
|
|
|
}
|
|
|
|
|
|
|
|
IntRect result = ComputeClipExtsInDeviceSpace(ctx);
|
|
|
|
ctx.Restore();
|
|
|
|
|
|
|
|
aParams.maskRect = result;
|
|
|
|
}
|
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder,
|
2016-09-07 06:46:12 +03:00
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
2016-10-05 18:23:40 +03:00
|
|
|
bool aHandleOpacity,
|
|
|
|
const DisplayItemScrollClip* aScrollClip)
|
|
|
|
: nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity, aScrollClip)
|
2016-08-09 22:02:45 +03:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayMask);
|
2016-10-13 13:35:35 +03:00
|
|
|
|
|
|
|
nsPresContext* presContext = mFrame->PresContext();
|
|
|
|
uint32_t flags = aBuilder->GetBackgroundPaintFlags() |
|
|
|
|
nsCSSRendering::PAINTBG_MASK_IMAGE;
|
|
|
|
const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
|
|
|
|
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
|
|
|
|
bool isTransformedFixed;
|
|
|
|
nsBackgroundLayerState state =
|
|
|
|
nsCSSRendering::PrepareImageLayer(presContext, aFrame, flags,
|
|
|
|
mFrame->GetRectRelativeToSelf(),
|
|
|
|
mFrame->GetRectRelativeToSelf(),
|
|
|
|
svgReset->mMask.mLayers[i],
|
|
|
|
&isTransformedFixed);
|
|
|
|
mDestRects.AppendElement(state.mDestArea);
|
|
|
|
}
|
2016-08-09 22:02:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayMask::~nsDisplayMask()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayMask);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool nsDisplayMask::TryMerge(nsDisplayItem* aItem)
|
|
|
|
{
|
|
|
|
if (aItem->GetType() != TYPE_MASK)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// items for the same content element should be merged into a single
|
|
|
|
// compositing group
|
|
|
|
// aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects
|
2016-09-18 18:16:35 +03:00
|
|
|
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
|
2016-08-09 22:02:45 +03:00
|
|
|
return false;
|
2016-09-18 18:16:35 +03:00
|
|
|
}
|
|
|
|
if (aItem->GetClip() != GetClip()) {
|
2016-08-09 22:02:45 +03:00
|
|
|
return false;
|
2016-09-18 18:16:35 +03:00
|
|
|
}
|
|
|
|
if (aItem->ScrollClip() != ScrollClip()) {
|
2016-08-09 22:02:45 +03:00
|
|
|
return false;
|
2016-09-18 18:16:35 +03:00
|
|
|
}
|
2016-09-18 13:47:02 +03:00
|
|
|
|
|
|
|
// Do not merge if mFrame has mask. Continuation frames should apply mask
|
|
|
|
// independently(just like nsDisplayBackgroundImage).
|
|
|
|
const nsStyleSVGReset *style = mFrame->StyleSVGReset();
|
2016-09-18 18:16:35 +03:00
|
|
|
if (style->mMask.HasLayerWithImage()) {
|
2016-09-18 13:47:02 +03:00
|
|
|
return false;
|
2016-09-18 18:16:35 +03:00
|
|
|
}
|
2016-09-18 13:47:02 +03:00
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
nsDisplayMask* other = static_cast<nsDisplayMask*>(aItem);
|
|
|
|
MergeFromTrackingMergedFrames(other);
|
|
|
|
mEffectsBounds.UnionRect(mEffectsBounds,
|
|
|
|
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
|
2016-09-18 13:47:02 +03:00
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayMask::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
|
|
|
{
|
|
|
|
if (!ValidateSVGFrame()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-09-05 06:47:18 +03:00
|
|
|
if (mFrame->StyleEffects()->mOpacity == 0.0f && mHandleOpacity) {
|
2016-08-09 22:02:45 +03:00
|
|
|
return nullptr;
|
2016-08-16 08:56:11 +03:00
|
|
|
}
|
2016-08-09 22:02:45 +03:00
|
|
|
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
|
|
|
2016-12-07 13:11:06 +03:00
|
|
|
if (effectProperties.HasInvalidClipPath() ||
|
|
|
|
effectProperties.HasInvalidMask()) {
|
2016-08-09 22:02:45 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
|
|
|
aContainerParameters, nullptr);
|
|
|
|
|
|
|
|
return container.forget();
|
|
|
|
}
|
|
|
|
|
2016-10-30 10:43:43 +03:00
|
|
|
bool
|
|
|
|
nsDisplayMask::PaintMask(nsDisplayListBuilder* aBuilder,
|
|
|
|
gfxContext* aMaskContext)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aMaskContext->GetDrawTarget()->GetFormat() == SurfaceFormat::A8);
|
|
|
|
|
|
|
|
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
|
|
|
nsSVGIntegrationUtils::PaintFramesParams params(*aMaskContext,
|
|
|
|
mFrame, mVisibleRect,
|
|
|
|
borderArea, aBuilder,
|
|
|
|
nullptr,
|
|
|
|
mHandleOpacity);
|
|
|
|
ComputeMaskGeometry(params);
|
|
|
|
image::DrawResult result = nsSVGIntegrationUtils::PaintMask(params);
|
|
|
|
|
|
|
|
nsDisplayMaskGeometry::UpdateDrawResult(this, result);
|
|
|
|
return (result == image::DrawResult::SUCCESS) ? true : false;
|
|
|
|
}
|
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
LayerState
|
|
|
|
nsDisplayMask::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
2016-10-19 06:44:15 +03:00
|
|
|
if (ShouldPaintOnMaskLayer(aManager)) {
|
|
|
|
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
|
|
|
|
mList, GetAnimatedGeometryRoot());
|
|
|
|
}
|
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
return LAYER_SVG_EFFECTS;
|
|
|
|
}
|
|
|
|
|
2016-10-19 06:44:15 +03:00
|
|
|
bool nsDisplayMask::ShouldPaintOnMaskLayer(LayerManager* aManager)
|
|
|
|
{
|
|
|
|
if (!aManager->IsCompositingCheap()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-03 06:16:46 +03:00
|
|
|
nsSVGUtils::MaskUsage maskUsage;
|
|
|
|
nsSVGUtils::DetermineMaskUsage(mFrame, mHandleOpacity, maskUsage);
|
2016-10-19 06:44:15 +03:00
|
|
|
|
2016-11-04 09:48:11 +03:00
|
|
|
if (!maskUsage.shouldGenerateMaskLayer &&
|
|
|
|
!maskUsage.shouldGenerateClipMaskLayer) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maskUsage.opacity != 1.0 || maskUsage.shouldApplyClipPath ||
|
|
|
|
maskUsage.shouldApplyBasicShape) {
|
2016-10-19 06:44:15 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nsSVGIntegrationUtils::IsMaskResourceReady(mFrame)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-04 07:25:33 +03:00
|
|
|
if (gfxPrefs::DrawMaskLayer()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-10-19 06:44:15 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-08-16 10:23:33 +03:00
|
|
|
bool nsDisplayMask::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2016-09-18 18:16:35 +03:00
|
|
|
nsRegion* aVisibleRegion)
|
2016-09-07 06:46:12 +03:00
|
|
|
{
|
2016-08-16 10:23:33 +03:00
|
|
|
// Our children may be made translucent or arbitrarily deformed so we should
|
|
|
|
// not allow them to subtract area from aVisibleRegion.
|
|
|
|
nsRegion childrenVisible(mVisibleRect);
|
|
|
|
nsRect r = mVisibleRect.Intersect(mList.GetBounds(aBuilder));
|
|
|
|
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-13 10:36:48 +03:00
|
|
|
void
|
|
|
|
nsDisplayMask::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
2016-10-28 06:31:08 +03:00
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
2016-10-13 10:36:48 +03:00
|
|
|
{
|
|
|
|
nsDisplaySVGEffects::ComputeInvalidationRegion(aBuilder, aGeometry,
|
|
|
|
aInvalidRegion);
|
|
|
|
|
|
|
|
const nsDisplayMaskGeometry* geometry =
|
|
|
|
static_cast<const nsDisplayMaskGeometry*>(aGeometry);
|
|
|
|
bool snap;
|
|
|
|
nsRect bounds = GetBounds(aBuilder, &snap);
|
2016-10-13 13:35:35 +03:00
|
|
|
|
|
|
|
if (mDestRects.Length() != geometry->mDestRects.Length()) {
|
|
|
|
aInvalidRegion->Or(bounds, geometry->mBounds);
|
|
|
|
} else {
|
|
|
|
for (size_t i = 0; i < mDestRects.Length(); i++) {
|
|
|
|
if (!mDestRects[i].IsEqualInterior(geometry->mDestRects[i])) {
|
|
|
|
aInvalidRegion->Or(bounds, geometry->mBounds);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-13 10:36:48 +03:00
|
|
|
if (aBuilder->ShouldSyncDecodeImages() &&
|
|
|
|
geometry->ShouldInvalidateToSyncDecodeImages()) {
|
2016-10-13 11:12:24 +03:00
|
|
|
const nsStyleSVGReset *svgReset = mFrame->StyleSVGReset();
|
|
|
|
NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, svgReset->mMask) {
|
|
|
|
const nsStyleImage& image = svgReset->mMask.mLayers[i].mImage;
|
|
|
|
if (image.GetType() == eStyleImageType_Image ) {
|
|
|
|
aInvalidRegion->Or(*aInvalidRegion, bounds);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-10-13 10:36:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
void
|
|
|
|
nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx,
|
|
|
|
LayerManager* aManager)
|
|
|
|
{
|
2016-10-30 10:43:43 +03:00
|
|
|
MOZ_ASSERT(!ShouldPaintOnMaskLayer(aManager));
|
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
|
|
|
nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
|
|
|
|
mFrame, mVisibleRect,
|
|
|
|
borderArea, aBuilder,
|
2016-09-05 06:47:18 +03:00
|
|
|
aManager,
|
|
|
|
mHandleOpacity);
|
2016-08-09 22:02:45 +03:00
|
|
|
|
2016-10-07 06:47:45 +03:00
|
|
|
// Clip the drawing target by mVisibleRect, which contains the visible
|
|
|
|
// region of the target frame and its out-of-flow and inflow descendants.
|
|
|
|
gfxContext* context = aCtx->ThebesContext();
|
|
|
|
context->Clip(NSRectToSnappedRect(mVisibleRect,
|
|
|
|
mFrame->PresContext()->AppUnitsPerDevPixel(),
|
|
|
|
*aCtx->GetDrawTarget()));
|
|
|
|
|
2016-10-11 08:12:00 +03:00
|
|
|
ComputeMaskGeometry(params);
|
|
|
|
|
2016-08-09 22:02:45 +03:00
|
|
|
image::DrawResult result =
|
|
|
|
nsSVGIntegrationUtils::PaintMaskAndClipPath(params);
|
|
|
|
|
2016-10-07 06:47:45 +03:00
|
|
|
context->PopClip();
|
|
|
|
|
2016-10-13 10:14:50 +03:00
|
|
|
nsDisplayMaskGeometry::UpdateDrawResult(this, result);
|
2016-08-09 22:02:45 +03:00
|
|
|
}
|
|
|
|
|
2011-11-17 07:44:16 +04:00
|
|
|
#ifdef MOZ_DUMP_PAINTING
|
|
|
|
void
|
2016-08-09 22:02:45 +03:00
|
|
|
nsDisplayMask::PrintEffects(nsACString& aTo)
|
2011-11-17 07:44:16 +04:00
|
|
|
{
|
|
|
|
nsIFrame* firstFrame =
|
2014-02-07 05:45:31 +04:00
|
|
|
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
2011-11-17 07:44:16 +04:00
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
2016-12-07 10:28:47 +03:00
|
|
|
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
|
2011-11-17 07:44:16 +04:00
|
|
|
bool first = true;
|
2014-01-27 02:07:08 +04:00
|
|
|
aTo += " effects=(";
|
2016-09-08 13:11:43 +03:00
|
|
|
if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
|
2011-11-17 07:44:16 +04:00
|
|
|
first = false;
|
2016-04-12 08:52:43 +03:00
|
|
|
aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
|
2011-11-17 07:44:16 +04:00
|
|
|
}
|
|
|
|
if (clipPathFrame) {
|
|
|
|
if (!first) {
|
2014-01-27 02:07:08 +04:00
|
|
|
aTo += ", ";
|
2011-11-17 07:44:16 +04:00
|
|
|
}
|
2014-01-27 02:07:08 +04:00
|
|
|
aTo += nsPrintfCString("clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
|
2011-11-17 07:44:16 +04:00
|
|
|
first = false;
|
|
|
|
}
|
2016-02-09 01:08:09 +03:00
|
|
|
const nsStyleSVGReset *style = mFrame->StyleSVGReset();
|
|
|
|
if (style->HasClipPath() && !clipPathFrame) {
|
|
|
|
if (!first) {
|
|
|
|
aTo += ", ";
|
|
|
|
}
|
|
|
|
aTo += "clip(basic-shape)";
|
|
|
|
first = false;
|
|
|
|
}
|
2016-08-09 22:02:45 +03:00
|
|
|
|
2016-12-07 05:12:36 +03:00
|
|
|
nsTArray<nsSVGMaskFrame*> masks = effectProperties.GetMaskFrames();
|
|
|
|
if (!masks.IsEmpty() && masks[0]) {
|
2011-11-17 07:44:16 +04:00
|
|
|
if (!first) {
|
2014-01-27 02:07:08 +04:00
|
|
|
aTo += ", ";
|
2011-11-17 07:44:16 +04:00
|
|
|
}
|
2014-01-27 02:07:08 +04:00
|
|
|
aTo += "mask";
|
2011-11-17 07:44:16 +04:00
|
|
|
}
|
2014-01-27 02:07:08 +04:00
|
|
|
aTo += ")";
|
2011-11-17 07:44:16 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-08-16 10:23:33 +03:00
|
|
|
nsDisplayFilter::nsDisplayFilter(nsDisplayListBuilder* aBuilder,
|
2016-09-07 06:46:12 +03:00
|
|
|
nsIFrame* aFrame, nsDisplayList* aList,
|
|
|
|
bool aHandleOpacity)
|
2016-09-05 06:47:18 +03:00
|
|
|
: nsDisplaySVGEffects(aBuilder, aFrame, aList, aHandleOpacity)
|
2016-08-16 10:23:33 +03:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(nsDisplayFilter);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NS_BUILD_REFCNT_LOGGING
|
|
|
|
nsDisplayFilter::~nsDisplayFilter()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(nsDisplayFilter);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
already_AddRefed<Layer>
|
|
|
|
nsDisplayFilter::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aContainerParameters)
|
|
|
|
{
|
|
|
|
if (!ValidateSVGFrame()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-09-05 06:47:18 +03:00
|
|
|
if (mFrame->StyleEffects()->mOpacity == 0.0f && mHandleOpacity) {
|
2016-08-16 10:23:33 +03:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
|
|
|
2016-12-13 14:40:27 +03:00
|
|
|
if (effectProperties.HasInvalidFilter()) {
|
|
|
|
return nullptr;
|
2016-08-16 10:23:33 +03:00
|
|
|
}
|
|
|
|
|
2016-12-13 14:40:27 +03:00
|
|
|
MOZ_ASSERT(effectProperties.mFilter && mFrame->StyleEffects()->HasFilters(),
|
|
|
|
"By getting here, we must have valid CSS filters.");
|
|
|
|
|
|
|
|
ContainerLayerParameters newContainerParameters = aContainerParameters;
|
|
|
|
newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
|
|
|
|
|
2016-08-16 10:23:33 +03:00
|
|
|
RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
|
|
|
|
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
|
|
|
newContainerParameters, nullptr);
|
|
|
|
|
|
|
|
return container.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool nsDisplayFilter::TryMerge(nsDisplayItem* aItem)
|
|
|
|
{
|
|
|
|
if (aItem->GetType() != TYPE_FILTER) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// items for the same content element should be merged into a single
|
|
|
|
// compositing group.
|
|
|
|
// aItem->Frame() returns non-null because it's nsDisplayFilter
|
|
|
|
if (aItem->Frame()->GetContent() != mFrame->GetContent()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (aItem->GetClip() != GetClip()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (aItem->ScrollClip() != ScrollClip()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDisplayFilter* other = static_cast<nsDisplayFilter*>(aItem);
|
|
|
|
MergeFromTrackingMergedFrames(other);
|
|
|
|
mEffectsBounds.UnionRect(mEffectsBounds,
|
|
|
|
other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerState
|
|
|
|
nsDisplayFilter::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|
|
|
LayerManager* aManager,
|
|
|
|
const ContainerLayerParameters& aParameters)
|
|
|
|
{
|
|
|
|
return LAYER_SVG_EFFECTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool nsDisplayFilter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
|
2016-09-07 06:46:12 +03:00
|
|
|
nsRegion* aVisibleRegion)
|
|
|
|
{
|
2016-08-16 10:23:33 +03:00
|
|
|
nsPoint offset = ToReferenceFrame();
|
|
|
|
nsRect dirtyRect =
|
|
|
|
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame,
|
|
|
|
mVisibleRect - offset) +
|
|
|
|
offset;
|
|
|
|
|
|
|
|
// Our children may be made translucent or arbitrarily deformed so we should
|
|
|
|
// not allow them to subtract area from aVisibleRegion.
|
|
|
|
nsRegion childrenVisible(dirtyRect);
|
|
|
|
nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder));
|
|
|
|
mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-28 06:31:08 +03:00
|
|
|
void
|
|
|
|
nsDisplayFilter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
|
|
|
const nsDisplayItemGeometry* aGeometry,
|
|
|
|
nsRegion* aInvalidRegion)
|
|
|
|
{
|
|
|
|
nsDisplaySVGEffects::ComputeInvalidationRegion(aBuilder, aGeometry,
|
|
|
|
aInvalidRegion);
|
|
|
|
|
|
|
|
const nsDisplayFilterGeometry* geometry =
|
|
|
|
static_cast<const nsDisplayFilterGeometry*>(aGeometry);
|
|
|
|
|
|
|
|
if (aBuilder->ShouldSyncDecodeImages() &&
|
|
|
|
geometry->ShouldInvalidateToSyncDecodeImages()) {
|
|
|
|
bool snap;
|
|
|
|
nsRect bounds = GetBounds(aBuilder, &snap);
|
|
|
|
aInvalidRegion->Or(*aInvalidRegion, bounds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-16 10:23:33 +03:00
|
|
|
void
|
|
|
|
nsDisplayFilter::PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
|
|
|
nsRenderingContext* aCtx,
|
|
|
|
LayerManager* aManager)
|
|
|
|
{
|
|
|
|
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
|
|
|
nsSVGIntegrationUtils::PaintFramesParams params(*aCtx->ThebesContext(),
|
|
|
|
mFrame, mVisibleRect,
|
|
|
|
borderArea, aBuilder,
|
2016-09-05 06:47:18 +03:00
|
|
|
aManager,
|
|
|
|
mHandleOpacity);
|
2016-08-16 10:23:33 +03:00
|
|
|
|
2016-10-13 10:36:48 +03:00
|
|
|
image::DrawResult result = nsSVGIntegrationUtils::PaintFilter(params);
|
|
|
|
nsDisplayFilterGeometry::UpdateDrawResult(this, result);
|
2016-08-16 10:23:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef MOZ_DUMP_PAINTING
|
|
|
|
void
|
|
|
|
nsDisplayFilter::PrintEffects(nsACString& aTo)
|
|
|
|
{
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
|
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
|
|
bool first = true;
|
|
|
|
aTo += " effects=(";
|
2016-09-08 13:11:43 +03:00
|
|
|
if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
|
2016-08-16 10:23:33 +03:00
|
|
|
first = false;
|
|
|
|
aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
|
|
|
|
}
|
|
|
|
if (effectProperties.HasValidFilter()) {
|
|
|
|
if (!first) {
|
|
|
|
aTo += ", ";
|
|
|
|
}
|
|
|
|
aTo += "filter";
|
|
|
|
}
|
|
|
|
aTo += ")";
|
|
|
|
}
|
|
|
|
#endif
|
2016-10-12 10:58:04 +03:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
uint32_t PaintTelemetry::sPaintLevel = 0;
|
|
|
|
uint32_t PaintTelemetry::sMetricLevel = 0;
|
|
|
|
EnumeratedArray<PaintTelemetry::Metric,
|
|
|
|
PaintTelemetry::Metric::COUNT,
|
|
|
|
double> PaintTelemetry::sMetrics;
|
|
|
|
|
|
|
|
PaintTelemetry::AutoRecordPaint::AutoRecordPaint()
|
|
|
|
{
|
|
|
|
// Don't record nested paints.
|
|
|
|
if (sPaintLevel++ > 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset metrics for a new paint.
|
|
|
|
for (auto& metric : sMetrics) {
|
|
|
|
metric = 0.0;
|
|
|
|
}
|
|
|
|
mStart = TimeStamp::Now();
|
|
|
|
}
|
|
|
|
|
|
|
|
PaintTelemetry::AutoRecordPaint::~AutoRecordPaint()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(sPaintLevel != 0);
|
|
|
|
if (--sPaintLevel > 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're in multi-process mode, don't include paint times for the parent
|
|
|
|
// process.
|
|
|
|
if (gfxVars::BrowserTabsRemoteAutostart() && XRE_IsParentProcess()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
double totalMs = (TimeStamp::Now() - mStart).ToMilliseconds();
|
|
|
|
|
|
|
|
// Record the total time.
|
|
|
|
Telemetry::Accumulate(Telemetry::CONTENT_PAINT_TIME, static_cast<uint32_t>(totalMs));
|
|
|
|
|
|
|
|
// If the total time was >= 16ms, then it's likely we missed a frame due to
|
|
|
|
// painting. In this case we'll gather some detailed metrics below.
|
|
|
|
if (totalMs <= 16.0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto record = [=](const char* aKey, double aDurationMs) -> void {
|
|
|
|
MOZ_ASSERT(aDurationMs <= totalMs);
|
|
|
|
|
|
|
|
uint32_t amount = static_cast<int32_t>((aDurationMs / totalMs) * 100.0);
|
|
|
|
|
|
|
|
nsDependentCString key(aKey);
|
|
|
|
Telemetry::Accumulate(Telemetry::CONTENT_LARGE_PAINT_PHASE_WEIGHT, key, amount);
|
|
|
|
};
|
|
|
|
|
|
|
|
double dlMs = sMetrics[Metric::DisplayList];
|
|
|
|
double flbMs = sMetrics[Metric::Layerization];
|
|
|
|
double rMs = sMetrics[Metric::Rasterization];
|
|
|
|
|
|
|
|
// Record all permutations since aggregation makes it difficult to
|
|
|
|
// correlate. For example we can't derive "flb+r" from "dl" because we
|
|
|
|
// don't know the total time associated with a bucket entry. So we just
|
|
|
|
// play it safe and include everything. We can however derive "other" time
|
|
|
|
// from the final permutation.
|
|
|
|
record("dl", dlMs);
|
|
|
|
record("flb", flbMs);
|
|
|
|
record("r", rMs);
|
|
|
|
record("dl,flb", dlMs + flbMs);
|
|
|
|
record("dl,r", dlMs + rMs);
|
|
|
|
record("flb,r", flbMs + rMs);
|
|
|
|
record("dl,flb,r", dlMs + flbMs + rMs);
|
|
|
|
}
|
|
|
|
|
|
|
|
PaintTelemetry::AutoRecord::AutoRecord(Metric aMetric)
|
|
|
|
: mMetric(aMetric)
|
|
|
|
{
|
|
|
|
// Don't double-record anything nested.
|
|
|
|
if (sMetricLevel++ > 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't record inside nested paints, or outside of paints.
|
|
|
|
if (sPaintLevel != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mStart = TimeStamp::Now();
|
|
|
|
}
|
|
|
|
|
|
|
|
PaintTelemetry::AutoRecord::~AutoRecord()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(sMetricLevel != 0);
|
|
|
|
|
|
|
|
sMetricLevel--;
|
|
|
|
if (mStart.IsNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sMetrics[mMetric] += (TimeStamp::Now() - mStart).ToMilliseconds();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|