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/. */ 6 7 #ifndef TextDrawTarget_h 8 #define TextDrawTarget_h 9 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" 17 18 namespace mozilla { 19 namespace layout { 20 21 using namespace gfx; 22 23 // This class is a fake DrawTarget, used to intercept text draw calls, while 24 // also collecting up the other aspects of text natively. 25 // 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). 30 // 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. 35 // 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). 40 // 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. 45 // 46 // This is also likely to be a bit buggy (missing or misinterpreted info) 47 // while we further develop the design. 48 // 49 // TextDrawTarget doesn't yet support all features. See mHasUnsupportedFeatures 50 // for details. 51 class TextDrawTarget : public DrawTarget { 52 public: 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) mCallerDoesSaveRestore(aCallerDoesSaveRestore)59 : mCallerDoesSaveRestore(aCallerDoesSaveRestore), mBuilder(aBuilder) { 60 Reinitialize(aResources, aSc, aManager, aItem, aBounds); 61 } 62 63 // Prevent this from being copied 64 TextDrawTarget(const TextDrawTarget& src) = delete; 65 TextDrawTarget& operator=(const TextDrawTarget&) = delete; 66 ~TextDrawTarget()67 ~TextDrawTarget() { MOZ_ASSERT(mFinished); } 68 Reinitialize(wr::IpcResourceUpdateQueue & aResources,const layers::StackingContextHelper & aSc,layers::RenderRootStateManager * aManager,nsDisplayItem * aItem,nsRect & aBounds)69 void Reinitialize(wr::IpcResourceUpdateQueue& aResources, 70 const layers::StackingContextHelper& aSc, 71 layers::RenderRootStateManager* aManager, 72 nsDisplayItem* aItem, nsRect& aBounds) { 73 mResources = &aResources; 74 mSc = &aSc; 75 mManager = aManager; 76 mHasUnsupportedFeatures = false; 77 mHasShadows = false; 78 79 SetPermitSubpixelAA(!aItem->IsSubpixelAADisabled()); 80 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); 88 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); 95 96 mBackfaceVisible = !aItem->BackfaceIsHidden(); 97 98 if (!mCallerDoesSaveRestore) { 99 mBuilder.Save(); 100 } 101 } 102 FoundUnsupportedFeature()103 void FoundUnsupportedFeature() { mHasUnsupportedFeatures = true; } CheckHasUnsupportedFeatures()104 bool CheckHasUnsupportedFeatures() { 105 MOZ_ASSERT(mCallerDoesSaveRestore); 106 #ifdef DEBUG 107 MOZ_ASSERT(!mFinished); 108 mFinished = true; 109 #endif 110 return mHasUnsupportedFeatures; 111 } 112 Finish()113 bool Finish() { 114 MOZ_ASSERT(!mCallerDoesSaveRestore); 115 #ifdef DEBUG 116 mFinished = true; 117 #endif 118 if (mHasUnsupportedFeatures) { 119 mBuilder.Restore(); 120 return false; 121 } 122 mBuilder.ClearSave(); 123 return true; 124 } 125 GetWRGlyphFlags()126 wr::FontInstanceFlags GetWRGlyphFlags() const { return mWRGlyphFlags; } SetWRGlyphFlags(wr::FontInstanceFlags aFlags)127 void SetWRGlyphFlags(wr::FontInstanceFlags aFlags) { mWRGlyphFlags = aFlags; } 128 129 class AutoRestoreWRGlyphFlags { 130 public: ~AutoRestoreWRGlyphFlags()131 ~AutoRestoreWRGlyphFlags() { 132 if (mTarget) { 133 mTarget->SetWRGlyphFlags(mFlags); 134 } 135 } 136 Save(TextDrawTarget * aTarget)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. 142 if (!mTarget) { 143 // Only record the first save with the original flags that will be 144 // restored. 145 mTarget = aTarget; 146 mFlags = aTarget->GetWRGlyphFlags(); 147 } else { 148 // Ensure that this is actually a recursive save to the same target 149 MOZ_ASSERT( 150 mTarget == aTarget, 151 "Recursive save of WR glyph flags to different TextDrawTargets"); 152 } 153 } 154 155 private: 156 TextDrawTarget* mTarget = nullptr; 157 wr::FontInstanceFlags mFlags = {0}; 158 }; 159 160 // This overload just stores the glyphs/font/color. FillGlyphs(ScaledFont * aFont,const GlyphBuffer & aBuffer,const Pattern & aPattern,const DrawOptions & aOptions)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); 168 169 // Make sure the font exists, and can be serialized 170 MOZ_RELEASE_ASSERT(aFont); 171 if (!aFont->CanSerialize()) { 172 FoundUnsupportedFeature(); 173 return; 174 } 175 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), 181 aBuffer.mNumGlyphs); 182 // MSVC won't let us use offsetof on the following directly so we give it a 183 // name with typedef 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 187 static_assert( 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"); 208 209 wr::GlyphOptions glyphOptions; 210 glyphOptions.render_mode = 211 wr::ToFontRenderMode(aOptions.mAntialiasMode, GetPermitSubpixelAA()); 212 glyphOptions.flags = mWRGlyphFlags; 213 214 mManager->WrBridge()->PushGlyphs(mBuilder, glyphs, aFont, color, *mSc, 215 mBoundsRect, ClipRect(), mBackfaceVisible, 216 &glyphOptions); 217 } 218 PushClipRect(const Rect & aRect)219 void PushClipRect(const Rect& aRect) override { 220 LayoutDeviceRect rect = LayoutDeviceRect::FromUnknownRect(aRect); 221 rect = rect.Intersect(mClipStack.LastElement()); 222 mClipStack.AppendElement(rect); 223 } 224 PopClip()225 void PopClip() override { mClipStack.RemoveLastElement(); } 226 GetSize()227 IntSize GetSize() const override { return mSize; } 228 AppendShadow(const wr::Shadow & aShadow,bool aInflate)229 void AppendShadow(const wr::Shadow& aShadow, bool aInflate) { 230 mBuilder.PushShadow(mBoundsRect, ClipRect(), mBackfaceVisible, aShadow, 231 aInflate); 232 mHasShadows = true; 233 } 234 TerminateShadows()235 void TerminateShadows() { 236 if (mHasShadows) { 237 mBuilder.PopAllShadows(); 238 mHasShadows = false; 239 } 240 } 241 AppendSelectionRect(const LayoutDeviceRect & aRect,const DeviceColor & aColor)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); 247 } 248 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 255 // are on corners. 256 // 257 // So we mangle the format here in a single centralized place, where neither 258 // webrender nor nsCSSRendering has to care about this mismatch. 259 // 260 // NOTE: we assume the points are axis-aligned, and aStart should be used 261 // as the top-left corner of the rect. AppendDecoration(const Point & aStart,const Point & aEnd,const float aThickness,const bool aVertical,const DeviceColor & aColor,const uint8_t aStyle)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; 267 268 if (aVertical) { 269 pos.x -= aThickness / 2; // adjust from center to corner 270 size = LayoutDeviceSize(aThickness, aEnd.y - aStart.y); 271 } else { 272 pos.y -= aThickness / 2; // adjust from center to corner 273 size = LayoutDeviceSize(aEnd.x - aStart.x, aThickness); 274 } 275 276 wr::Line decoration; 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; 282 283 switch (aStyle) { 284 case NS_STYLE_TEXT_DECORATION_STYLE_SOLID: 285 decoration.style = wr::LineStyle::Solid; 286 break; 287 case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED: 288 decoration.style = wr::LineStyle::Dotted; 289 break; 290 case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: 291 decoration.style = wr::LineStyle::Dashed; 292 break; 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: 297 default: 298 MOZ_CRASH("TextDrawTarget received unsupported line style"); 299 } 300 301 mBuilder.PushLine(ClipRect(), mBackfaceVisible, decoration); 302 } 303 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 306 // worth. AppendWavyDecoration(const Rect & aBounds,const float aThickness,const bool aVertical,const DeviceColor & aColor)307 void AppendWavyDecoration(const Rect& aBounds, const float aThickness, 308 const bool aVertical, const DeviceColor& aColor) { 309 wr::Line decoration; 310 311 decoration.bounds = 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; 318 319 mBuilder.PushLine(ClipRect(), mBackfaceVisible, decoration); 320 } 321 WrBridge()322 layers::WebRenderBridgeChild* WrBridge() { return mManager->WrBridge(); } WrLayerManager()323 layers::WebRenderLayerManager* WrLayerManager() { 324 return mManager->LayerManager(); 325 } 326 DefineImage(const IntSize & aSize,uint32_t aStride,SurfaceFormat aFormat,const uint8_t * aData)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)) { 333 return Some(key); 334 } 335 return Nothing(); 336 } 337 PushImage(wr::ImageKey aKey,const Rect & aBounds,const Rect & aClip,wr::ImageRendering aFilter,const wr::ColorF & aColor)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())) { 341 return; 342 } 343 mBuilder.PushImage(wr::ToLayoutRect(aBounds), wr::ToLayoutRect(aClip), true, 344 aFilter, aKey, true, aColor); 345 } 346 347 private: ClipRect()348 wr::LayoutRect ClipRect() { 349 return wr::ToLayoutRect(mClipStack.LastElement()); 350 } GeckoClipRect()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: 358 // 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) 365 // 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; 374 375 // The caller promises to call Save/Restore on the builder as needed. 376 bool mCallerDoesSaveRestore = false; 377 #ifdef DEBUG 378 bool mFinished = false; 379 #endif 380 381 // Whether PopAllShadows needs to be called 382 bool mHasShadows = false; 383 384 // Things used to push to webrender 385 wr::DisplayListBuilder& mBuilder; 386 wr::IpcResourceUpdateQueue* mResources; 387 const layers::StackingContextHelper* mSc; 388 layers::RenderRootStateManager* mManager; 389 390 // Computed facts 391 IntSize mSize; 392 wr::LayoutRect mBoundsRect; 393 AutoTArray<LayoutDeviceRect, 3> mClipStack; 394 bool mBackfaceVisible; 395 396 wr::FontInstanceFlags mWRGlyphFlags = {0}; 397 398 // The rest of this is dummy implementations of DrawTarget's API 399 public: GetType()400 DrawTargetType GetType() const override { 401 return DrawTargetType::SOFTWARE_RASTER; 402 } 403 GetBackendType()404 BackendType GetBackendType() const override { 405 return BackendType::WEBRENDER_TEXT; 406 } 407 IsRecording()408 bool IsRecording() const override { return true; } IsCaptureDT()409 bool IsCaptureDT() const override { return false; } 410 Snapshot()411 already_AddRefed<SourceSurface> Snapshot() override { 412 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 413 return nullptr; 414 } 415 IntoLuminanceSource(LuminanceType aLuminanceType,float aOpacity)416 already_AddRefed<SourceSurface> IntoLuminanceSource( 417 LuminanceType aLuminanceType, float aOpacity) override { 418 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 419 return nullptr; 420 } 421 Flush()422 void Flush() override { 423 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 424 } 425 DrawCapturedDT(DrawTargetCapture * aCaptureDT,const Matrix & aTransform)426 void DrawCapturedDT(DrawTargetCapture* aCaptureDT, 427 const Matrix& aTransform) override { 428 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 429 } 430 DrawSurface(SourceSurface * aSurface,const Rect & aDest,const Rect & aSource,const DrawSurfaceOptions & aSurfOptions,const DrawOptions & aOptions)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"); 435 } 436 DrawFilter(FilterNode * aNode,const Rect & aSourceRect,const Point & aDestPoint,const DrawOptions & aOptions)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"); 441 } 442 DrawSurfaceWithShadow(SourceSurface * aSurface,const Point & aDest,const DeviceColor & aColor,const Point & aOffset,Float aSigma,CompositionOp aOperator)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"); 447 } 448 ClearRect(const Rect & aRect)449 void ClearRect(const Rect& aRect) override { 450 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 451 } 452 CopySurface(SourceSurface * aSurface,const IntRect & aSourceRect,const IntPoint & aDestination)453 void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect, 454 const IntPoint& aDestination) override { 455 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 456 } 457 458 void FillRect(const Rect& aRect, const Pattern& aPattern, 459 const DrawOptions& aOptions = DrawOptions()) override { 460 MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR); 461 462 if (!aRect.Intersects(GeckoClipRect().ToUnknownRect())) { 463 return; 464 } 465 auto rect = wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect)); 466 auto color = 467 wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor); 468 mBuilder.PushRect(rect, ClipRect(), mBackfaceVisible, color); 469 } 470 StrokeRect(const Rect & aRect,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aOptions)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); 476 477 wr::LayoutSideOffsets widths = { 478 aStrokeOptions.mLineWidth, aStrokeOptions.mLineWidth, 479 aStrokeOptions.mLineWidth, aStrokeOptions.mLineWidth}; 480 wr::ColorF color = 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())) { 490 return; 491 } 492 wr::LayoutRect bounds = wr::ToLayoutRect(rect); 493 mBuilder.PushBorder(bounds, ClipRect(), true, widths, 494 Range<const wr::BorderSide>(sides, 4), radius); 495 } 496 StrokeLine(const Point & aStart,const Point & aEnd,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aOptions)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"); 501 } 502 Stroke(const Path * aPath,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aOptions)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"); 507 } 508 Fill(const Path * aPath,const Pattern & aPattern,const DrawOptions & aOptions)509 void Fill(const Path* aPath, const Pattern& aPattern, 510 const DrawOptions& aOptions) override { 511 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 512 } 513 StrokeGlyphs(ScaledFont * aFont,const GlyphBuffer & aBuffer,const Pattern & aPattern,const StrokeOptions & aStrokeOptions,const DrawOptions & aOptions)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"); 519 } 520 Mask(const Pattern & aSource,const Pattern & aMask,const DrawOptions & aOptions)521 void Mask(const Pattern& aSource, const Pattern& aMask, 522 const DrawOptions& aOptions) override { 523 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 524 } 525 MaskSurface(const Pattern & aSource,SourceSurface * aMask,Point aOffset,const DrawOptions & aOptions)526 void MaskSurface(const Pattern& aSource, SourceSurface* aMask, Point aOffset, 527 const DrawOptions& aOptions) override { 528 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 529 } 530 Draw3DTransformedSurface(SourceSurface * aSurface,const Matrix4x4 & aMatrix)531 bool Draw3DTransformedSurface(SourceSurface* aSurface, 532 const Matrix4x4& aMatrix) override { 533 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 534 } 535 PushClip(const Path * aPath)536 void PushClip(const Path* aPath) override { 537 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 538 } 539 PushDeviceSpaceClipRects(const IntRect * aRects,uint32_t aCount)540 void PushDeviceSpaceClipRects(const IntRect* aRects, 541 uint32_t aCount) override { 542 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 543 } 544 PushLayer(bool aOpaque,Float aOpacity,SourceSurface * aMask,const Matrix & aMaskTransform,const IntRect & aBounds,bool aCopyBackground)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 549 } 550 PopLayer()551 void PopLayer() override { 552 // Fine to pretend we do this 553 } 554 CreateSourceSurfaceFromData(unsigned char * aData,const IntSize & aSize,int32_t aStride,SurfaceFormat aFormat)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"); 559 return nullptr; 560 } 561 OptimizeSourceSurface(SourceSurface * aSurface)562 already_AddRefed<SourceSurface> OptimizeSourceSurface( 563 SourceSurface* aSurface) const override { 564 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 565 return nullptr; 566 } 567 CreateSourceSurfaceFromNativeSurface(const NativeSurface & aSurface)568 already_AddRefed<SourceSurface> CreateSourceSurfaceFromNativeSurface( 569 const NativeSurface& aSurface) const override { 570 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 571 return nullptr; 572 } 573 CreateSimilarDrawTarget(const IntSize & aSize,SurfaceFormat aFormat)574 already_AddRefed<DrawTarget> CreateSimilarDrawTarget( 575 const IntSize& aSize, SurfaceFormat aFormat) const override { 576 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 577 return nullptr; 578 } 579 CanCreateSimilarDrawTarget(const IntSize & aSize,SurfaceFormat aFormat)580 bool CanCreateSimilarDrawTarget(const IntSize& aSize, 581 SurfaceFormat aFormat) const override { 582 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 583 return false; 584 } 585 CreateClippedDrawTarget(const Rect & aBounds,SurfaceFormat aFormat)586 virtual RefPtr<DrawTarget> CreateClippedDrawTarget( 587 const Rect& aBounds, SurfaceFormat aFormat) override { 588 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 589 return nullptr; 590 } 591 CreatePathBuilder(FillRule aFillRule)592 already_AddRefed<PathBuilder> CreatePathBuilder( 593 FillRule aFillRule) const override { 594 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 595 return nullptr; 596 } 597 CreateFilter(FilterType aType)598 already_AddRefed<FilterNode> CreateFilter(FilterType aType) override { 599 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 600 return nullptr; 601 } 602 CreateGradientStops(GradientStop * aStops,uint32_t aNumStops,ExtendMode aExtendMode)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"); 607 return nullptr; 608 } 609 DetachAllSnapshots()610 void DetachAllSnapshots() override { 611 MOZ_CRASH("TextDrawTarget: Method shouldn't be called"); 612 } 613 }; 614 615 } // namespace layout 616 } // namespace mozilla 617 618 #endif 619