tor-browser

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

gfxDrawable.cpp (7897B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "gfxDrawable.h"
      7 #include "gfxContext.h"
      8 #include "gfxPlatform.h"
      9 #include "gfx2DGlue.h"
     10 #ifdef MOZ_X11
     11 #  include "cairo.h"
     12 #  include "gfxXlibSurface.h"
     13 #endif
     14 #include "mozilla/gfx/Logging.h"
     15 
     16 using namespace mozilla;
     17 using namespace mozilla::gfx;
     18 
     19 gfxSurfaceDrawable::gfxSurfaceDrawable(SourceSurface* aSurface,
     20                                       const IntSize aSize,
     21                                       const gfxMatrix aTransform)
     22    : gfxDrawable(aSize), mSourceSurface(aSurface), mTransform(aTransform) {
     23  if (!mSourceSurface) {
     24    gfxWarning() << "Creating gfxSurfaceDrawable with null SourceSurface";
     25  }
     26 }
     27 
     28 bool gfxSurfaceDrawable::DrawWithSamplingRect(
     29    DrawTarget* aDrawTarget, CompositionOp aOp, AntialiasMode aAntialiasMode,
     30    const gfxRect& aFillRect, const gfxRect& aSamplingRect,
     31    ExtendMode aExtendMode, const SamplingFilter aSamplingFilter,
     32    gfxFloat aOpacity) {
     33  if (!mSourceSurface) {
     34    return true;
     35  }
     36 
     37  // When drawing with CLAMP we can expand the sampling rect to the nearest
     38  // pixel without changing the result.
     39  IntRect intRect =
     40      IntRect::RoundOut(aSamplingRect.X(), aSamplingRect.Y(),
     41                        aSamplingRect.Width(), aSamplingRect.Height());
     42 
     43  IntSize size = mSourceSurface->GetSize();
     44  if (!IntRect(IntPoint(), size).Contains(intRect)) {
     45    return false;
     46  }
     47 
     48  DrawInternal(aDrawTarget, aOp, aAntialiasMode, aFillRect, intRect,
     49               ExtendMode::CLAMP, aSamplingFilter, aOpacity, gfxMatrix());
     50  return true;
     51 }
     52 
     53 bool gfxSurfaceDrawable::Draw(gfxContext* aContext, const gfxRect& aFillRect,
     54                              ExtendMode aExtendMode,
     55                              const SamplingFilter aSamplingFilter,
     56                              gfxFloat aOpacity, const gfxMatrix& aTransform)
     57 
     58 {
     59  if (!mSourceSurface) {
     60    return true;
     61  }
     62 
     63  DrawInternal(aContext->GetDrawTarget(), aContext->CurrentOp(),
     64               aContext->CurrentAntialiasMode(), aFillRect, IntRect(),
     65               aExtendMode, aSamplingFilter, aOpacity, aTransform);
     66  return true;
     67 }
     68 
     69 void gfxSurfaceDrawable::DrawInternal(
     70    DrawTarget* aDrawTarget, CompositionOp aOp, AntialiasMode aAntialiasMode,
     71    const gfxRect& aFillRect, const IntRect& aSamplingRect,
     72    ExtendMode aExtendMode, const SamplingFilter aSamplingFilter,
     73    gfxFloat aOpacity, const gfxMatrix& aTransform) {
     74  Matrix patternTransform = ToMatrix(aTransform * mTransform);
     75  patternTransform.Invert();
     76 
     77  SurfacePattern pattern(mSourceSurface, aExtendMode, patternTransform,
     78                         aSamplingFilter, aSamplingRect);
     79 
     80  Rect fillRect = ToRect(aFillRect);
     81 
     82  if (aOp == CompositionOp::OP_SOURCE && aOpacity == 1.0) {
     83    // Emulate cairo operator source which is bound by mask!
     84    aDrawTarget->ClearRect(fillRect);
     85    aDrawTarget->FillRect(fillRect, pattern);
     86  } else {
     87    aDrawTarget->FillRect(fillRect, pattern,
     88                          DrawOptions(aOpacity, aOp, aAntialiasMode));
     89  }
     90 }
     91 
     92 gfxCallbackDrawable::gfxCallbackDrawable(gfxDrawingCallback* aCallback,
     93                                         const IntSize aSize)
     94    : gfxDrawable(aSize), mCallback(aCallback) {}
     95 
     96 already_AddRefed<gfxSurfaceDrawable> gfxCallbackDrawable::MakeSurfaceDrawable(
     97    gfxContext* aContext, const SamplingFilter aSamplingFilter) {
     98  SurfaceFormat format = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(
     99      gfxContentType::COLOR_ALPHA);
    100  if (!aContext->GetDrawTarget()->CanCreateSimilarDrawTarget(mSize, format)) {
    101    return nullptr;
    102  }
    103  RefPtr<DrawTarget> dt =
    104      aContext->GetDrawTarget()->CreateSimilarDrawTarget(mSize, format);
    105 
    106  if (!dt || !dt->IsValid()) {
    107    return nullptr;
    108  }
    109 
    110  gfxContext ctx(dt);
    111  Draw(&ctx, gfxRect(0, 0, mSize.width, mSize.height), ExtendMode::CLAMP,
    112       aSamplingFilter);
    113 
    114  RefPtr<SourceSurface> surface = dt->Snapshot();
    115  if (surface) {
    116    RefPtr<gfxSurfaceDrawable> drawable =
    117        new gfxSurfaceDrawable(surface, mSize);
    118    return drawable.forget();
    119  }
    120  return nullptr;
    121 }
    122 
    123 static bool IsRepeatingExtendMode(ExtendMode aExtendMode) {
    124  switch (aExtendMode) {
    125    case ExtendMode::REPEAT:
    126    case ExtendMode::REPEAT_X:
    127    case ExtendMode::REPEAT_Y:
    128      return true;
    129    default:
    130      return false;
    131  }
    132 }
    133 
    134 bool gfxCallbackDrawable::Draw(gfxContext* aContext, const gfxRect& aFillRect,
    135                               ExtendMode aExtendMode,
    136                               const SamplingFilter aSamplingFilter,
    137                               gfxFloat aOpacity, const gfxMatrix& aTransform) {
    138  if ((IsRepeatingExtendMode(aExtendMode) || aOpacity != 1.0 ||
    139       aContext->CurrentOp() != CompositionOp::OP_OVER) &&
    140      !mSurfaceDrawable) {
    141    mSurfaceDrawable = MakeSurfaceDrawable(aContext, aSamplingFilter);
    142  }
    143 
    144  if (mSurfaceDrawable)
    145    return mSurfaceDrawable->Draw(aContext, aFillRect, aExtendMode,
    146                                  aSamplingFilter, aOpacity, aTransform);
    147 
    148  if (mCallback)
    149    return (*mCallback)(aContext, aFillRect, aSamplingFilter, aTransform);
    150 
    151  return false;
    152 }
    153 
    154 gfxPatternDrawable::gfxPatternDrawable(gfxPattern* aPattern,
    155                                       const IntSize aSize)
    156    : gfxDrawable(aSize), mPattern(aPattern) {}
    157 
    158 gfxPatternDrawable::~gfxPatternDrawable() = default;
    159 
    160 class DrawingCallbackFromDrawable : public gfxDrawingCallback {
    161 public:
    162  explicit DrawingCallbackFromDrawable(gfxDrawable* aDrawable)
    163      : mDrawable(aDrawable) {
    164    NS_ASSERTION(aDrawable, "aDrawable is null!");
    165  }
    166 
    167  virtual ~DrawingCallbackFromDrawable() = default;
    168 
    169  bool operator()(gfxContext* aContext, const gfxRect& aFillRect,
    170                  const SamplingFilter aSamplingFilter,
    171                  const gfxMatrix& aTransform = gfxMatrix()) override {
    172    return mDrawable->Draw(aContext, aFillRect, ExtendMode::CLAMP,
    173                           aSamplingFilter, 1.0, aTransform);
    174  }
    175 
    176 private:
    177  RefPtr<gfxDrawable> mDrawable;
    178 };
    179 
    180 already_AddRefed<gfxCallbackDrawable>
    181 gfxPatternDrawable::MakeCallbackDrawable() {
    182  RefPtr<gfxDrawingCallback> callback = new DrawingCallbackFromDrawable(this);
    183  RefPtr<gfxCallbackDrawable> callbackDrawable =
    184      new gfxCallbackDrawable(callback, mSize);
    185  return callbackDrawable.forget();
    186 }
    187 
    188 bool gfxPatternDrawable::Draw(gfxContext* aContext, const gfxRect& aFillRect,
    189                              ExtendMode aExtendMode,
    190                              const SamplingFilter aSamplingFilter,
    191                              gfxFloat aOpacity, const gfxMatrix& aTransform) {
    192  DrawTarget& aDrawTarget = *aContext->GetDrawTarget();
    193 
    194  if (!mPattern) return false;
    195 
    196  if (IsRepeatingExtendMode(aExtendMode)) {
    197    // We can't use mPattern directly: We want our repeated tiles to have
    198    // the size mSize, which might not be the case in mPattern.
    199    // So we need to draw mPattern into a surface of size mSize, create
    200    // a pattern from the surface and draw that pattern.
    201    // gfxCallbackDrawable and gfxSurfaceDrawable already know how to do
    202    // those things, so we use them here. Drawing mPattern into the surface
    203    // will happen through this Draw() method with aRepeat = false.
    204    RefPtr<gfxCallbackDrawable> callbackDrawable = MakeCallbackDrawable();
    205    return callbackDrawable->Draw(aContext, aFillRect, aExtendMode,
    206                                  aSamplingFilter, aOpacity, aTransform);
    207  }
    208 
    209  gfxMatrix oldMatrix = mPattern->GetMatrix();
    210  mPattern->SetMatrix(aTransform * oldMatrix);
    211  DrawOptions drawOptions(aOpacity);
    212  aDrawTarget.FillRect(ToRect(aFillRect), *mPattern->GetPattern(&aDrawTarget),
    213                       drawOptions);
    214  mPattern->SetMatrix(oldMatrix);
    215  return true;
    216 }