tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TextDrawTarget.h (24126B)


      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/IpcResourceUpdateQueue.h"
     12 #include "mozilla/layers/RenderRootStateManager.h"
     13 #include "mozilla/layers/StackingContextHelper.h"
     14 #include "mozilla/layers/WebRenderBridgeChild.h"
     15 #include "mozilla/layers/WebRenderLayerManager.h"
     16 #include "mozilla/webrender/WebRenderAPI.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)
     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 
     67  ~TextDrawTarget() { MOZ_ASSERT(mFinished); }
     68 
     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(true);
     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 
    103  void FoundUnsupportedFeature() { mHasUnsupportedFeatures = true; }
    104  bool CheckHasUnsupportedFeatures() {
    105    MOZ_ASSERT(mCallerDoesSaveRestore);
    106 #ifdef DEBUG
    107    MOZ_ASSERT(!mFinished);
    108    mFinished = true;
    109 #endif
    110    return mHasUnsupportedFeatures;
    111  }
    112 
    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 
    126  wr::FontInstanceFlags GetWRGlyphFlags() const { return mWRGlyphFlags; }
    127  void SetWRGlyphFlags(wr::FontInstanceFlags aFlags) { mWRGlyphFlags = aFlags; }
    128 
    129  class AutoRestoreWRGlyphFlags {
    130   public:
    131    ~AutoRestoreWRGlyphFlags() {
    132      if (mTarget) {
    133        mTarget->SetWRGlyphFlags(mFlags);
    134      }
    135    }
    136 
    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.
    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.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");
    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, *mResources, glyphs, aFont,
    215                                     color, *mSc, mBoundsRect, ClipRect(),
    216                                     mBackfaceVisible, &glyphOptions);
    217  }
    218 
    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 
    225  void PopClip() override { mClipStack.RemoveLastElement(); }
    226 
    227  IntSize GetSize() const override { return mSize; }
    228 
    229  void AppendShadow(const wr::Shadow& aShadow, bool aInflate) {
    230    mBuilder.PushShadow(mBoundsRect, ClipRect(), mBackfaceVisible, aShadow,
    231                        aInflate);
    232    mHasShadows = true;
    233  }
    234 
    235  void TerminateShadows() {
    236    if (mHasShadows) {
    237      mBuilder.PopAllShadows();
    238      mHasShadows = false;
    239    }
    240  }
    241 
    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);
    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.
    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;
    268 
    269    if (aVertical) {
    270      pos.x -= aThickness / 2;  // adjust from center to corner
    271      size = LayoutDeviceSize(aThickness,
    272                              ViewAs<LayoutDevicePixel>(aEnd.y - aStart.y));
    273    } else {
    274      pos.y -= aThickness / 2;  // adjust from center to corner
    275      size = LayoutDeviceSize(ViewAs<LayoutDevicePixel>(aEnd.x - aStart.x),
    276                              aThickness);
    277    }
    278 
    279    wr::Line decoration;
    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;
    285 
    286    switch (aStyle) {
    287      case StyleTextDecorationStyle::Solid:
    288        decoration.style = wr::LineStyle::Solid;
    289        break;
    290      case StyleTextDecorationStyle::Dotted:
    291        decoration.style = wr::LineStyle::Dotted;
    292        break;
    293      case StyleTextDecorationStyle::Dashed:
    294        decoration.style = wr::LineStyle::Dashed;
    295        break;
    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:
    300      default:
    301        MOZ_CRASH("TextDrawTarget received unsupported line style");
    302    }
    303 
    304    mBuilder.PushLine(ClipRect(), mBackfaceVisible, decoration);
    305  }
    306 
    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
    309  // worth.
    310  void AppendWavyDecoration(const Rect& aBounds, const float aThickness,
    311                            const bool aVertical, const DeviceColor& aColor) {
    312    wr::Line decoration;
    313 
    314    decoration.bounds =
    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;
    321 
    322    mBuilder.PushLine(ClipRect(), mBackfaceVisible, decoration);
    323  }
    324 
    325  layers::WebRenderBridgeChild* WrBridge() { return mManager->WrBridge(); }
    326  layers::WebRenderLayerManager* WrLayerManager() {
    327    return mManager->LayerManager();
    328  }
    329 
    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)) {
    336      return Some(key);
    337    }
    338    return Nothing();
    339  }
    340 
    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())) {
    344      return;
    345    }
    346    mBuilder.PushImage(wr::ToLayoutRect(aBounds), wr::ToLayoutRect(aClip), true,
    347                       false, aFilter, aKey, true, aColor);
    348  }
    349 
    350  LayoutDeviceRect GeckoClipRect() { return mClipStack.LastElement(); }
    351 
    352 private:
    353  wr::LayoutRect ClipRect() {
    354    return wr::ToLayoutRect(mClipStack.LastElement());
    355  }
    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:
    362  //
    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)
    369  //
    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;
    378 
    379  // The caller promises to call Save/Restore on the builder as needed.
    380  bool mCallerDoesSaveRestore = false;
    381 #ifdef DEBUG
    382  bool mFinished = false;
    383 #endif
    384 
    385  // Whether PopAllShadows needs to be called
    386  bool mHasShadows = false;
    387 
    388  // Things used to push to webrender
    389  wr::DisplayListBuilder& mBuilder;
    390  wr::IpcResourceUpdateQueue* mResources;
    391  const layers::StackingContextHelper* mSc;
    392  layers::RenderRootStateManager* mManager;
    393 
    394  // Computed facts
    395  IntSize mSize;
    396  wr::LayoutRect mBoundsRect;
    397  AutoTArray<LayoutDeviceRect, 3> mClipStack;
    398  bool mBackfaceVisible;
    399 
    400  wr::FontInstanceFlags mWRGlyphFlags = {0};
    401 
    402  // The rest of this is dummy implementations of DrawTarget's API
    403 public:
    404  DrawTargetType GetType() const override {
    405    return DrawTargetType::SOFTWARE_RASTER;
    406  }
    407 
    408  BackendType GetBackendType() const override {
    409    return BackendType::WEBRENDER_TEXT;
    410  }
    411 
    412  bool IsRecording() const override { return true; }
    413 
    414  already_AddRefed<SourceSurface> Snapshot() override {
    415    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    416    return nullptr;
    417  }
    418 
    419  already_AddRefed<SourceSurface> IntoLuminanceSource(
    420      LuminanceType aLuminanceType, float aOpacity) override {
    421    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    422    return nullptr;
    423  }
    424 
    425  void Flush() override {
    426    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    427  }
    428 
    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");
    433  }
    434 
    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");
    439  }
    440 
    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");
    445  }
    446 
    447  void ClearRect(const Rect& aRect) override {
    448    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    449  }
    450 
    451  void CopySurface(SourceSurface* aSurface, const IntRect& aSourceRect,
    452                   const IntPoint& aDestination) override {
    453    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    454  }
    455 
    456  void FillRect(const Rect& aRect, const Pattern& aPattern,
    457                const DrawOptions& aOptions = DrawOptions()) override {
    458    MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR);
    459 
    460    if (!aRect.Intersects(GeckoClipRect().ToUnknownRect())) {
    461      return;
    462    }
    463    auto rect = wr::ToLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect));
    464    auto color =
    465        wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor);
    466    mBuilder.PushRect(rect, ClipRect(), mBackfaceVisible, false, false, color);
    467  }
    468 
    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);
    474 
    475    wr::LayoutSideOffsets widths = {
    476        aStrokeOptions.mLineWidth, aStrokeOptions.mLineWidth,
    477        aStrokeOptions.mLineWidth, aStrokeOptions.mLineWidth};
    478    wr::ColorF color =
    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())) {
    488      return;
    489    }
    490    wr::LayoutRect bounds = wr::ToLayoutRect(rect);
    491    mBuilder.PushBorder(bounds, ClipRect(), true, widths,
    492                        Range<const wr::BorderSide>(sides, 4), radius);
    493  }
    494 
    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");
    499  }
    500 
    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");
    505  }
    506 
    507  void Fill(const Path* aPath, const Pattern& aPattern,
    508            const DrawOptions& aOptions) override {
    509    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    510  }
    511 
    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");
    517  }
    518 
    519  void Mask(const Pattern& aSource, const Pattern& aMask,
    520            const DrawOptions& aOptions) override {
    521    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    522  }
    523 
    524  void MaskSurface(const Pattern& aSource, SourceSurface* aMask, Point aOffset,
    525                   const DrawOptions& aOptions) override {
    526    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    527  }
    528 
    529  bool Draw3DTransformedSurface(SourceSurface* aSurface,
    530                                const Matrix4x4& aMatrix) override {
    531    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    532  }
    533 
    534  void PushClip(const Path* aPath) override {
    535    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    536  }
    537 
    538  void PushDeviceSpaceClipRects(const IntRect* aRects,
    539                                uint32_t aCount) override {
    540    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    541  }
    542 
    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
    547  }
    548 
    549  void PopLayer() override {
    550    // Fine to pretend we do this
    551  }
    552 
    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");
    557    return nullptr;
    558  }
    559 
    560  already_AddRefed<SourceSurface> OptimizeSourceSurface(
    561      SourceSurface* aSurface) const override {
    562    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    563    return nullptr;
    564  }
    565 
    566  already_AddRefed<SourceSurface> CreateSourceSurfaceFromNativeSurface(
    567      const NativeSurface& aSurface) const override {
    568    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    569    return nullptr;
    570  }
    571 
    572  already_AddRefed<DrawTarget> CreateSimilarDrawTarget(
    573      const IntSize& aSize, SurfaceFormat aFormat) const override {
    574    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    575    return nullptr;
    576  }
    577 
    578  bool CanCreateSimilarDrawTarget(const IntSize& aSize,
    579                                  SurfaceFormat aFormat) const override {
    580    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    581    return false;
    582  }
    583 
    584  virtual RefPtr<DrawTarget> CreateClippedDrawTarget(
    585      const Rect& aBounds, SurfaceFormat aFormat) override {
    586    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    587    return nullptr;
    588  }
    589 
    590  already_AddRefed<PathBuilder> CreatePathBuilder(
    591      FillRule aFillRule) const override {
    592    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    593    return nullptr;
    594  }
    595 
    596  already_AddRefed<FilterNode> CreateFilter(FilterType aType) override {
    597    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    598    return nullptr;
    599  }
    600 
    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");
    605    return nullptr;
    606  }
    607 
    608  void DetachAllSnapshots() override {
    609    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
    610  }
    611 };
    612 
    613 }  // namespace layout
    614 }  // namespace mozilla
    615 
    616 #endif