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(!aItem
->IsSubpixelAADisabled());
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
),
191 decltype(glyphs
[0].point
.x
)>() &&
192 std::is_same
<decltype(aBuffer
.mGlyphs
[0].mPosition
.y
),
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
, glyphs
, aFont
, color
, *mSc
,
215 mBoundsRect
, ClipRect(), mBackfaceVisible
,
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
, 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
, const uint8_t aStyle
) {
265 auto pos
= LayoutDevicePoint::FromUnknownPoint(aStart
);
266 LayoutDeviceSize size
;
269 pos
.x
-= aThickness
/ 2; // adjust from center to corner
270 size
= LayoutDeviceSize(aThickness
, aEnd
.y
- aStart
.y
);
272 pos
.y
-= aThickness
/ 2; // adjust from center to corner
273 size
= LayoutDeviceSize(aEnd
.x
- aStart
.x
, aThickness
);
277 decoration
.bounds
= wr::ToLayoutRect(LayoutDeviceRect(pos
, size
));
278 decoration
.wavyLineThickness
= 0; // dummy value, unused
279 decoration
.color
= wr::ToColorF(aColor
);
280 decoration
.orientation
= aVertical
? wr::LineOrientation::Vertical
281 : wr::LineOrientation::Horizontal
;
284 case NS_STYLE_TEXT_DECORATION_STYLE_SOLID
:
285 decoration
.style
= wr::LineStyle::Solid
;
287 case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED
:
288 decoration
.style
= wr::LineStyle::Dotted
;
290 case NS_STYLE_TEXT_DECORATION_STYLE_DASHED
:
291 decoration
.style
= wr::LineStyle::Dashed
;
293 // Wavy lines should go through AppendWavyDecoration
294 case NS_STYLE_TEXT_DECORATION_STYLE_WAVY
:
295 // Double lines should be lowered to two solid lines
296 case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE
:
298 MOZ_CRASH("TextDrawTarget received unsupported line style");
301 mBuilder
.PushLine(ClipRect(), mBackfaceVisible
, decoration
);
304 // Seperated out from AppendDecoration because Wavy Lines are completely
305 // different, and trying to merge the concept is more of a mess than it's
307 void AppendWavyDecoration(const Rect
& aBounds
, const float aThickness
,
308 const bool aVertical
, const DeviceColor
& aColor
) {
312 wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aBounds
));
313 decoration
.wavyLineThickness
= aThickness
;
314 decoration
.color
= wr::ToColorF(aColor
);
315 decoration
.orientation
= aVertical
? wr::LineOrientation::Vertical
316 : wr::LineOrientation::Horizontal
;
317 decoration
.style
= wr::LineStyle::Wavy
;
319 mBuilder
.PushLine(ClipRect(), mBackfaceVisible
, decoration
);
322 layers::WebRenderBridgeChild
* WrBridge() { return mManager
->WrBridge(); }
323 layers::WebRenderLayerManager
* WrLayerManager() {
324 return mManager
->LayerManager();
327 Maybe
<wr::ImageKey
> DefineImage(const IntSize
& aSize
, uint32_t aStride
,
328 SurfaceFormat aFormat
, const uint8_t* aData
) {
329 wr::ImageKey key
= mManager
->WrBridge()->GetNextImageKey();
330 wr::ImageDescriptor
desc(aSize
, aStride
, aFormat
);
331 Range
<uint8_t> bytes(const_cast<uint8_t*>(aData
), aStride
* aSize
.height
);
332 if (mResources
->AddImage(key
, desc
, bytes
)) {
338 void PushImage(wr::ImageKey aKey
, const Rect
& aBounds
, const Rect
& aClip
,
339 wr::ImageRendering aFilter
, const wr::ColorF
& aColor
) {
340 if (!aClip
.Intersects(GeckoClipRect().ToUnknownRect())) {
343 mBuilder
.PushImage(wr::ToLayoutRect(aBounds
), wr::ToLayoutRect(aClip
), true,
344 aFilter
, aKey
, true, aColor
);
348 wr::LayoutRect
ClipRect() {
349 return wr::ToLayoutRect(mClipStack
.LastElement());
351 LayoutDeviceRect
GeckoClipRect() { return mClipStack
.LastElement(); }
352 // Whether anything unsupported was encountered. This will result in this
353 // text being emitted as a blob, which means subpixel-AA can't be used and
354 // that performance will probably be a bit worse. At this point, we've
355 // properly implemented everything that shows up a lot, so you can assume
356 // that the remaining things we don't implement are fairly rare. The complete
357 // set of things that we don't implement are as follows:
359 // * Unserializable Fonts: WR lives across an IPC boundary
360 // * Text-Combine-Upright Squishing: no one's really bothered to impl it yet
361 // * Text-Stroke: not a real standard (exists for webcompat)
362 // * SVG Glyphs: not a real standard (we got overzealous with svg)
363 // * Color Glyphs (Emoji) With Transparency: requires us to apply transparency
364 // with a composited layer (a single emoji can be many single-color glyphs)
366 // The transparent colored-glyphs issue is probably the most valuable to fix,
367 // since ideally it would also result in us fixing transparency for all
368 // intersecting glyphs (which currently look bad with or without webrender,
369 // so there's no fallback like with emoji). Specifically, transparency
370 // looks bad for "cursive" fonts where glyphs overlap at the seams. Since
371 // this is more common for non-latin scripts (e.g. मनीष), this amounts to us
372 // treating non-latin scripts poorly... unless they're emoji. Yikes!
373 bool mHasUnsupportedFeatures
= false;
375 // The caller promises to call Save/Restore on the builder as needed.
376 bool mCallerDoesSaveRestore
= false;
378 bool mFinished
= false;
381 // Whether PopAllShadows needs to be called
382 bool mHasShadows
= false;
384 // Things used to push to webrender
385 wr::DisplayListBuilder
& mBuilder
;
386 wr::IpcResourceUpdateQueue
* mResources
;
387 const layers::StackingContextHelper
* mSc
;
388 layers::RenderRootStateManager
* mManager
;
392 wr::LayoutRect mBoundsRect
;
393 AutoTArray
<LayoutDeviceRect
, 3> mClipStack
;
394 bool mBackfaceVisible
;
396 wr::FontInstanceFlags mWRGlyphFlags
= {0};
398 // The rest of this is dummy implementations of DrawTarget's API
400 DrawTargetType
GetType() const override
{
401 return DrawTargetType::SOFTWARE_RASTER
;
404 BackendType
GetBackendType() const override
{
405 return BackendType::WEBRENDER_TEXT
;
408 bool IsRecording() const override
{ return true; }
409 bool IsCaptureDT() const override
{ return false; }
411 already_AddRefed
<SourceSurface
> Snapshot() override
{
412 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
416 already_AddRefed
<SourceSurface
> IntoLuminanceSource(
417 LuminanceType aLuminanceType
, float aOpacity
) override
{
418 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
422 void Flush() override
{
423 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
426 void DrawCapturedDT(DrawTargetCapture
* aCaptureDT
,
427 const Matrix
& aTransform
) override
{
428 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
431 void DrawSurface(SourceSurface
* aSurface
, const Rect
& aDest
,
432 const Rect
& aSource
, const DrawSurfaceOptions
& aSurfOptions
,
433 const DrawOptions
& aOptions
) override
{
434 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
437 void DrawFilter(FilterNode
* aNode
, const Rect
& aSourceRect
,
438 const Point
& aDestPoint
,
439 const DrawOptions
& aOptions
) override
{
440 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
443 void DrawSurfaceWithShadow(SourceSurface
* aSurface
, const Point
& aDest
,
444 const DeviceColor
& aColor
, const Point
& aOffset
,
445 Float aSigma
, CompositionOp aOperator
) override
{
446 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
449 void ClearRect(const Rect
& aRect
) override
{
450 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
453 void CopySurface(SourceSurface
* aSurface
, const IntRect
& aSourceRect
,
454 const IntPoint
& aDestination
) override
{
455 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
458 void FillRect(const Rect
& aRect
, const Pattern
& aPattern
,
459 const DrawOptions
& aOptions
= DrawOptions()) override
{
460 MOZ_RELEASE_ASSERT(aPattern
.GetType() == PatternType::COLOR
);
462 if (!aRect
.Intersects(GeckoClipRect().ToUnknownRect())) {
465 auto rect
= wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect
));
467 wr::ToColorF(static_cast<const ColorPattern
&>(aPattern
).mColor
);
468 mBuilder
.PushRect(rect
, ClipRect(), mBackfaceVisible
, color
);
471 void StrokeRect(const Rect
& aRect
, const Pattern
& aPattern
,
472 const StrokeOptions
& aStrokeOptions
,
473 const DrawOptions
& aOptions
) override
{
474 MOZ_RELEASE_ASSERT(aPattern
.GetType() == PatternType::COLOR
&&
475 aStrokeOptions
.mDashLength
== 0);
477 wr::LayoutSideOffsets widths
= {
478 aStrokeOptions
.mLineWidth
, aStrokeOptions
.mLineWidth
,
479 aStrokeOptions
.mLineWidth
, aStrokeOptions
.mLineWidth
};
481 wr::ToColorF(static_cast<const ColorPattern
&>(aPattern
).mColor
);
482 wr::BorderSide sides
[4] = {{color
, wr::BorderStyle::Solid
},
483 {color
, wr::BorderStyle::Solid
},
484 {color
, wr::BorderStyle::Solid
},
485 {color
, wr::BorderStyle::Solid
}};
486 wr::BorderRadius radius
= {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
487 LayoutDeviceRect rect
= LayoutDeviceRect::FromUnknownRect(aRect
);
488 rect
.Inflate(aStrokeOptions
.mLineWidth
/ 2);
489 if (!rect
.Intersects(GeckoClipRect())) {
492 wr::LayoutRect bounds
= wr::ToLayoutRect(rect
);
493 mBuilder
.PushBorder(bounds
, ClipRect(), true, widths
,
494 Range
<const wr::BorderSide
>(sides
, 4), radius
);
497 void StrokeLine(const Point
& aStart
, const Point
& aEnd
,
498 const Pattern
& aPattern
, const StrokeOptions
& aStrokeOptions
,
499 const DrawOptions
& aOptions
) override
{
500 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
503 void Stroke(const Path
* aPath
, const Pattern
& aPattern
,
504 const StrokeOptions
& aStrokeOptions
,
505 const DrawOptions
& aOptions
) override
{
506 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
509 void Fill(const Path
* aPath
, const Pattern
& aPattern
,
510 const DrawOptions
& aOptions
) override
{
511 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
514 void StrokeGlyphs(ScaledFont
* aFont
, const GlyphBuffer
& aBuffer
,
515 const Pattern
& aPattern
,
516 const StrokeOptions
& aStrokeOptions
,
517 const DrawOptions
& aOptions
) override
{
518 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
521 void Mask(const Pattern
& aSource
, const Pattern
& aMask
,
522 const DrawOptions
& aOptions
) override
{
523 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
526 void MaskSurface(const Pattern
& aSource
, SourceSurface
* aMask
, Point aOffset
,
527 const DrawOptions
& aOptions
) override
{
528 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
531 bool Draw3DTransformedSurface(SourceSurface
* aSurface
,
532 const Matrix4x4
& aMatrix
) override
{
533 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
536 void PushClip(const Path
* aPath
) override
{
537 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
540 void PushDeviceSpaceClipRects(const IntRect
* aRects
,
541 uint32_t aCount
) override
{
542 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
545 void PushLayer(bool aOpaque
, Float aOpacity
, SourceSurface
* aMask
,
546 const Matrix
& aMaskTransform
, const IntRect
& aBounds
,
547 bool aCopyBackground
) override
{
548 // Fine to pretend we do this
551 void PopLayer() override
{
552 // Fine to pretend we do this
555 already_AddRefed
<SourceSurface
> CreateSourceSurfaceFromData(
556 unsigned char* aData
, const IntSize
& aSize
, int32_t aStride
,
557 SurfaceFormat aFormat
) const override
{
558 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
562 already_AddRefed
<SourceSurface
> OptimizeSourceSurface(
563 SourceSurface
* aSurface
) const override
{
564 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
568 already_AddRefed
<SourceSurface
> CreateSourceSurfaceFromNativeSurface(
569 const NativeSurface
& aSurface
) const override
{
570 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
574 already_AddRefed
<DrawTarget
> CreateSimilarDrawTarget(
575 const IntSize
& aSize
, SurfaceFormat aFormat
) const override
{
576 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
580 bool CanCreateSimilarDrawTarget(const IntSize
& aSize
,
581 SurfaceFormat aFormat
) const override
{
582 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
586 virtual RefPtr
<DrawTarget
> CreateClippedDrawTarget(
587 const Rect
& aBounds
, SurfaceFormat aFormat
) override
{
588 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
592 already_AddRefed
<PathBuilder
> CreatePathBuilder(
593 FillRule aFillRule
) const override
{
594 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
598 already_AddRefed
<FilterNode
> CreateFilter(FilterType aType
) override
{
599 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
603 already_AddRefed
<GradientStops
> CreateGradientStops(
604 GradientStop
* aStops
, uint32_t aNumStops
,
605 ExtendMode aExtendMode
) const override
{
606 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
610 void DetachAllSnapshots() override
{
611 MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
615 } // namespace layout
616 } // namespace mozilla