summaryrefslogtreecommitdiffstats
path: root/layout/generic/TextDrawTarget.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/TextDrawTarget.h')
-rw-r--r--layout/generic/TextDrawTarget.h618
1 files changed, 618 insertions, 0 deletions
diff --git a/layout/generic/TextDrawTarget.h b/layout/generic/TextDrawTarget.h
new file mode 100644
index 0000000000..fadd7049fb
--- /dev/null
+++ b/layout/generic/TextDrawTarget.h
@@ -0,0 +1,618 @@
+/* -*- 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/. */
+
+#ifndef TextDrawTarget_h
+#define TextDrawTarget_h
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/RenderRootStateManager.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/layers/IpcResourceUpdateQueue.h"
+
+namespace mozilla {
+namespace layout {
+
+using namespace gfx;
+
+// This class is a fake DrawTarget, used to intercept text draw calls, while
+// also collecting up the other aspects of text natively.
+//
+// When using advanced-layers in nsDisplayText's constructor, we construct this
+// and run the full painting algorithm with this as the DrawTarget. This is
+// done to avoid having to massively refactor gecko's text painting code (which
+// has lots of components shared between other rendering algorithms).
+//
+// In some phases of the painting algorithm, we can grab the relevant values
+// and feed them directly into TextDrawTarget. For instance, selections,
+// decorations, and shadows are handled in this manner. In those cases we can
+// also short-circuit the painting algorithm to save work.
+//
+// In other phases, the computed values are sufficiently buried in complex
+// code that it's best for us to just intercept the final draw calls. This
+// is how we handle computing the glyphs of the main text and text-emphasis
+// (see our overloaded FillGlyphs implementation).
+//
+// To be clear: this is a big hack. With time we hope to refactor the codebase
+// so that all the elements of text are handled directly by TextDrawTarget,
+// which is to say everything is done like we do selections and shadows now.
+// This design is a good step for doing this work incrementally.
+//
+// This is also likely to be a bit buggy (missing or misinterpreted info)
+// while we further develop the design.
+//
+// TextDrawTarget doesn't yet support all features. See mHasUnsupportedFeatures
+// for details.
+class TextDrawTarget : public DrawTarget {
+ public:
+ explicit TextDrawTarget(wr::DisplayListBuilder& aBuilder,
+ wr::IpcResourceUpdateQueue& aResources,
+ const layers::StackingContextHelper& aSc,
+ layers::RenderRootStateManager* aManager,
+ nsDisplayItem* aItem, nsRect& aBounds,
+ bool aCallerDoesSaveRestore = false)
+ : mCallerDoesSaveRestore(aCallerDoesSaveRestore), mBuilder(aBuilder) {
+ Reinitialize(aResources, aSc, aManager, aItem, aBounds);
+ }
+
+ // Prevent this from being copied
+ TextDrawTarget(const TextDrawTarget& src) = delete;
+ TextDrawTarget& operator=(const TextDrawTarget&) = delete;
+
+ ~TextDrawTarget() { MOZ_ASSERT(mFinished); }
+
+ void Reinitialize(wr::IpcResourceUpdateQueue& aResources,
+ const layers::StackingContextHelper& aSc,
+ layers::RenderRootStateManager* aManager,
+ nsDisplayItem* aItem, nsRect& aBounds) {
+ mResources = &aResources;
+ mSc = &aSc;
+ mManager = aManager;
+ mHasUnsupportedFeatures = false;
+ mHasShadows = false;
+
+ SetPermitSubpixelAA(!aItem->IsSubpixelAADisabled());
+
+ // Compute clip/bounds
+ auto appUnitsPerDevPixel =
+ aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+ LayoutDeviceRect layoutBoundsRect =
+ LayoutDeviceRect::FromAppUnits(aBounds, appUnitsPerDevPixel);
+ LayoutDeviceRect layoutClipRect = layoutBoundsRect;
+ mBoundsRect = wr::ToLayoutRect(layoutBoundsRect);
+
+ // Add 1 pixel of dirty area around clip rect to allow us to paint
+ // antialiased pixels beyond the measured text extents.
+ layoutClipRect.Inflate(1);
+ mSize = IntSize::Ceil(layoutClipRect.Width(), layoutClipRect.Height());
+ mClipStack.ClearAndRetainStorage();
+ mClipStack.AppendElement(layoutClipRect);
+
+ mBackfaceVisible = !aItem->BackfaceIsHidden();
+
+ if (!mCallerDoesSaveRestore) {
+ mBuilder.Save();
+ }
+ }
+
+ void FoundUnsupportedFeature() { mHasUnsupportedFeatures = true; }
+ bool CheckHasUnsupportedFeatures() {
+ MOZ_ASSERT(mCallerDoesSaveRestore);
+#ifdef DEBUG
+ MOZ_ASSERT(!mFinished);
+ mFinished = true;
+#endif
+ return mHasUnsupportedFeatures;
+ }
+
+ bool Finish() {
+ MOZ_ASSERT(!mCallerDoesSaveRestore);
+#ifdef DEBUG
+ mFinished = true;
+#endif
+ if (mHasUnsupportedFeatures) {
+ mBuilder.Restore();
+ return false;
+ }
+ mBuilder.ClearSave();
+ return true;
+ }
+
+ wr::FontInstanceFlags GetWRGlyphFlags() const { return mWRGlyphFlags; }
+ void SetWRGlyphFlags(wr::FontInstanceFlags aFlags) { mWRGlyphFlags = aFlags; }
+
+ class AutoRestoreWRGlyphFlags {
+ public:
+ ~AutoRestoreWRGlyphFlags() {
+ if (mTarget) {
+ mTarget->SetWRGlyphFlags(mFlags);
+ }
+ }
+
+ void Save(TextDrawTarget* aTarget) {
+ // This allows for recursive saves, in case the flags need to be modified
+ // under multiple conditions (i.e. transforms and synthetic italics),
+ // since the flags will be restored to the first saved value in the
+ // destructor on scope exit.
+ if (!mTarget) {
+ // Only record the first save with the original flags that will be
+ // restored.
+ mTarget = aTarget;
+ mFlags = aTarget->GetWRGlyphFlags();
+ } else {
+ // Ensure that this is actually a recursive save to the same target
+ MOZ_ASSERT(
+ mTarget == aTarget,
+ "Recursive save of WR glyph flags to different TextDrawTargets");
+ }
+ }
+
+ private:
+ TextDrawTarget* mTarget = nullptr;
+ wr::FontInstanceFlags mFlags = {0};
+ };
+
+ // This overload just stores the glyphs/font/color.
+ void FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
+ const Pattern& aPattern,
+ const DrawOptions& aOptions) override {
+ // Make sure we're only given boring color patterns
+ MOZ_RELEASE_ASSERT(aOptions.mCompositionOp == CompositionOp::OP_OVER);
+ MOZ_RELEASE_ASSERT(aOptions.mAlpha == 1.0f);
+ MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR);
+
+ // Make sure the font exists, and can be serialized
+ MOZ_RELEASE_ASSERT(aFont);
+ if (!aFont->CanSerialize()) {
+ FoundUnsupportedFeature();
+ return;
+ }
+
+ auto* colorPat = static_cast<const ColorPattern*>(&aPattern);
+ auto color = wr::ToColorF(colorPat->mColor);
+ MOZ_ASSERT(aBuffer.mNumGlyphs);
+ auto glyphs = Range<const wr::GlyphInstance>(
+ reinterpret_cast<const wr::GlyphInstance*>(aBuffer.mGlyphs),
+ aBuffer.mNumGlyphs);
+ // MSVC won't let us use offsetof on the following directly so we give it a
+ // name with typedef
+ typedef std::remove_reference<decltype(aBuffer.mGlyphs[0])>::type GlyphType;
+ // Compare gfx::Glyph and wr::GlyphInstance to make sure that they are
+ // structurally equivalent to ensure that our cast above was ok
+ static_assert(
+ std::is_same<decltype(aBuffer.mGlyphs[0].mIndex),
+ decltype(glyphs[0].index)>() &&
+ std::is_same<decltype(aBuffer.mGlyphs[0].mPosition.x),
+ decltype(glyphs[0].point.x)>() &&
+ std::is_same<decltype(aBuffer.mGlyphs[0].mPosition.y),
+ decltype(glyphs[0].point.y)>() &&
+ offsetof(GlyphType, mIndex) == offsetof(wr::GlyphInstance, index) &&
+ offsetof(GlyphType, mPosition) ==
+ offsetof(wr::GlyphInstance, point) &&
+ offsetof(decltype(aBuffer.mGlyphs[0].mPosition), x) ==
+ offsetof(decltype(glyphs[0].point), x) &&
+ offsetof(decltype(aBuffer.mGlyphs[0].mPosition), y) ==
+ offsetof(decltype(glyphs[0].point), y) &&
+ std::is_standard_layout<
+ std::remove_reference<decltype(aBuffer.mGlyphs[0])>>::value &&
+ std::is_standard_layout<
+ std::remove_reference<decltype(glyphs[0])>>::value &&
+ sizeof(aBuffer.mGlyphs[0]) == sizeof(glyphs[0]) &&
+ sizeof(aBuffer.mGlyphs[0].mPosition) == sizeof(glyphs[0].point),
+ "glyph buf types don't match");
+
+ wr::GlyphOptions glyphOptions;
+ glyphOptions.render_mode =
+ wr::ToFontRenderMode(aOptions.mAntialiasMode, GetPermitSubpixelAA());
+ glyphOptions.flags = mWRGlyphFlags;
+
+ mManager->WrBridge()->PushGlyphs(mBuilder, glyphs, aFont, color, *mSc,
+ mBoundsRect, ClipRect(), mBackfaceVisible,
+ &glyphOptions);
+ }
+
+ void PushClipRect(const Rect& aRect) override {
+ LayoutDeviceRect rect = LayoutDeviceRect::FromUnknownRect(aRect);
+ rect = rect.Intersect(mClipStack.LastElement());
+ mClipStack.AppendElement(rect);
+ }
+
+ void PopClip() override { mClipStack.RemoveLastElement(); }
+
+ IntSize GetSize() const override { return mSize; }
+
+ void AppendShadow(const wr::Shadow& aShadow, bool aInflate) {
+ mBuilder.PushShadow(mBoundsRect, ClipRect(), mBackfaceVisible, aShadow,
+ aInflate);
+ mHasShadows = true;
+ }
+
+ void TerminateShadows() {
+ if (mHasShadows) {
+ mBuilder.PopAllShadows();
+ mHasShadows = false;
+ }
+ }
+
+ void AppendSelectionRect(const LayoutDeviceRect& aRect,
+ const DeviceColor& aColor) {
+ auto rect = wr::ToLayoutRect(aRect);
+ auto color = wr::ToColorF(aColor);
+ mBuilder.PushRect(rect, ClipRect(), mBackfaceVisible, color);
+ }
+
+ // This function is basically designed to slide into the decoration drawing
+ // code of nsCSSRendering with minimum disruption, to minimize the
+ // chances of implementation drift. As such, it mostly looks like a call
+ // to a skia-style StrokeLine method: two end-points, with a thickness
+ // and style. Notably the end-points are *centered* in the block direction,
+ // even though webrender wants a rect-like representation, where the points
+ // are on corners.
+ //
+ // So we mangle the format here in a single centralized place, where neither
+ // webrender nor nsCSSRendering has to care about this mismatch.
+ //
+ // NOTE: we assume the points are axis-aligned, and aStart should be used
+ // as the top-left corner of the rect.
+ void AppendDecoration(const Point& aStart, const Point& aEnd,
+ const float aThickness, const bool aVertical,
+ const DeviceColor& aColor, const uint8_t aStyle) {
+ auto pos = LayoutDevicePoint::FromUnknownPoint(aStart);
+ LayoutDeviceSize size;
+
+ if (aVertical) {
+ pos.x -= aThickness / 2; // adjust from center to corner
+ size = LayoutDeviceSize(aThickness, aEnd.y - aStart.y);
+ } else {
+ pos.y -= aThickness / 2; // adjust from center to corner
+ size = LayoutDeviceSize(aEnd.x - aStart.x, aThickness);
+ }
+
+ wr::Line decoration;
+ decoration.bounds = wr::ToLayoutRect(LayoutDeviceRect(pos, size));
+ decoration.wavyLineThickness = 0; // dummy value, unused
+ decoration.color = wr::ToColorF(aColor);
+ decoration.orientation = aVertical ? wr::LineOrientation::Vertical
+ : wr::LineOrientation::Horizontal;
+
+ switch (aStyle) {
+ case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
+ decoration.style = wr::LineStyle::Solid;
+ break;
+ case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
+ decoration.style = wr::LineStyle::Dotted;
+ break;
+ case NS_STYLE_TEXT_DECORATION_STYLE_DASHED:
+ decoration.style = wr::LineStyle::Dashed;
+ break;
+ // Wavy lines should go through AppendWavyDecoration
+ case NS_STYLE_TEXT_DECORATION_STYLE_WAVY:
+ // Double lines should be lowered to two solid lines
+ case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE:
+ default:
+ MOZ_CRASH("TextDrawTarget received unsupported line style");
+ }
+
+ mBuilder.PushLine(ClipRect(), mBackfaceVisible, decoration);
+ }
+
+ // Seperated out from AppendDecoration because Wavy Lines are completely
+ // different, and trying to merge the concept is more of a mess than it's
+ // worth.
+ void AppendWavyDecoration(const Rect& aBounds, const float aThickness,
+ const bool aVertical, const DeviceColor& aColor) {
+ wr::Line decoration;
+
+ decoration.bounds =
+ wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aBounds));
+ decoration.wavyLineThickness = aThickness;
+ decoration.color = wr::ToColorF(aColor);
+ decoration.orientation = aVertical ? wr::LineOrientation::Vertical
+ : wr::LineOrientation::Horizontal;
+ decoration.style = wr::LineStyle::Wavy;
+
+ mBuilder.PushLine(ClipRect(), mBackfaceVisible, decoration);
+ }
+
+ layers::WebRenderBridgeChild* WrBridge() { return mManager->WrBridge(); }
+ layers::WebRenderLayerManager* WrLayerManager() {
+ return mManager->LayerManager();
+ }
+
+ Maybe<wr::ImageKey> DefineImage(const IntSize& aSize, uint32_t aStride,
+ SurfaceFormat aFormat, const uint8_t* aData) {
+ wr::ImageKey key = mManager->WrBridge()->GetNextImageKey();
+ wr::ImageDescriptor desc(aSize, aStride, aFormat);
+ Range<uint8_t> bytes(const_cast<uint8_t*>(aData), aStride * aSize.height);
+ if (mResources->AddImage(key, desc, bytes)) {
+ return Some(key);
+ }
+ return Nothing();
+ }
+
+ void PushImage(wr::ImageKey aKey, const Rect& aBounds, const Rect& aClip,
+ wr::ImageRendering aFilter, const wr::ColorF& aColor) {
+ if (!aClip.Intersects(GeckoClipRect().ToUnknownRect())) {
+ return;
+ }
+ mBuilder.PushImage(wr::ToLayoutRect(aBounds), wr::ToLayoutRect(aClip), true,
+ aFilter, aKey, true, aColor);
+ }
+
+ private:
+ wr::LayoutRect ClipRect() {
+ return wr::ToLayoutRect(mClipStack.LastElement());
+ }
+ LayoutDeviceRect GeckoClipRect() { return mClipStack.LastElement(); }
+ // Whether anything unsupported was encountered. This will result in this
+ // text being emitted as a blob, which means subpixel-AA can't be used and
+ // that performance will probably be a bit worse. At this point, we've
+ // properly implemented everything that shows up a lot, so you can assume
+ // that the remaining things we don't implement are fairly rare. The complete
+ // set of things that we don't implement are as follows:
+ //
+ // * Unserializable Fonts: WR lives across an IPC boundary
+ // * Text-Combine-Upright Squishing: no one's really bothered to impl it yet
+ // * Text-Stroke: not a real standard (exists for webcompat)
+ // * SVG Glyphs: not a real standard (we got overzealous with svg)
+ // * Color Glyphs (Emoji) With Transparency: requires us to apply transparency
+ // with a composited layer (a single emoji can be many single-color glyphs)
+ //
+ // The transparent colored-glyphs issue is probably the most valuable to fix,
+ // since ideally it would also result in us fixing transparency for all
+ // intersecting glyphs (which currently look bad with or without webrender,
+ // so there's no fallback like with emoji). Specifically, transparency
+ // looks bad for "cursive" fonts where glyphs overlap at the seams. Since
+ // this is more common for non-latin scripts (e.g. मनीष), this amounts to us
+ // treating non-latin scripts poorly... unless they're emoji. Yikes!
+ bool mHasUnsupportedFeatures = false;
+
+ // The caller promises to call Save/Restore on the builder as needed.
+ bool mCallerDoesSaveRestore = false;
+#ifdef DEBUG
+ bool mFinished = false;
+#endif
+
+ // Whether PopAllShadows needs to be called
+ bool mHasShadows = false;
+
+ // Things used to push to webrender
+ wr::DisplayListBuilder& mBuilder;
+ wr::IpcResourceUpdateQueue* mResources;
+ const layers::StackingContextHelper* mSc;
+ layers::RenderRootStateManager* mManager;
+
+ // Computed facts
+ IntSize mSize;
+ wr::LayoutRect mBoundsRect;
+ AutoTArray<LayoutDeviceRect, 3> mClipStack;
+ bool mBackfaceVisible;
+
+ wr::FontInstanceFlags mWRGlyphFlags = {0};
+
+ // The rest of this is dummy implementations of DrawTarget's API
+ public:
+ DrawTargetType GetType() const override {
+ return DrawTargetType::SOFTWARE_RASTER;
+ }
+
+ BackendType GetBackendType() const override {
+ return BackendType::WEBRENDER_TEXT;
+ }
+
+ bool IsRecording() const override { return true; }
+ bool IsCaptureDT() const override { return false; }
+
+ already_AddRefed<SourceSurface> Snapshot() override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ already_AddRefed<SourceSurface> IntoLuminanceSource(
+ LuminanceType aLuminanceType, float aOpacity) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ void Flush() override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void DrawCapturedDT(DrawTargetCapture* aCaptureDT,
+ const Matrix& aTransform) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void DrawSurface(SourceSurface* aSurface, const Rect& aDest,
+ const Rect& aSource, const DrawSurfaceOptions& aSurfOptions,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
+ const Point& aDestPoint,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void DrawSurfaceWithShadow(SourceSurface* aSurface, const Point& aDest,
+ const DeviceColor& aColor, const Point& aOffset,
+ Float aSigma, CompositionOp aOperator) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void ClearRect(const Rect& aRect) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect,
+ const IntPoint& aDestination) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void FillRect(const Rect& aRect, const Pattern& aPattern,
+ const DrawOptions& aOptions = DrawOptions()) override {
+ MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR);
+
+ if (!aRect.Intersects(GeckoClipRect().ToUnknownRect())) {
+ return;
+ }
+ auto rect = wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect));
+ auto color =
+ wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor);
+ mBuilder.PushRect(rect, ClipRect(), mBackfaceVisible, color);
+ }
+
+ void StrokeRect(const Rect& aRect, const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aOptions) override {
+ MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR &&
+ aStrokeOptions.mDashLength == 0);
+
+ wr::LayoutSideOffsets widths = {
+ aStrokeOptions.mLineWidth, aStrokeOptions.mLineWidth,
+ aStrokeOptions.mLineWidth, aStrokeOptions.mLineWidth};
+ wr::ColorF color =
+ wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor);
+ wr::BorderSide sides[4] = {{color, wr::BorderStyle::Solid},
+ {color, wr::BorderStyle::Solid},
+ {color, wr::BorderStyle::Solid},
+ {color, wr::BorderStyle::Solid}};
+ wr::BorderRadius radius = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
+ LayoutDeviceRect rect = LayoutDeviceRect::FromUnknownRect(aRect);
+ rect.Inflate(aStrokeOptions.mLineWidth / 2);
+ if (!rect.Intersects(GeckoClipRect())) {
+ return;
+ }
+ wr::LayoutRect bounds = wr::ToLayoutRect(rect);
+ mBuilder.PushBorder(bounds, ClipRect(), true, widths,
+ Range<const wr::BorderSide>(sides, 4), radius);
+ }
+
+ void StrokeLine(const Point& aStart, const Point& aEnd,
+ const Pattern& aPattern, const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void Stroke(const Path* aPath, const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void Fill(const Path* aPath, const Pattern& aPattern,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void StrokeGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
+ const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void Mask(const Pattern& aSource, const Pattern& aMask,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void MaskSurface(const Pattern& aSource, SourceSurface* aMask, Point aOffset,
+ const DrawOptions& aOptions) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ bool Draw3DTransformedSurface(SourceSurface* aSurface,
+ const Matrix4x4& aMatrix) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void PushClip(const Path* aPath) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void PushDeviceSpaceClipRects(const IntRect* aRects,
+ uint32_t aCount) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+
+ void PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
+ const Matrix& aMaskTransform, const IntRect& aBounds,
+ bool aCopyBackground) override {
+ // Fine to pretend we do this
+ }
+
+ void PopLayer() override {
+ // Fine to pretend we do this
+ }
+
+ already_AddRefed<SourceSurface> CreateSourceSurfaceFromData(
+ unsigned char* aData, const IntSize& aSize, int32_t aStride,
+ SurfaceFormat aFormat) const override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ already_AddRefed<SourceSurface> OptimizeSourceSurface(
+ SourceSurface* aSurface) const override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ already_AddRefed<SourceSurface> CreateSourceSurfaceFromNativeSurface(
+ const NativeSurface& aSurface) const override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ already_AddRefed<DrawTarget> CreateSimilarDrawTarget(
+ const IntSize& aSize, SurfaceFormat aFormat) const override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ bool CanCreateSimilarDrawTarget(const IntSize& aSize,
+ SurfaceFormat aFormat) const override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return false;
+ }
+
+ virtual RefPtr<DrawTarget> CreateClippedDrawTarget(
+ const Rect& aBounds, SurfaceFormat aFormat) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ already_AddRefed<PathBuilder> CreatePathBuilder(
+ FillRule aFillRule) const override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ already_AddRefed<FilterNode> CreateFilter(FilterType aType) override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ already_AddRefed<GradientStops> CreateGradientStops(
+ GradientStop* aStops, uint32_t aNumStops,
+ ExtendMode aExtendMode) const override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ return nullptr;
+ }
+
+ void DetachAllSnapshots() override {
+ MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+ }
+};
+
+} // namespace layout
+} // namespace mozilla
+
+#endif