Bug 1273706 - Part 8: Separate nsStyleImage from nsStyleStruct. r?heycam
Also expose EqualURIs as mozilla::EqualURIs, which is necessary to separate
nsStyleImage, and which also allows us to remove nsCSSFrameConstructor's own
copy of EqualURIs.
This is so that CSSComputedValue, implemented by a future patch in this series,
can contain nsStyleImages without causing a circular dependency (because
CSSComputedValues are stored in a nsStyleStruct added by a different future
patch).
MozReview-Commit-ID: 5roQChonIs0
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -9154,23 +9154,16 @@ nsCSSFrameConstructor::CaptureStateForFr
GetRootFrame();
}
for ( ; frame;
frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame)) {
CaptureFrameState(frame, aHistoryState);
}
}
-static bool EqualURIs(mozilla::css::URLValue *aURI1,
- mozilla::css::URLValue *aURI2)
-{
- return aURI1 == aURI2 || // handle null==null, and optimize
- (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
-}
-
nsStyleContext*
nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
{
RefPtr<nsStyleContext> oldContext = GetUndisplayedContent(aElement);
uint8_t oldDisplay = NS_STYLE_DISPLAY_NONE;
if (!oldContext) {
oldContext = GetDisplayContentsStyleFor(aElement);
if (!oldContext) {
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -10,16 +10,17 @@
#include "gfxBlur.h"
#include "gfxContext.h"
#include "imgIContainer.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/TypedEnumBits.h"
#include "nsLayoutUtils.h"
+#include "nsStyleImage.h"
#include "nsStyleStruct.h"
#include "nsIFrame.h"
class gfxDrawable;
class nsStyleContext;
class nsPresContext;
class nsRenderingContext;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -70,16 +70,17 @@
#include "mozilla/EventStateManager.h"
#include "mozilla/RestyleManager.h"
#include "nsCaret.h"
#include "nsISelection.h"
#include "nsDOMTokenList.h"
#include "mozilla/RuleNodeCacheConditions.h"
#include "nsCSSProps.h"
#include "nsPluginFrame.h"
+#include "nsStyleImage.h"
#include "DisplayItemScrollClip.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount().
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -32,16 +32,17 @@
#include "nsFrameList.h"
#include "nsFrameState.h"
#include "mozilla/ReflowOutput.h"
#include "nsITheme.h"
#include "nsLayoutUtils.h"
#include "nsQueryFrame.h"
#include "nsStringGlue.h"
#include "nsStyleContext.h"
+#include "nsStyleImage.h"
#include "nsStyleStruct.h"
#include "Visibility.h"
#ifdef ACCESSIBILITY
#include "mozilla/a11y/AccTypes.h"
#endif
/**
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -66,16 +66,17 @@ EXPORTS += [
'nsLayoutStylesheetCache.h',
'nsRuleData.h',
'nsRuleNode.h',
'nsRuleProcessorData.h',
'nsRuleWalker.h',
'nsStyleConsts.h',
'nsStyleContext.h',
'nsStyleCoord.h',
+ 'nsStyleImage.h',
'nsStyleSet.h',
'nsStyleStruct.h',
'nsStyleStructFwd.h',
'nsStyleStructInlines.h',
'nsStyleTransformMatrix.h',
'nsStyleUtil.h',
]
@@ -179,16 +180,17 @@ UNIFIED_SOURCES += [
'nsHTMLStyleSheet.cpp',
'nsMediaFeatures.cpp',
'nsNthIndexCache.cpp',
'nsROCSSPrimitiveValue.cpp',
'nsRuleData.cpp',
'nsRuleNode.cpp',
'nsStyleContext.cpp',
'nsStyleCoord.cpp',
+ 'nsStyleImage.cpp',
'nsStyleSet.cpp',
'nsStyleStruct.cpp',
'nsStyleTransformMatrix.cpp',
'nsStyleUtil.cpp',
'nsTransitionManager.cpp',
'RuleNodeCacheConditions.cpp',
'RuleProcessorCache.cpp',
'ServoBindings.cpp',
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -29,16 +29,17 @@
#include "nsIPresShell.h"
#include "nsFontMetrics.h"
#include "gfxFont.h"
#include "nsCSSAnonBoxes.h"
#include "nsCSSPseudoElements.h"
#include "nsThemeConstants.h"
#include "PLDHashTable.h"
#include "nsStyleContext.h"
+#include "nsStyleImage.h"
#include "nsStyleSet.h"
#include "nsStyleStruct.h"
#include "nsSize.h"
#include "nsRuleData.h"
#include "nsIStyleRule.h"
#include "nsBidiUtils.h"
#include "nsStyleStructInlines.h"
#include "nsCSSProps.h"
new file mode 100644
--- /dev/null
+++ b/layout/style/nsStyleImage.cpp
@@ -0,0 +1,385 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsStyleImage.h"
+#include "nsStyleStruct.h"
+
+nsStyleImage::nsStyleImage()
+ : mType(eStyleImageType_Null)
+ , mCropRect(nullptr)
+#ifdef DEBUG
+ , mImageTracked(false)
+#endif
+{
+ MOZ_COUNT_CTOR(nsStyleImage);
+}
+
+nsStyleImage::~nsStyleImage()
+{
+ MOZ_COUNT_DTOR(nsStyleImage);
+ if (mType != eStyleImageType_Null) {
+ SetNull();
+ }
+}
+
+nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
+ : mType(eStyleImageType_Null)
+ , mCropRect(nullptr)
+#ifdef DEBUG
+ , mImageTracked(false)
+#endif
+{
+ // We need our own copy constructor because we don't want
+ // to copy the reference count
+ MOZ_COUNT_CTOR(nsStyleImage);
+ DoCopy(aOther);
+}
+
+nsStyleImage&
+nsStyleImage::operator=(const nsStyleImage& aOther)
+{
+ if (this != &aOther) {
+ DoCopy(aOther);
+ }
+
+ return *this;
+}
+
+void
+nsStyleImage::DoCopy(const nsStyleImage& aOther)
+{
+ SetNull();
+
+ if (aOther.mType == eStyleImageType_Image) {
+ SetImageData(aOther.mImage);
+ } else if (aOther.mType == eStyleImageType_Gradient) {
+ SetGradientData(aOther.mGradient);
+ } else if (aOther.mType == eStyleImageType_Element) {
+ SetElementId(aOther.mElementId);
+ }
+
+ UniquePtr<nsStyleSides> cropRectCopy;
+ if (aOther.mCropRect) {
+ cropRectCopy = MakeUnique<nsStyleSides>(*aOther.mCropRect.get());
+ }
+ SetCropRect(Move(cropRectCopy));
+}
+
+void
+nsStyleImage::SetNull()
+{
+ MOZ_ASSERT(!mImageTracked,
+ "Calling SetNull() with image tracked!");
+
+ if (mType == eStyleImageType_Gradient) {
+ mGradient->Release();
+ } else if (mType == eStyleImageType_Image) {
+ NS_RELEASE(mImage);
+ } else if (mType == eStyleImageType_Element) {
+ free(mElementId);
+ }
+
+ mType = eStyleImageType_Null;
+ mCropRect = nullptr;
+}
+
+void
+nsStyleImage::SetImageData(imgRequestProxy* aImage)
+{
+ MOZ_ASSERT(!mImageTracked,
+ "Setting a new image without untracking the old one!");
+
+ NS_IF_ADDREF(aImage);
+
+ if (mType != eStyleImageType_Null) {
+ SetNull();
+ }
+
+ if (aImage) {
+ mImage = aImage;
+ mType = eStyleImageType_Image;
+ }
+ if (mCachedBIData) {
+ mCachedBIData->PurgeCachedImages();
+ }
+}
+
+void
+nsStyleImage::TrackImage(nsPresContext* aContext)
+{
+ // Sanity
+ MOZ_ASSERT(!mImageTracked, "Already tracking image!");
+ MOZ_ASSERT(mType == eStyleImageType_Image,
+ "Can't track image when there isn't one!");
+
+ // Register the image with the document
+ nsIDocument* doc = aContext->Document();
+ if (doc) {
+ doc->AddImage(mImage);
+ }
+
+ // Mark state
+#ifdef DEBUG
+ mImageTracked = true;
+#endif
+}
+
+void
+nsStyleImage::UntrackImage(nsPresContext* aContext)
+{
+ // Sanity
+ MOZ_ASSERT(mImageTracked, "Image not tracked!");
+ MOZ_ASSERT(mType == eStyleImageType_Image,
+ "Can't untrack image when there isn't one!");
+
+ // Unregister the image with the document
+ nsIDocument* doc = aContext->Document();
+ if (doc) {
+ doc->RemoveImage(mImage);
+ }
+
+ // Mark state
+#ifdef DEBUG
+ mImageTracked = false;
+#endif
+}
+
+void
+nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
+{
+ if (aGradient) {
+ aGradient->AddRef();
+ }
+
+ if (mType != eStyleImageType_Null) {
+ SetNull();
+ }
+
+ if (aGradient) {
+ mGradient = aGradient;
+ mType = eStyleImageType_Gradient;
+ }
+}
+
+void
+nsStyleImage::SetElementId(const char16_t* aElementId)
+{
+ if (mType != eStyleImageType_Null) {
+ SetNull();
+ }
+
+ if (aElementId) {
+ mElementId = NS_strdup(aElementId);
+ mType = eStyleImageType_Element;
+ }
+}
+
+void
+nsStyleImage::SetCropRect(UniquePtr<nsStyleSides> aCropRect)
+{
+ mCropRect = Move(aCropRect);
+}
+
+static int32_t
+ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale)
+{
+ double pixelValue;
+ switch (aCoord.GetUnit()) {
+ case eStyleUnit_Percent:
+ pixelValue = aCoord.GetPercentValue() * aPercentScale;
+ break;
+ case eStyleUnit_Factor:
+ pixelValue = aCoord.GetFactorValue();
+ break;
+ default:
+ NS_NOTREACHED("unexpected unit for image crop rect");
+ return 0;
+ }
+ MOZ_ASSERT(pixelValue >= 0, "we ensured non-negative while parsing");
+ pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow
+ return NS_lround(pixelValue);
+}
+
+bool
+nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
+ bool* aIsEntireImage) const
+{
+ if (mType != eStyleImageType_Image) {
+ return false;
+ }
+
+ nsCOMPtr<imgIContainer> imageContainer;
+ mImage->GetImage(getter_AddRefs(imageContainer));
+ if (!imageContainer) {
+ return false;
+ }
+
+ nsIntSize imageSize;
+ imageContainer->GetWidth(&imageSize.width);
+ imageContainer->GetHeight(&imageSize.height);
+ if (imageSize.width <= 0 || imageSize.height <= 0) {
+ return false;
+ }
+
+ int32_t left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width);
+ int32_t top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height);
+ int32_t right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width);
+ int32_t bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
+
+ // IntersectRect() returns an empty rect if we get negative width or height
+ nsIntRect cropRect(left, top, right - left, bottom - top);
+ nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
+ aActualCropRect.IntersectRect(imageRect, cropRect);
+
+ if (aIsEntireImage) {
+ *aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect);
+ }
+ return true;
+}
+
+nsresult
+nsStyleImage::StartDecoding() const
+{
+ if ((mType == eStyleImageType_Image) && mImage) {
+ return mImage->StartDecoding();
+ }
+ return NS_OK;
+}
+
+bool
+nsStyleImage::IsOpaque() const
+{
+ if (!IsComplete()) {
+ return false;
+ }
+
+ if (mType == eStyleImageType_Gradient) {
+ return mGradient->IsOpaque();
+ }
+
+ if (mType == eStyleImageType_Element) {
+ return false;
+ }
+
+ MOZ_ASSERT(mType == eStyleImageType_Image, "unexpected image type");
+
+ nsCOMPtr<imgIContainer> imageContainer;
+ mImage->GetImage(getter_AddRefs(imageContainer));
+ MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
+
+ // Check if the crop region of the image is opaque.
+ if (imageContainer->IsOpaque()) {
+ if (!mCropRect) {
+ return true;
+ }
+
+ // Must make sure if mCropRect contains at least a pixel.
+ // XXX Is this optimization worth it? Maybe I should just return false.
+ nsIntRect actualCropRect;
+ bool rv = ComputeActualCropRect(actualCropRect);
+ NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
+ return rv && !actualCropRect.IsEmpty();
+ }
+
+ return false;
+}
+
+bool
+nsStyleImage::IsComplete() const
+{
+ switch (mType) {
+ case eStyleImageType_Null:
+ return false;
+ case eStyleImageType_Gradient:
+ case eStyleImageType_Element:
+ return true;
+ case eStyleImageType_Image:
+ {
+ uint32_t status = imgIRequest::STATUS_ERROR;
+ return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
+ (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
+ (status & imgIRequest::STATUS_FRAME_COMPLETE);
+ }
+ default:
+ NS_NOTREACHED("unexpected image type");
+ return false;
+ }
+}
+
+bool
+nsStyleImage::IsLoaded() const
+{
+ switch (mType) {
+ case eStyleImageType_Null:
+ return false;
+ case eStyleImageType_Gradient:
+ case eStyleImageType_Element:
+ return true;
+ case eStyleImageType_Image:
+ {
+ uint32_t status = imgIRequest::STATUS_ERROR;
+ return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
+ !(status & imgIRequest::STATUS_ERROR) &&
+ (status & imgIRequest::STATUS_LOAD_COMPLETE);
+ }
+ default:
+ NS_NOTREACHED("unexpected image type");
+ return false;
+ }
+}
+
+static inline bool
+EqualRects(const UniquePtr<nsStyleSides>& aRect1, const UniquePtr<nsStyleSides>& aRect2)
+{
+ return aRect1 == aRect2 || /* handles null== null, and optimize */
+ (aRect1 && aRect2 && *aRect1 == *aRect2);
+}
+
+bool
+nsStyleImage::operator==(const nsStyleImage& aOther) const
+{
+ if (mType != aOther.mType) {
+ return false;
+ }
+
+ if (!EqualRects(mCropRect, aOther.mCropRect)) {
+ return false;
+ }
+
+ if (mType == eStyleImageType_Image) {
+ return mozilla::EqualImages(mImage, aOther.mImage);
+ }
+
+ if (mType == eStyleImageType_Gradient) {
+ return *mGradient == *aOther.mGradient;
+ }
+
+ if (mType == eStyleImageType_Element) {
+ return NS_strcmp(mElementId, aOther.mElementId) == 0;
+ }
+
+ return true;
+}
+
+void
+nsStyleImage::PurgeCacheForViewportChange(
+ const mozilla::Maybe<nsSize>& aSVGViewportSize,
+ const bool aHasIntrinsicRatio) const
+{
+ EnsureCachedBIData();
+
+ // If we're redrawing with a different viewport-size than we used for our
+ // cached subimages, then we can't trust that our subimages are valid;
+ // any percent sizes/positions in our SVG doc may be different now. Purge!
+ // (We don't have to purge if the SVG document has an intrinsic ratio,
+ // though, because the actual size of elements in SVG documant's coordinate
+ // axis are fixed in this case.)
+ if (aSVGViewportSize != mCachedBIData->GetCachedSVGViewportSize() &&
+ !aHasIntrinsicRatio) {
+ mCachedBIData->PurgeCachedImages();
+ mCachedBIData->SetCachedSVGViewportSize(aSVGViewportSize);
+ }
+}
new file mode 100644
--- /dev/null
+++ b/layout/style/nsStyleImage.h
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * nsStyleImage and support classes.
+ */
+
+#ifndef nsStyleImage_h
+#define nsStyleImage_h
+
+#include <stdint.h>
+
+#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
+#include "nsCOMArray.h"
+#include "nsSize.h"
+#include "imgIContainer.h"
+#include "nsRect.h"
+
+class nsPresContext;
+class nsStyleSides;
+class nsStyleGradient;
+class imgRequestProxy;
+
+enum nsStyleImageType {
+ eStyleImageType_Null,
+ eStyleImageType_Image,
+ eStyleImageType_Gradient,
+ eStyleImageType_Element
+};
+
+struct CachedBorderImageData
+{
+ // Caller are expected to ensure that the value of aSVGViewportSize is
+ // different from the cached one since the method won't do the check.
+ void SetCachedSVGViewportSize(const mozilla::Maybe<nsSize>& aSVGViewportSize);
+ const mozilla::Maybe<nsSize>& GetCachedSVGViewportSize();
+ void PurgeCachedImages();
+ void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage);
+ imgIContainer* GetSubImage(uint8_t aIndex);
+
+private:
+ // If this is a SVG border-image, we save the size of the SVG viewport that
+ // we used when rasterizing any cached border-image subimages. (The viewport
+ // size matters for percent-valued sizes & positions in inner SVG doc).
+ mozilla::Maybe<nsSize> mCachedSVGViewportSize;
+ nsCOMArray<imgIContainer> mSubImages;
+};
+
+/**
+ * Represents a paintable image of one of the following types.
+ * (1) A real image loaded from an external source.
+ * (2) A CSS linear or radial gradient.
+ * (3) An element within a document, or an <img>, <video>, or <canvas> element
+ * not in a document.
+ * (*) Optionally a crop rect can be set to paint a partial (rectangular)
+ * region of an image. (Currently, this feature is only supported with an
+ * image of type (1)).
+ */
+struct nsStyleImage
+{
+ nsStyleImage();
+ ~nsStyleImage();
+ nsStyleImage(const nsStyleImage& aOther);
+ nsStyleImage& operator=(const nsStyleImage& aOther);
+
+ void SetNull();
+ void SetImageData(imgRequestProxy* aImage);
+ void TrackImage(nsPresContext* aContext);
+ void UntrackImage(nsPresContext* aContext);
+ void SetGradientData(nsStyleGradient* aGradient);
+ void SetElementId(const char16_t* aElementId);
+ void SetCropRect(mozilla::UniquePtr<nsStyleSides> aCropRect);
+
+ nsStyleImageType GetType() const {
+ return mType;
+ }
+ imgRequestProxy* GetImageData() const {
+ MOZ_ASSERT(mType == eStyleImageType_Image, "Data is not an image!");
+ MOZ_ASSERT(mImageTracked,
+ "Should be tracking any image we're going to use!");
+ return mImage;
+ }
+ nsStyleGradient* GetGradientData() const {
+ NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
+ return mGradient;
+ }
+ const char16_t* GetElementId() const {
+ NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!");
+ return mElementId;
+ }
+ const mozilla::UniquePtr<nsStyleSides>& GetCropRect() const {
+ NS_ASSERTION(mType == eStyleImageType_Image,
+ "Only image data can have a crop rect");
+ return mCropRect;
+ }
+
+ /**
+ * Compute the actual crop rect in pixels, using the source image bounds.
+ * The computation involves converting percentage unit to pixel unit and
+ * clamping each side value to fit in the source image bounds.
+ * @param aActualCropRect the computed actual crop rect.
+ * @param aIsEntireImage true iff |aActualCropRect| is identical to the
+ * source image bounds.
+ * @return true iff |aActualCropRect| holds a meaningful value.
+ */
+ bool ComputeActualCropRect(nsIntRect& aActualCropRect,
+ bool* aIsEntireImage = nullptr) const;
+
+ /**
+ * Starts the decoding of a image.
+ */
+ nsresult StartDecoding() const;
+ /**
+ * @return true if the item is definitely opaque --- i.e., paints every
+ * pixel within its bounds opaquely, and the bounds contains at least a pixel.
+ */
+ bool IsOpaque() const;
+ /**
+ * @return true if this image is fully loaded, and its size is calculated;
+ * always returns true if |mType| is |eStyleImageType_Gradient| or
+ * |eStyleImageType_Element|.
+ */
+ bool IsComplete() const;
+ /**
+ * @return true if this image is loaded without error;
+ * always returns true if |mType| is |eStyleImageType_Gradient| or
+ * |eStyleImageType_Element|.
+ */
+ bool IsLoaded() const;
+ /**
+ * @return true if it is 100% confident that this image contains no pixel
+ * to draw.
+ */
+ bool IsEmpty() const {
+ // There are some other cases when the image will be empty, for example
+ // when the crop rect is empty. However, checking the emptiness of crop
+ // rect is non-trivial since each side value can be specified with
+ // percentage unit, which can not be evaluated until the source image size
+ // is available. Therefore, we currently postpone the evaluation of crop
+ // rect until the actual rendering time --- alternatively until GetOpaqueRegion()
+ // is called.
+ return mType == eStyleImageType_Null;
+ }
+
+ bool operator==(const nsStyleImage& aOther) const;
+ bool operator!=(const nsStyleImage& aOther) const {
+ return !(*this == aOther);
+ }
+
+ bool ImageDataEquals(const nsStyleImage& aOther) const
+ {
+ return GetType() == eStyleImageType_Image &&
+ aOther.GetType() == eStyleImageType_Image &&
+ GetImageData() == aOther.GetImageData();
+ }
+
+ // These methods are used for the caller to caches the sub images created
+ // during a border-image paint operation
+ inline void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage) const;
+ inline imgIContainer* GetSubImage(uint8_t aIndex) const;
+ void PurgeCacheForViewportChange(
+ const mozilla::Maybe<nsSize>& aSVGViewportSize,
+ const bool aHasIntrinsicRatio) const;
+
+private:
+ void DoCopy(const nsStyleImage& aOther);
+ void EnsureCachedBIData() const;
+
+ // This variable keeps some cache data for border image and is lazily
+ // allocated since it is only used in border image case.
+ mozilla::UniquePtr<CachedBorderImageData> mCachedBIData;
+
+ nsStyleImageType mType;
+ union {
+ imgRequestProxy* mImage;
+ nsStyleGradient* mGradient;
+ char16_t* mElementId;
+ };
+
+ // This is _currently_ used only in conjunction with eStyleImageType_Image.
+ mozilla::UniquePtr<nsStyleSides> mCropRect;
+#ifdef DEBUG
+ bool mImageTracked;
+#endif
+};
+
+#endif // nsStyleImage_h
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -39,62 +39,65 @@
#include <algorithm>
using namespace mozilla;
static_assert((((1 << nsStyleStructID_Length) - 1) &
~(NS_STYLE_INHERIT_MASK)) == 0,
"Not enough bits in NS_STYLE_INHERIT_MASK");
-// These are the limits that we choose to clamp grid line numbers to.
-// http://dev.w3.org/csswg/css-grid/#overlarge-grids
-const int32_t nsStyleGridLine::kMinLine = -10000;
-const int32_t nsStyleGridLine::kMaxLine = 10000;
-
-static bool
+namespace mozilla {
+
+bool
EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
{
bool eq;
return aURI1 == aURI2 || // handle null==null, and optimize
(aURI1 && aURI2 &&
NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail
eq);
}
-static bool
+bool
EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2)
{
return aURI1 == aURI2 || // handle null==null, and optimize
(aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
}
-static
bool EqualURIs(const FragmentOrURL* aURI1, const FragmentOrURL* aURI2)
{
return aURI1 == aURI2 || // handle null==null, and optimize
(aURI1 && aURI2 && *aURI1 == *aURI2);
}
-static bool
+bool
EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
{
if (aImage1 == aImage2) {
return true;
}
if (!aImage1 || !aImage2) {
return false;
}
nsCOMPtr<nsIURI> uri1, uri2;
aImage1->GetURI(getter_AddRefs(uri1));
aImage2->GetURI(getter_AddRefs(uri2));
return EqualURIs(uri1, uri2);
}
+} // namespace mozilla
+
+// These are the limits that we choose to clamp grid line numbers to.
+// http://dev.w3.org/csswg/css-grid/#overlarge-grids
+const int32_t nsStyleGridLine::kMinLine = -10000;
+const int32_t nsStyleGridLine::kMaxLine = 10000;
+
// A nullsafe wrapper for strcmp. We depend on null-safety.
static int
safe_strcmp(const char16_t* a, const char16_t* b)
{
if (!a || !b) {
return (int)(a - b);
}
return NS_strcmp(a, b);
@@ -157,17 +160,17 @@ FragmentOrURL::operator=(const FragmentO
bool
FragmentOrURL::operator==(const FragmentOrURL& aOther) const
{
if (aOther.mIsLocalRef != mIsLocalRef) {
return false;
}
- return EqualURIs(aOther.mURL, mURL);
+ return mozilla::EqualURIs(aOther.mURL, mURL);
}
bool
FragmentOrURL::EqualsExceptRef(nsIURI* aURI) const
{
bool ret = false;
mURL->EqualsExceptRef(aURI, &ret);
return ret;
@@ -795,17 +798,17 @@ nsStyleList::CalcDifference(const nsStyl
if (mQuotes != aNewData.mQuotes &&
(mQuotes || aNewData.mQuotes) &&
GetQuotePairs() != aNewData.GetQuotePairs()) {
return nsChangeHint_ReconstructFrame;
}
if (mListStylePosition != aNewData.mListStylePosition) {
return nsChangeHint_ReconstructFrame;
}
- if (EqualImages(mListStyleImage, aNewData.mListStyleImage) &&
+ if (mozilla::EqualImages(mListStyleImage, aNewData.mListStyleImage) &&
mCounterStyle == aNewData.mCounterStyle) {
if (mImageRegion.IsEqualInterior(aNewData.mImageRegion)) {
return nsChangeHint(0);
}
if (mImageRegion.width == aNewData.mImageRegion.width &&
mImageRegion.height == aNewData.mImageRegion.height) {
return NS_STYLE_HINT_VISUAL;
}
@@ -1004,17 +1007,17 @@ nsStyleSVG::nsStyleSVG(const nsStyleSVG&
static bool
PaintURIChanged(const nsStyleSVGPaint& aPaint1, const nsStyleSVGPaint& aPaint2)
{
if (aPaint1.mType != aPaint2.mType) {
return aPaint1.mType == eStyleSVGPaintType_Server ||
aPaint2.mType == eStyleSVGPaintType_Server;
}
return aPaint1.mType == eStyleSVGPaintType_Server &&
- !EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
+ !mozilla::EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
}
nsChangeHint
nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const
{
nsChangeHint hint = nsChangeHint(0);
if (mMarkerEnd != aNewData.mMarkerEnd || mMarkerMid != aNewData.mMarkerMid ||
@@ -1159,17 +1162,17 @@ nsStyleFilter::operator=(const nsStyleFi
bool
nsStyleFilter::operator==(const nsStyleFilter& aOther) const
{
if (mType != aOther.mType) {
return false;
}
if (mType == NS_STYLE_FILTER_URL) {
- return EqualURIs(mURL, aOther.mURL);
+ return mozilla::EqualURIs(mURL, aOther.mURL);
} else if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
return *mDropShadow == *aOther.mDropShadow;
} else if (mType != NS_STYLE_FILTER_NONE) {
return mFilterParameter == aOther.mFilterParameter;
}
return true;
}
@@ -1380,17 +1383,17 @@ nsStyleSVGPaint::operator=(const nsStyle
}
bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const
{
if (mType != aOther.mType) {
return false;
}
if (mType == eStyleSVGPaintType_Server) {
- return EqualURIs(mPaint.mPaintServer, aOther.mPaint.mPaintServer) &&
+ return mozilla::EqualURIs(mPaint.mPaintServer, aOther.mPaint.mPaintServer) &&
mFallbackColor == aOther.mFallbackColor;
}
if (mType == eStyleSVGPaintType_Color) {
return mPaint.mColor == aOther.mPaint.mColor;
}
return true;
}
@@ -1944,397 +1947,16 @@ CachedBorderImageData::GetSubImage(uint8
{
imgIContainer* subImage = nullptr;
if (aIndex < mSubImages.Count())
subImage = mSubImages[aIndex];
return subImage;
}
// --------------------
-// nsStyleImage
-//
-
-nsStyleImage::nsStyleImage()
- : mType(eStyleImageType_Null)
- , mCropRect(nullptr)
-#ifdef DEBUG
- , mImageTracked(false)
-#endif
-{
- MOZ_COUNT_CTOR(nsStyleImage);
-}
-
-nsStyleImage::~nsStyleImage()
-{
- MOZ_COUNT_DTOR(nsStyleImage);
- if (mType != eStyleImageType_Null) {
- SetNull();
- }
-}
-
-nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
- : mType(eStyleImageType_Null)
- , mCropRect(nullptr)
-#ifdef DEBUG
- , mImageTracked(false)
-#endif
-{
- // We need our own copy constructor because we don't want
- // to copy the reference count
- MOZ_COUNT_CTOR(nsStyleImage);
- DoCopy(aOther);
-}
-
-nsStyleImage&
-nsStyleImage::operator=(const nsStyleImage& aOther)
-{
- if (this != &aOther) {
- DoCopy(aOther);
- }
-
- return *this;
-}
-
-void
-nsStyleImage::DoCopy(const nsStyleImage& aOther)
-{
- SetNull();
-
- if (aOther.mType == eStyleImageType_Image) {
- SetImageData(aOther.mImage);
- } else if (aOther.mType == eStyleImageType_Gradient) {
- SetGradientData(aOther.mGradient);
- } else if (aOther.mType == eStyleImageType_Element) {
- SetElementId(aOther.mElementId);
- }
-
- UniquePtr<nsStyleSides> cropRectCopy;
- if (aOther.mCropRect) {
- cropRectCopy = MakeUnique<nsStyleSides>(*aOther.mCropRect.get());
- }
- SetCropRect(Move(cropRectCopy));
-}
-
-void
-nsStyleImage::SetNull()
-{
- MOZ_ASSERT(!mImageTracked,
- "Calling SetNull() with image tracked!");
-
- if (mType == eStyleImageType_Gradient) {
- mGradient->Release();
- } else if (mType == eStyleImageType_Image) {
- NS_RELEASE(mImage);
- } else if (mType == eStyleImageType_Element) {
- free(mElementId);
- }
-
- mType = eStyleImageType_Null;
- mCropRect = nullptr;
-}
-
-void
-nsStyleImage::SetImageData(imgRequestProxy* aImage)
-{
- MOZ_ASSERT(!mImageTracked,
- "Setting a new image without untracking the old one!");
-
- NS_IF_ADDREF(aImage);
-
- if (mType != eStyleImageType_Null) {
- SetNull();
- }
-
- if (aImage) {
- mImage = aImage;
- mType = eStyleImageType_Image;
- }
- if (mCachedBIData) {
- mCachedBIData->PurgeCachedImages();
- }
-}
-
-void
-nsStyleImage::TrackImage(nsPresContext* aContext)
-{
- // Sanity
- MOZ_ASSERT(!mImageTracked, "Already tracking image!");
- MOZ_ASSERT(mType == eStyleImageType_Image,
- "Can't track image when there isn't one!");
-
- // Register the image with the document
- nsIDocument* doc = aContext->Document();
- if (doc) {
- doc->AddImage(mImage);
- }
-
- // Mark state
-#ifdef DEBUG
- mImageTracked = true;
-#endif
-}
-
-void
-nsStyleImage::UntrackImage(nsPresContext* aContext)
-{
- // Sanity
- MOZ_ASSERT(mImageTracked, "Image not tracked!");
- MOZ_ASSERT(mType == eStyleImageType_Image,
- "Can't untrack image when there isn't one!");
-
- // Unregister the image with the document
- nsIDocument* doc = aContext->Document();
- if (doc) {
- doc->RemoveImage(mImage);
- }
-
- // Mark state
-#ifdef DEBUG
- mImageTracked = false;
-#endif
-}
-
-void
-nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
-{
- if (aGradient) {
- aGradient->AddRef();
- }
-
- if (mType != eStyleImageType_Null) {
- SetNull();
- }
-
- if (aGradient) {
- mGradient = aGradient;
- mType = eStyleImageType_Gradient;
- }
-}
-
-void
-nsStyleImage::SetElementId(const char16_t* aElementId)
-{
- if (mType != eStyleImageType_Null) {
- SetNull();
- }
-
- if (aElementId) {
- mElementId = NS_strdup(aElementId);
- mType = eStyleImageType_Element;
- }
-}
-
-void
-nsStyleImage::SetCropRect(UniquePtr<nsStyleSides> aCropRect)
-{
- mCropRect = Move(aCropRect);
-}
-
-static int32_t
-ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale)
-{
- double pixelValue;
- switch (aCoord.GetUnit()) {
- case eStyleUnit_Percent:
- pixelValue = aCoord.GetPercentValue() * aPercentScale;
- break;
- case eStyleUnit_Factor:
- pixelValue = aCoord.GetFactorValue();
- break;
- default:
- NS_NOTREACHED("unexpected unit for image crop rect");
- return 0;
- }
- MOZ_ASSERT(pixelValue >= 0, "we ensured non-negative while parsing");
- pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow
- return NS_lround(pixelValue);
-}
-
-bool
-nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
- bool* aIsEntireImage) const
-{
- if (mType != eStyleImageType_Image) {
- return false;
- }
-
- nsCOMPtr<imgIContainer> imageContainer;
- mImage->GetImage(getter_AddRefs(imageContainer));
- if (!imageContainer) {
- return false;
- }
-
- nsIntSize imageSize;
- imageContainer->GetWidth(&imageSize.width);
- imageContainer->GetHeight(&imageSize.height);
- if (imageSize.width <= 0 || imageSize.height <= 0) {
- return false;
- }
-
- int32_t left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width);
- int32_t top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height);
- int32_t right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width);
- int32_t bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
-
- // IntersectRect() returns an empty rect if we get negative width or height
- nsIntRect cropRect(left, top, right - left, bottom - top);
- nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
- aActualCropRect.IntersectRect(imageRect, cropRect);
-
- if (aIsEntireImage) {
- *aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect);
- }
- return true;
-}
-
-nsresult
-nsStyleImage::StartDecoding() const
-{
- if ((mType == eStyleImageType_Image) && mImage) {
- return mImage->StartDecoding();
- }
- return NS_OK;
-}
-
-bool
-nsStyleImage::IsOpaque() const
-{
- if (!IsComplete()) {
- return false;
- }
-
- if (mType == eStyleImageType_Gradient) {
- return mGradient->IsOpaque();
- }
-
- if (mType == eStyleImageType_Element) {
- return false;
- }
-
- MOZ_ASSERT(mType == eStyleImageType_Image, "unexpected image type");
-
- nsCOMPtr<imgIContainer> imageContainer;
- mImage->GetImage(getter_AddRefs(imageContainer));
- MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
-
- // Check if the crop region of the image is opaque.
- if (imageContainer->IsOpaque()) {
- if (!mCropRect) {
- return true;
- }
-
- // Must make sure if mCropRect contains at least a pixel.
- // XXX Is this optimization worth it? Maybe I should just return false.
- nsIntRect actualCropRect;
- bool rv = ComputeActualCropRect(actualCropRect);
- NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
- return rv && !actualCropRect.IsEmpty();
- }
-
- return false;
-}
-
-bool
-nsStyleImage::IsComplete() const
-{
- switch (mType) {
- case eStyleImageType_Null:
- return false;
- case eStyleImageType_Gradient:
- case eStyleImageType_Element:
- return true;
- case eStyleImageType_Image:
- {
- uint32_t status = imgIRequest::STATUS_ERROR;
- return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
- (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
- (status & imgIRequest::STATUS_FRAME_COMPLETE);
- }
- default:
- NS_NOTREACHED("unexpected image type");
- return false;
- }
-}
-
-bool
-nsStyleImage::IsLoaded() const
-{
- switch (mType) {
- case eStyleImageType_Null:
- return false;
- case eStyleImageType_Gradient:
- case eStyleImageType_Element:
- return true;
- case eStyleImageType_Image:
- {
- uint32_t status = imgIRequest::STATUS_ERROR;
- return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
- !(status & imgIRequest::STATUS_ERROR) &&
- (status & imgIRequest::STATUS_LOAD_COMPLETE);
- }
- default:
- NS_NOTREACHED("unexpected image type");
- return false;
- }
-}
-
-static inline bool
-EqualRects(const UniquePtr<nsStyleSides>& aRect1, const UniquePtr<nsStyleSides>& aRect2)
-{
- return aRect1 == aRect2 || /* handles null== null, and optimize */
- (aRect1 && aRect2 && *aRect1 == *aRect2);
-}
-
-bool
-nsStyleImage::operator==(const nsStyleImage& aOther) const
-{
- if (mType != aOther.mType) {
- return false;
- }
-
- if (!EqualRects(mCropRect, aOther.mCropRect)) {
- return false;
- }
-
- if (mType == eStyleImageType_Image) {
- return EqualImages(mImage, aOther.mImage);
- }
-
- if (mType == eStyleImageType_Gradient) {
- return *mGradient == *aOther.mGradient;
- }
-
- if (mType == eStyleImageType_Element) {
- return NS_strcmp(mElementId, aOther.mElementId) == 0;
- }
-
- return true;
-}
-
-void
-nsStyleImage::PurgeCacheForViewportChange(
- const mozilla::Maybe<nsSize>& aSVGViewportSize,
- const bool aHasIntrinsicRatio) const
-{
- EnsureCachedBIData();
-
- // If we're redrawing with a different viewport-size than we used for our
- // cached subimages, then we can't trust that our subimages are valid;
- // any percent sizes/positions in our SVG doc may be different now. Purge!
- // (We don't have to purge if the SVG document has an intrinsic ratio,
- // though, because the actual size of elements in SVG documant's coordinate
- // axis are fixed in this case.)
- if (aSVGViewportSize != mCachedBIData->GetCachedSVGViewportSize() &&
- !aHasIntrinsicRatio) {
- mCachedBIData->PurgeCachedImages();
- mCachedBIData->SetCachedSVGViewportSize(aSVGViewportSize);
- }
-}
-
-// --------------------
// nsStyleImageLayers
//
const nsCSSPropertyID nsStyleImageLayers::kBackgroundLayerTable[] = {
eCSSProperty_background, // shorthand
eCSSProperty_background_color, // color
eCSSProperty_background_image, // image
eCSSProperty_background_repeat, // repeat
@@ -3094,17 +2716,17 @@ nsStyleDisplay::nsStyleDisplay(const nsS
mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1];
}
nsChangeHint
nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const
{
nsChangeHint hint = nsChangeHint(0);
- if (!EqualURIs(mBinding, aNewData.mBinding)
+ if (!mozilla::EqualURIs(mBinding, aNewData.mBinding)
|| mPosition != aNewData.mPosition
|| mDisplay != aNewData.mDisplay
|| mContain != aNewData.mContain
|| (mFloat == NS_STYLE_FLOAT_NONE) != (aNewData.mFloat == NS_STYLE_FLOAT_NONE)
|| mOverflowX != aNewData.mOverflowX
|| mOverflowY != aNewData.mOverflowY
|| mScrollBehavior != aNewData.mScrollBehavior
|| mScrollSnapTypeX != aNewData.mScrollSnapTypeX
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -21,16 +21,17 @@
#include "mozilla/StyleStructContext.h"
#include "mozilla/UniquePtr.h"
#include "nsColor.h"
#include "nsCoord.h"
#include "nsMargin.h"
#include "nsFont.h"
#include "nsStyleCoord.h"
#include "nsStyleConsts.h"
+#include "nsStyleImage.h"
#include "nsChangeHint.h"
#include "nsPresContext.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsCSSValue.h"
#include "imgRequestProxy.h"
#include "Orientation.h"
@@ -105,16 +106,28 @@ static_assert(int(mozilla::SheetType::Co
"NS_RULE_NODE_LEVEL_MASK cannot fit SheetType");
static_assert(NS_STYLE_INHERIT_MASK == (1 << nsStyleStructID_Length) - 1,
"NS_STYLE_INHERIT_MASK is not correct");
static_assert((NS_RULE_NODE_IS_ANIMATION_RULE & NS_STYLE_INHERIT_MASK) == 0,
"NS_RULE_NODE_IS_ANIMATION_RULE must not overlap the style struct bits.");
+struct FragmentOrURL;
+
+namespace mozilla {
+
+bool EqualURIs(nsIURI *aURI1, nsIURI *aURI2);
+bool EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2);
+bool EqualURIs(const FragmentOrURL* aURI1, const FragmentOrURL* aURI2);
+
+bool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2);
+
+} // namespace mozilla
+
struct FragmentOrURL
{
FragmentOrURL() : mIsLocalRef(false) {}
FragmentOrURL(const FragmentOrURL& aSource)
: mIsLocalRef(false)
{ *this = aSource; }
void SetValue(const nsCSSValue* aValue);
@@ -268,179 +281,16 @@ public:
private:
// Private destructor, to discourage deletion outside of Release():
~nsStyleGradient() {}
nsStyleGradient(const nsStyleGradient& aOther) = delete;
nsStyleGradient& operator=(const nsStyleGradient& aOther) = delete;
};
-enum nsStyleImageType {
- eStyleImageType_Null,
- eStyleImageType_Image,
- eStyleImageType_Gradient,
- eStyleImageType_Element
-};
-
-struct CachedBorderImageData
-{
- // Caller are expected to ensure that the value of aSVGViewportSize is
- // different from the cached one since the method won't do the check.
- void SetCachedSVGViewportSize(const mozilla::Maybe<nsSize>& aSVGViewportSize);
- const mozilla::Maybe<nsSize>& GetCachedSVGViewportSize();
- void PurgeCachedImages();
- void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage);
- imgIContainer* GetSubImage(uint8_t aIndex);
-
-private:
- // If this is a SVG border-image, we save the size of the SVG viewport that
- // we used when rasterizing any cached border-image subimages. (The viewport
- // size matters for percent-valued sizes & positions in inner SVG doc).
- mozilla::Maybe<nsSize> mCachedSVGViewportSize;
- nsCOMArray<imgIContainer> mSubImages;
-};
-
-/**
- * Represents a paintable image of one of the following types.
- * (1) A real image loaded from an external source.
- * (2) A CSS linear or radial gradient.
- * (3) An element within a document, or an <img>, <video>, or <canvas> element
- * not in a document.
- * (*) Optionally a crop rect can be set to paint a partial (rectangular)
- * region of an image. (Currently, this feature is only supported with an
- * image of type (1)).
- */
-struct nsStyleImage
-{
- nsStyleImage();
- ~nsStyleImage();
- nsStyleImage(const nsStyleImage& aOther);
- nsStyleImage& operator=(const nsStyleImage& aOther);
-
- void SetNull();
- void SetImageData(imgRequestProxy* aImage);
- void TrackImage(nsPresContext* aContext);
- void UntrackImage(nsPresContext* aContext);
- void SetGradientData(nsStyleGradient* aGradient);
- void SetElementId(const char16_t* aElementId);
- void SetCropRect(mozilla::UniquePtr<nsStyleSides> aCropRect);
-
- nsStyleImageType GetType() const {
- return mType;
- }
- imgRequestProxy* GetImageData() const {
- MOZ_ASSERT(mType == eStyleImageType_Image, "Data is not an image!");
- MOZ_ASSERT(mImageTracked,
- "Should be tracking any image we're going to use!");
- return mImage;
- }
- nsStyleGradient* GetGradientData() const {
- NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
- return mGradient;
- }
- const char16_t* GetElementId() const {
- NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!");
- return mElementId;
- }
- const mozilla::UniquePtr<nsStyleSides>& GetCropRect() const {
- NS_ASSERTION(mType == eStyleImageType_Image,
- "Only image data can have a crop rect");
- return mCropRect;
- }
-
- /**
- * Compute the actual crop rect in pixels, using the source image bounds.
- * The computation involves converting percentage unit to pixel unit and
- * clamping each side value to fit in the source image bounds.
- * @param aActualCropRect the computed actual crop rect.
- * @param aIsEntireImage true iff |aActualCropRect| is identical to the
- * source image bounds.
- * @return true iff |aActualCropRect| holds a meaningful value.
- */
- bool ComputeActualCropRect(nsIntRect& aActualCropRect,
- bool* aIsEntireImage = nullptr) const;
-
- /**
- * Starts the decoding of a image.
- */
- nsresult StartDecoding() const;
- /**
- * @return true if the item is definitely opaque --- i.e., paints every
- * pixel within its bounds opaquely, and the bounds contains at least a pixel.
- */
- bool IsOpaque() const;
- /**
- * @return true if this image is fully loaded, and its size is calculated;
- * always returns true if |mType| is |eStyleImageType_Gradient| or
- * |eStyleImageType_Element|.
- */
- bool IsComplete() const;
- /**
- * @return true if this image is loaded without error;
- * always returns true if |mType| is |eStyleImageType_Gradient| or
- * |eStyleImageType_Element|.
- */
- bool IsLoaded() const;
- /**
- * @return true if it is 100% confident that this image contains no pixel
- * to draw.
- */
- bool IsEmpty() const {
- // There are some other cases when the image will be empty, for example
- // when the crop rect is empty. However, checking the emptiness of crop
- // rect is non-trivial since each side value can be specified with
- // percentage unit, which can not be evaluated until the source image size
- // is available. Therefore, we currently postpone the evaluation of crop
- // rect until the actual rendering time --- alternatively until GetOpaqueRegion()
- // is called.
- return mType == eStyleImageType_Null;
- }
-
- bool operator==(const nsStyleImage& aOther) const;
- bool operator!=(const nsStyleImage& aOther) const {
- return !(*this == aOther);
- }
-
- bool ImageDataEquals(const nsStyleImage& aOther) const
- {
- return GetType() == eStyleImageType_Image &&
- aOther.GetType() == eStyleImageType_Image &&
- GetImageData() == aOther.GetImageData();
- }
-
- // These methods are used for the caller to caches the sub images created
- // during a border-image paint operation
- inline void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage) const;
- inline imgIContainer* GetSubImage(uint8_t aIndex) const;
- void PurgeCacheForViewportChange(
- const mozilla::Maybe<nsSize>& aSVGViewportSize,
- const bool aHasIntrinsicRatio) const;
-
-private:
- void DoCopy(const nsStyleImage& aOther);
- void EnsureCachedBIData() const;
-
- // This variable keeps some cache data for border image and is lazily
- // allocated since it is only used in border image case.
- mozilla::UniquePtr<CachedBorderImageData> mCachedBIData;
-
- nsStyleImageType mType;
- union {
- imgRequestProxy* mImage;
- nsStyleGradient* mGradient;
- char16_t* mElementId;
- };
-
- // This is _currently_ used only in conjunction with eStyleImageType_Image.
- mozilla::UniquePtr<nsStyleSides> mCropRect;
-#ifdef DEBUG
- bool mImageTracked;
-#endif
-};
-
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColor
{
explicit nsStyleColor(StyleStructContext aContext);
nsStyleColor(const nsStyleColor& aOther);
~nsStyleColor() {
MOZ_COUNT_DTOR(nsStyleColor);
}