1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef TextDrawTarget_h
8 #define TextDrawTarget_h
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/layers/RenderRootStateManager.h"
12 #include "mozilla/layers/WebRenderLayerManager.h"
13 #include "mozilla/layers/WebRenderBridgeChild.h"
14 #include "mozilla/webrender/WebRenderAPI.h"
15 #include "mozilla/layers/StackingContextHelper.h"
16 #include "mozilla/layers/IpcResourceUpdateQueue.h"
23 // This class is a fake DrawTarget, used to intercept text draw calls, while
24 // also collecting up the other aspects of text natively.
26 // When using advanced-layers in nsDisplayText's constructor, we construct this
27 // and run the full painting algorithm with this as the DrawTarget. This is
28 // done to avoid having to massively refactor gecko's text painting code (which
29 // has lots of components shared between other rendering algorithms).
31 // In some phases of the painting algorithm, we can grab the relevant values
32 // and feed them directly into TextDrawTarget. For instance, selections,
33 // decorations, and shadows are handled in this manner. In those cases we can
34 // also short-circuit the painting algorithm to save work.
36 // In other phases, the computed values are sufficiently buried in complex
37 // code that it's best for us to just intercept the final draw calls. This
38 // is how we handle computing the glyphs of the main text and text-emphasis
39 // (see our overloaded FillGlyphs implementation).
41 // To be clear: this is a big hack. With time we hope to refactor the codebase
42 // so that all the elements of text are handled directly by TextDrawTarget,
43 // which is to say everything is done like we do selections and shadows now.
44 // This design is a good step for doing this work incrementally.
46 // This is also likely to be a bit buggy (missing or misinterpreted info)
47 // while we further develop the design.
49 // TextDrawTarget doesn't yet support all features. See mHasUnsupportedFeatures
51 class TextDrawTarget
: public DrawTarget
{
53 explicit TextDrawTarget(wr::DisplayListBuilder
& aBuilder
,
54 wr::IpcResourceUpdateQueue
& aResources
,
55 const layers::StackingContextHelper
& aSc
,
56 layers::RenderRootStateManager
* aManager
,
57 nsDisplayItem
* aItem
, nsRect
& aBounds
,
58 bool aCallerDoesSaveRestore
= false)
59 : mCallerDoesSaveRestore(aCallerDoesSaveRestore
), mBuilder(aBuilder
) {
60 Reinitialize(aResources
, aSc
, aManager
, aItem
, aBounds
);
63 // Prevent this from being copied
64 TextDrawTarget(const TextDrawTarget
& src
) = delete;
65 TextDrawTarget
& operator=(const TextDrawTarget
&) = delete;
67 ~TextDrawTarget() { MOZ_ASSERT(mFinished
); }
69 void Reinitialize(wr::IpcResourceUpdateQueue
& aResources
,
70 const layers::StackingContextHelper
& aSc
,
71 layers::RenderRootStateManager
* aManager
,
72 nsDisplayItem
* aItem
, nsRect
& aBounds
) {
73 mResources
= &aResources
;
76 mHasUnsupportedFeatures
= false;
79 SetPermitSubpixelAA(true);
81 // Compute clip/bounds
82 auto appUnitsPerDevPixel
=
83 aItem
->Frame()->PresContext()->AppUnitsPerDevPixel();
84 LayoutDeviceRect layoutBoundsRect
=
85 LayoutDeviceRect::FromAppUnits(aBounds
, appUnitsPerDevPixel
);
86 LayoutDeviceRect layoutClipRect
= layoutBoundsRect
;
87 mBoundsRect
= wr::ToLayoutRect(layoutBoundsRect
);
89 // Add 1 pixel of dirty area around clip rect to allow us to paint
90 // antialiased pixels beyond the measured text extents.
91 layoutClipRect
.Inflate(1);
92 mSize
= IntSize::Ceil(layoutClipRect
.Width(), layoutClipRect
.Height());
93 mClipStack
.ClearAndRetainStorage();
94 mClipStack
.AppendElement(layoutClipRect
);
96 mBackfaceVisible
= !aItem
->BackfaceIsHidden();
98 if (!mCallerDoesSaveRestore
) {
103 void FoundUnsupportedFeature() { mHasUnsupportedFeatures
= true; }
104 bool CheckHasUnsupportedFeatures() {
105 MOZ_ASSERT(mCallerDoesSaveRestore
);
107 MOZ_ASSERT(!mFinished
);
110 return mHasUnsupportedFeatures
;
114 MOZ_ASSERT(!mCallerDoesSaveRestore
);
118 if (mHasUnsupportedFeatures
) {
122 mBuilder
.ClearSave();
126 wr::FontInstanceFlags
GetWRGlyphFlags() const { return mWRGlyphFlags
; }
127 void SetWRGlyphFlags(wr::FontInstanceFlags aFlags
) { mWRGlyphFlags
= aFlags
; }
129 class AutoRestoreWRGlyphFlags
{
131 ~AutoRestoreWRGlyphFlags() {
133 mTarget
->SetWRGlyphFlags(mFlags
);
137 void Save(TextDrawTarget
* aTarget
) {
138 // This allows for recursive saves, in case the flags need to be modified
139 // under multiple conditions (i.e. transforms and synthetic italics),
140 // since the flags will be restored to the first saved value in the
141 // destructor on scope exit.
143 // Only record the first save with the original flags that will be
146 mFlags
= aTarget
->GetWRGlyphFlags();
148 // Ensure that this is actually a recursive save to the same target
151 "Recursive save of WR glyph flags to different TextDrawTargets");
156 TextDrawTarget
* mTarget
= nullptr;
157 wr::FontInstanceFlags mFlags
= {0};
160 // This overload just stores the glyphs/font/color.
161 void FillGlyphs(ScaledFont
* aFont
, const GlyphBuffer
& aBuffer
,
162 const Pattern
& aPattern
,
163 const DrawOptions
& aOptions
) override
{
164 // Make sure we're only given boring color patterns
165 MOZ_RELEASE_ASSERT(aOptions
.mCompositionOp
== CompositionOp::OP_OVER
);
166 MOZ_RELEASE_ASSERT(aOptions
.mAlpha
== 1.0f
);
167 MOZ_RELEASE_ASSERT(aPattern
.GetType() == PatternType::COLOR
);
169 // Make sure the font exists, and can be serialized
170 MOZ_RELEASE_ASSERT(aFont
);
171 if (!aFont
->CanSerialize()) {
172 FoundUnsupportedFeature();
176 auto* colorPat
= static_cast<const ColorPattern
*>(&aPattern
);
177 auto color
= wr::ToColorF(colorPat
->mColor
);
178 MOZ_ASSERT(aBuffer
.mNumGlyphs
);
179 auto glyphs
= Range
<const wr::GlyphInstance
>(
180 reinterpret_cast<const wr::GlyphInstance
*>(aBuffer
.mGlyphs
),
182 // MSVC won't let us use offsetof on the following directly so we give it a
184 typedef std::remove_reference
<decltype(aBuffer
.mGlyphs
[0])>::type GlyphType
;
185 // Compare gfx::Glyph and wr::GlyphInstance to make sure that they are
186 // structurally equivalent to ensure that our cast above was ok
188 std::is_same
<decltype(aBuffer
.mGlyphs
[0].mIndex
),
189 decltype(glyphs
[0].index
)>() &&
190 std::is_same
<decltype(aBuffer
.mGlyphs
[0].mPosition
.x
.value
),
191 decltype(glyphs
[0].point
.x
)>() &&
192 std::is_same
<decltype(aBuffer
.mGlyphs
[0].mPosition
.y
.value
),
193 decltype(glyphs
[0].point
.y
)>() &&
194 offsetof(GlyphType
, mIndex
) == offsetof(wr::GlyphInstance
, index
) &&
195 offsetof(GlyphType
, mPosition
) ==
196 offsetof(wr::GlyphInstance
, point
) &&
197 offsetof(decltype(aBuffer
.mGlyphs
[0].mPosition
), x
) ==
198 offsetof(decltype(glyphs
[0].point
), x
) &&
199 offsetof(decltype(aBuffer
.mGlyphs
[0].mPosition
), y
) ==
200 offsetof(decltype(glyphs
[0].point
), y
) &&
201 std::is_standard_layout
<
202 std::remove_reference
<decltype(aBuffer
.mGlyphs
[0])>>::value
&&
203 std::is_standard_layout
<
204 std::remove_reference
<decltype(glyphs
[0])>>::value
&&
205 sizeof(aBuffer
.mGlyphs
[0]) == sizeof(glyphs
[0]) &&
206 sizeof(aBuffer
.mGlyphs
[0].mPosition
) == sizeof(glyphs
[0].point
),
207 "glyph buf types don't match");
209 wr::GlyphOptions glyphOptions
;
210 glyphOptions
.render_mode
=
211 wr::ToFontRenderMode(aOptions
.mAntialiasMode
, GetPermitSubpixelAA());
212 glyphOptions
.flags
= mWRGlyphFlags
;
214 mManager
->WrBridge()->PushGlyphs(mBuilder
, *mResources
, glyphs
, aFont
,
215 color
, *mSc
, mBoundsRect
, ClipRect(),
216 mBackfaceVisible
, &glyphOptions
);
219 void PushClipRect(const Rect
& aRect
) override
{
220 LayoutDeviceRect rect
= LayoutDeviceRect::FromUnknownRect(aRect
);
221 rect
= rect
.Intersect(mClipStack
.LastElement());
222 mClipStack
.AppendElement(rect
);
225 void PopClip() override
{ mClipStack
.RemoveLastElement(); }
227 IntSize
GetSize() const override
{ return mSize
; }
229 void AppendShadow(const wr::Shadow
& aShadow
, bool aInflate
) {
230 mBuilder
.PushShadow(mBoundsRect
, ClipRect(), mBackfaceVisible
, aShadow
,
235 void TerminateShadows() {
237 mBuilder
.PopAllShadows();
242 void AppendSelectionRect(const LayoutDeviceRect
& aRect
,
243 const DeviceColor
& aColor
) {
244 auto rect
= wr::ToLayoutRect(aRect
);
245 auto color
= wr::ToColorF(aColor
);
246 mBuilder
.PushRect(rect
, ClipRect(), mBackfaceVisible
, false, false, color
);
249 // This function is basically designed to slide into the decoration drawing
250 // code of nsCSSRendering with minimum disruption, to minimize the
251 // chances of implementation drift. As such, it mostly looks like a call
252 // to a skia-style StrokeLine method: two end-points, with a thickness
253 // and style. Notably the end-points are *centered* in the block direction,
254 // even though webrender wants a rect-like representation, where the points
257 // So we mangle the format here in a single centralized place, where neither
258 // webrender nor nsCSSRendering has to care about this mismatch.
260 // NOTE: we assume the points are axis-aligned, and aStart should be used
261 // as the top-left corner of the rect.
262 void AppendDecoration(const Point
& aStart
, const Point
& aEnd
,
263 const float aThickness
, const bool aVertical
,
264 const DeviceColor
& aColor
,
265 const StyleTextDecorationStyle aStyle
) {
266 auto pos
= LayoutDevicePoint::FromUnknownPoint(aStart
);
267 LayoutDeviceSize size
;
270 pos
.x
-= aThickness
/ 2; // adjust from center to corner
271 size
= LayoutDeviceSize(aThickness
,
272 ViewAs
<LayoutDevicePixel
>(aEnd
.y
- aStart
.y
));
274 pos
.y
-= aThickness
/ 2; // adjust from center to corner
275 size
= LayoutDeviceSize(ViewAs
<LayoutDevicePixel
>(aEnd
.x
- aStart
.x
),
280 decoration
.bounds
= wr::ToLayoutRect(LayoutDeviceRect(pos
, size
));
281 decoration
.wavyLineThickness
= 0; // dummy value, unused
282 decoration
.color
= wr::ToColorF(aColor
);
283 decoration
.orientation
= aVertical
? wr::LineOrientation::Vertical
284 : wr::LineOrientation::Horizontal
;
287 case StyleTextDecorationStyle::Solid
:
288 decoration
.style
= wr::LineStyle::Solid
;
290 case StyleTextDecorationStyle::Dotted
:
291 decoration
.style
= wr::LineStyle::Dotted
;
293 case StyleTextDecorationStyle::Dashed
:
294 decoration
.style
= wr::LineStyle::Dashed
;
296 // Wavy lines should go through AppendWavyDecoration
297 case StyleTextDecorationStyle::Wavy
:
298 // Double lines should be lowered to two solid lines
299 case StyleTextDecorationStyle::Double
:
301 MOZ_CRASH("TextDrawTarget received unsupported line style");
304 mBuilder
.PushLine(ClipRect(), mBackfaceVisible
, decoration
);
307 // Seperated out from AppendDecoration because Wavy Lines are completely
308 // different, and trying to merge the concept is more of a mess than it's
310 void AppendWavyDecoration(const Rect
& aBounds
, const float aThickness
,
311 const bool aVertical
, const DeviceColor
& aColor
) {
315 wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aBounds
));
316 decoration
.wavyLineThickness
= aThickness
;
317 decoration
.color
= wr::ToColorF(aColor
);
318 decoration
.orientation
= aVertical
? wr::LineOrientation::Vertical
319 : wr::LineOrientation::Horizontal
;
320 decoration
.style
= wr::LineStyle::Wavy
;
322 mBuilder
.PushLine(ClipRect(), mBackfaceVisible
, decoration
);
325 layers::WebRenderBridgeChild
* WrBridge() { return mManager
->WrBridge(); }
326 layers::WebRenderLayerManager
* WrLayerManager() {
327 return mManager
->LayerManager();
330 Maybe
<wr::ImageKey
> DefineImage(const IntSize
& aSize
, uint32_t aStride
,
331 SurfaceFormat aFormat
, const uint8_t* aData
) {
332 wr::ImageKey key
= mManager
->WrBridge()->GetNextImageKey();
333 wr::ImageDescriptor
desc(aSize
, aStride
, aFormat
);
334 Range
<uint8_t> bytes(const_cast<uint8_t*>(aData
), aStride
* aSize
.height
);
335 if (mResources
->AddImage(key
, desc
, bytes
)) {
341 void PushImage(wr::ImageKey aKey
, const Rect
& aBounds
, const Rect
& aClip
,
342 wr::ImageRendering aFilter
, const wr::ColorF
& aColor
) {
343 if (!aClip
.Intersects(GeckoClipRect().ToUnknownRect())) {
346 mBuilder
.PushImage(wr::ToLayoutRect(aBounds
), wr::ToLayoutRect(aClip
), true,
347 false, aFilter
, aKey
, true, aColor
);
350 LayoutDeviceRect
GeckoClipRect() { return mClipStack
.LastElement(); }
353 wr::LayoutRect
ClipRect() {
354 return wr::ToLayoutRect(mClipStack
.LastElement());
356 // Whether anything unsupported was encountered. This will result in this
357 // text being emitted as a blob, which means subpixel-AA can't be used and
358 // that performance will probably be a bit worse. At this point, we've
359 // properly implemented everything that shows up a lot, so you can assume
360 // that the remaining things we don't implement are fairly rare. The complete
361 // set of things that we don't implement are as follows:
363 // * Unserializable Fonts: WR lives across an IPC boundary
364 // * Text-Combine-Upright Squishing: no one's really bothered to impl it yet
365 // * Text-Stroke: not a real standard (exists for webcompat)
366 // * SVG Glyphs: not a real standard (we got overzealous with svg)
367 // * Color Glyphs (Emoji) With Transparency: requires us to apply transparency
368 // with a composited layer (a single emoji can be many single-color glyphs)
370 // The transparent colored-glyphs issue is probably the most valuable to fix,
371 // since ideally it would also result in us fixing transparency for all
372 // intersecting glyphs (which currently look bad with or without webrender,
373 // so there's no fallback like with emoji). Specifically, transparency
374 // looks bad for "cursive" fonts where glyphs overlap at the seams. Since
375 // this is more common for non-latin scripts (e.g. मनीष), this amounts to us
376 // treating non-latin scripts poorly... unless they're emoji. Yikes!
377 bool mHasUnsupportedFeatures
= false;
379 // The caller promises to call Save/Restore on the builder as needed.
380 bool mCallerDoesSaveRestore
= false;
382 bool mFinished
= false;
385 // Whether PopAllShadows needs to be called
386 bool mHasShadows
= false;
388 // Things used to push to webrender
389 wr::DisplayListBuilder
& mBuilder
;
390 wr::IpcResourceUpdateQueue
* mResources
;
391 const layers::StackingContextHelper
* mSc
;
392 layers::RenderRootStateManager
* mManager
;
396 wr::LayoutRect mBoundsRect
;
397 AutoTArray
<LayoutDeviceRect
, 3> mClipStack
;
398 bool mBackfaceVisible
;
400 wr::FontInstanceFlags mWRGlyphFlags
= {0};
402 // The rest of this is dummy implementations of DrawTarget's API
404 DrawTargetType
GetType() const override
{
405 return DrawTargetType::SOFTWARE_RASTER
;
408 BackendType
GetBackendType() const override
{
409 return BackendType::WEBRENDER_TEXT
;
412 bool IsRecording() const override
{ return true; }
414 already_AddRefed
<SourceSurface
> Snapshot() override
{
415 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
419 already_AddRefed
<SourceSurface
> IntoLuminanceSource(
420 LuminanceType aLuminanceType
, float aOpacity
) override
{
421 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
425 void Flush() override
{
426 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
429 void DrawSurface(SourceSurface
* aSurface
, const Rect
& aDest
,
430 const Rect
& aSource
, const DrawSurfaceOptions
& aSurfOptions
,
431 const DrawOptions
& aOptions
) override
{
432 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
435 void DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
436 const Point
& aDestPoint
,
437 const DrawOptions
& aOptions
) override
{
438 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
441 void DrawSurfaceWithShadow(SourceSurface
* aSurface
, const Point
& aDest
,
442 const ShadowOptions
& aShadow
,
443 CompositionOp aOperator
) override
{
444 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
447 void ClearRect(const Rect
& aRect
) override
{
448 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
451 void CopySurface(SourceSurface
* aSurface
, const IntRect
& aSourceRect
,
452 const IntPoint
& aDestination
) override
{
453 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
456 void FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
457 const DrawOptions
& aOptions
= DrawOptions()) override
{
458 MOZ_RELEASE_ASSERT(aPattern
.GetType() == PatternType::COLOR
);
460 if (!aRect
.Intersects(GeckoClipRect().ToUnknownRect())) {
463 auto rect
= wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect
));
465 wr::ToColorF(static_cast<const ColorPattern
&>(aPattern
).mColor
);
466 mBuilder
.PushRect(rect
, ClipRect(), mBackfaceVisible
, false, false, color
);
469 void StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
470 const StrokeOptions
& aStrokeOptions
,
471 const DrawOptions
& aOptions
) override
{
472 MOZ_RELEASE_ASSERT(aPattern
.GetType() == PatternType::COLOR
&&
473 aStrokeOptions
.mDashLength
== 0);
475 wr::LayoutSideOffsets widths
= {
476 aStrokeOptions
.mLineWidth
, aStrokeOptions
.mLineWidth
,
477 aStrokeOptions
.mLineWidth
, aStrokeOptions
.mLineWidth
};
479 wr::ToColorF(static_cast<const ColorPattern
&>(aPattern
).mColor
);
480 wr::BorderSide sides
[4] = {{color
, wr::BorderStyle::Solid
},
481 {color
, wr::BorderStyle::Solid
},
482 {color
, wr::BorderStyle::Solid
},
483 {color
, wr::BorderStyle::Solid
}};
484 wr::BorderRadius radius
= {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
485 LayoutDeviceRect rect
= LayoutDeviceRect::FromUnknownRect(aRect
);
486 rect
.Inflate(aStrokeOptions
.mLineWidth
/ 2);
487 if (!rect
.Intersects(GeckoClipRect())) {
490 wr::LayoutRect bounds
= wr::ToLayoutRect(rect
);
491 mBuilder
.PushBorder(bounds
, ClipRect(), true, widths
,
492 Range
<const wr::BorderSide
>(sides
, 4), radius
);
495 void StrokeLine(const Point
& aStart
, const Point
& aEnd
,
496 const Pattern
& aPattern
, const StrokeOptions
& aStrokeOptions
,
497 const DrawOptions
& aOptions
) override
{
498 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
501 void Stroke(const Path
* aPath
, const Pattern
& aPattern
,
502 const StrokeOptions
& aStrokeOptions
,
503 const DrawOptions
& aOptions
) override
{
504 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
507 void Fill(const Path
* aPath
, const Pattern
& aPattern
,
508 const DrawOptions
& aOptions
) override
{
509 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
512 void StrokeGlyphs(ScaledFont
* aFont
, const GlyphBuffer
& aBuffer
,
513 const Pattern
& aPattern
,
514 const StrokeOptions
& aStrokeOptions
,
515 const DrawOptions
& aOptions
) override
{
516 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
519 void Mask(const Pattern
& aSource
, const Pattern
& aMask
,
520 const DrawOptions
& aOptions
) override
{
521 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
524 void MaskSurface(const Pattern
& aSource
, SourceSurface
* aMask
, Point aOffset
,
525 const DrawOptions
& aOptions
) override
{
526 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
529 bool Draw3DTransformedSurface(SourceSurface
* aSurface
,
530 const Matrix4x4
& aMatrix
) override
{
531 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
534 void PushClip(const Path
* aPath
) override
{
535 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
538 void PushDeviceSpaceClipRects(const IntRect
* aRects
,
539 uint32_t aCount
) override
{
540 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
543 void PushLayer(bool aOpaque
, Float aOpacity
, SourceSurface
* aMask
,
544 const Matrix
& aMaskTransform
, const IntRect
& aBounds
,
545 bool aCopyBackground
) override
{
546 // Fine to pretend we do this
549 void PopLayer() override
{
550 // Fine to pretend we do this
553 already_AddRefed
<SourceSurface
> CreateSourceSurfaceFromData(
554 unsigned char* aData
, const IntSize
& aSize
, int32_t aStride
,
555 SurfaceFormat aFormat
) const override
{
556 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
560 already_AddRefed
<SourceSurface
> OptimizeSourceSurface(
561 SourceSurface
* aSurface
) const override
{
562 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
566 already_AddRefed
<SourceSurface
> CreateSourceSurfaceFromNativeSurface(
567 const NativeSurface
& aSurface
) const override
{
568 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
572 already_AddRefed
<DrawTarget
> CreateSimilarDrawTarget(
573 const IntSize
& aSize
, SurfaceFormat aFormat
) const override
{
574 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
578 bool CanCreateSimilarDrawTarget(const IntSize
& aSize
,
579 SurfaceFormat aFormat
) const override
{
580 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
584 virtual RefPtr
<DrawTarget
> CreateClippedDrawTarget(
585 const Rect
& aBounds
, SurfaceFormat aFormat
) override
{
586 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
590 already_AddRefed
<PathBuilder
> CreatePathBuilder(
591 FillRule aFillRule
) const override
{
592 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
596 already_AddRefed
<FilterNode
> CreateFilter(FilterType aType
) override
{
597 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
601 already_AddRefed
<GradientStops
> CreateGradientStops(
602 GradientStop
* aStops
, uint32_t aNumStops
,
603 ExtendMode aExtendMode
) const override
{
604 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
608 void DetachAllSnapshots() override
{
609 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
613 } // namespace layout
614 } // namespace mozilla