gfx/thebes/gfxDrawable.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     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/. */
     6 #include "gfxDrawable.h"
     7 #include "gfxASurface.h"
     8 #include "gfxContext.h"
     9 #include "gfxImageSurface.h"
    10 #include "gfxPlatform.h"
    11 #include "gfxColor.h"
    12 #ifdef MOZ_X11
    13 #include "cairo.h"
    14 #include "gfxXlibSurface.h"
    15 #endif
    17 using namespace mozilla;
    18 using namespace mozilla::gfx;
    20 gfxSurfaceDrawable::gfxSurfaceDrawable(gfxASurface* aSurface,
    21                                        const gfxIntSize aSize,
    22                                        const gfxMatrix aTransform)
    23  : gfxDrawable(aSize)
    24  , mSurface(aSurface)
    25  , mTransform(aTransform)
    26 {
    27 }
    29 gfxSurfaceDrawable::gfxSurfaceDrawable(DrawTarget* aDrawTarget,
    30                                        const gfxIntSize aSize,
    31                                        const gfxMatrix aTransform)
    32  : gfxDrawable(aSize)
    33  , mDrawTarget(aDrawTarget)
    34  , mTransform(aTransform)
    35 {
    36 }
    38 gfxSurfaceDrawable::gfxSurfaceDrawable(SourceSurface* aSurface,
    39                                        const gfxIntSize aSize,
    40                                        const gfxMatrix aTransform)
    41  : gfxDrawable(aSize)
    42  , mSourceSurface(aSurface)
    43  , mTransform(aTransform)
    44 {
    45 }
    47 static gfxMatrix
    48 DeviceToImageTransform(gfxContext* aContext,
    49                        const gfxMatrix& aUserSpaceToImageSpace)
    50 {
    51     gfxFloat deviceX, deviceY;
    52     nsRefPtr<gfxASurface> currentTarget =
    53         aContext->CurrentSurface(&deviceX, &deviceY);
    54     gfxMatrix currentMatrix = aContext->CurrentMatrix();
    55     gfxMatrix deviceToUser = gfxMatrix(currentMatrix).Invert();
    56     deviceToUser.Translate(-gfxPoint(-deviceX, -deviceY));
    57     return gfxMatrix(deviceToUser).Multiply(aUserSpaceToImageSpace);
    58 }
    60 static void
    61 PreparePatternForUntiledDrawing(gfxPattern* aPattern,
    62                                 const gfxMatrix& aDeviceToImage,
    63                                 gfxASurface *currentTarget,
    64                                 const GraphicsFilter aDefaultFilter)
    65 {
    66     if (!currentTarget) {
    67         // This happens if we're dealing with an Azure target.
    68         aPattern->SetExtend(gfxPattern::EXTEND_PAD);
    69         aPattern->SetFilter(aDefaultFilter);
    70         return;
    71     }
    73     // In theory we can handle this using cairo's EXTEND_PAD,
    74     // but implementation limitations mean we have to consult
    75     // the surface type.
    76     switch (currentTarget->GetType()) {
    78 #ifdef MOZ_X11
    79         case gfxSurfaceType::Xlib:
    80         {
    81             // See bugs 324698, 422179, and 468496.  This is a workaround for
    82             // XRender's RepeatPad not being implemented correctly on old X
    83             // servers.
    84             //
    85             // In this situation, cairo avoids XRender and instead reads back
    86             // to perform EXTEND_PAD with pixman.  This is too slow so we
    87             // avoid EXTEND_PAD and set the filter to CAIRO_FILTER_FAST ---
    88             // otherwise, pixman's sampling will sample transparency for the
    89             // outside edges and we'll get blurry edges.
    90             //
    91             // But don't do this for simple downscales because it's horrible.
    92             // Downscaling means that device-space coordinates are
    93             // scaled *up* to find the image pixel coordinates.
    94             //
    95             // Cairo, and hence Gecko, can use RepeatPad on Xorg 1.7. We
    96             // enable EXTEND_PAD provided that we're running on a recent
    97             // enough X server.
    98             if (static_cast<gfxXlibSurface*>(currentTarget)->IsPadSlow()) {
    99                 bool isDownscale =
   100                     aDeviceToImage.xx >= 1.0 && aDeviceToImage.yy >= 1.0 &&
   101                     aDeviceToImage.xy == 0.0 && aDeviceToImage.yx == 0.0;
   103                 GraphicsFilter filter =
   104                     isDownscale ? aDefaultFilter : (const GraphicsFilter)GraphicsFilter::FILTER_FAST;
   105                 aPattern->SetFilter(filter);
   107                 // Use the default EXTEND_NONE
   108                 break;
   109             }
   110             // else fall through to EXTEND_PAD and the default filter.
   111         }
   112 #endif
   114         default:
   115             // turn on EXTEND_PAD.
   116             // This is what we really want for all surface types, if the
   117             // implementation was universally good.
   118             aPattern->SetExtend(gfxPattern::EXTEND_PAD);
   119             aPattern->SetFilter(aDefaultFilter);
   120             break;
   121     }
   122 }
   124 bool
   125 gfxSurfaceDrawable::Draw(gfxContext* aContext,
   126                          const gfxRect& aFillRect,
   127                          bool aRepeat,
   128                          const GraphicsFilter& aFilter,
   129                          const gfxMatrix& aTransform)
   130 {
   131     nsRefPtr<gfxPattern> pattern;
   132     if (mDrawTarget) {
   133       if (aContext->IsCairo()) {
   134         nsRefPtr<gfxASurface> source =
   135           gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
   136         pattern = new gfxPattern(source);
   137       } else {
   138         RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
   139         pattern = new gfxPattern(source, Matrix());
   140       }
   141     } else if (mSourceSurface) {
   142       pattern = new gfxPattern(mSourceSurface, Matrix());
   143     } else {
   144       pattern = new gfxPattern(mSurface);
   145     }
   146     if (aRepeat) {
   147         pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
   148         pattern->SetFilter(aFilter);
   149     } else {
   150         GraphicsFilter filter = aFilter;
   151         if (aContext->CurrentMatrix().HasOnlyIntegerTranslation() &&
   152             aTransform.HasOnlyIntegerTranslation())
   153         {
   154           // If we only have integer translation, no special filtering needs to
   155           // happen and we explicitly use FILTER_FAST. This is fast for some
   156           // backends.
   157           filter = GraphicsFilter::FILTER_FAST;
   158         }
   159         nsRefPtr<gfxASurface> currentTarget = aContext->CurrentSurface();
   160         gfxMatrix deviceSpaceToImageSpace =
   161             DeviceToImageTransform(aContext, aTransform);
   162         PreparePatternForUntiledDrawing(pattern, deviceSpaceToImageSpace,
   163                                         currentTarget, filter);
   164     }
   165     pattern->SetMatrix(gfxMatrix(aTransform).Multiply(mTransform));
   166     aContext->NewPath();
   167     aContext->SetPattern(pattern);
   168     aContext->Rectangle(aFillRect);
   169     aContext->Fill();
   170     // clear the pattern so that the snapshot is released before the
   171     // drawable is destroyed
   172     aContext->SetDeviceColor(gfxRGBA(0.0, 0.0, 0.0, 0.0));
   173     return true;
   174 }
   176 already_AddRefed<gfxImageSurface>
   177 gfxSurfaceDrawable::GetAsImageSurface()
   178 {
   179     if (mDrawTarget || mSourceSurface) {
   180       // TODO: Find a way to implement this. The caller really wants a 'sub-image' of
   181       // the original, without having to do a copy. GetDataSurface() might just copy,
   182       // which isn't useful.
   183       return nullptr;
   185     }
   186     return mSurface->GetAsImageSurface();
   187 }
   189 gfxCallbackDrawable::gfxCallbackDrawable(gfxDrawingCallback* aCallback,
   190                                          const gfxIntSize aSize)
   191  : gfxDrawable(aSize)
   192  , mCallback(aCallback)
   193 {
   194 }
   196 already_AddRefed<gfxSurfaceDrawable>
   197 gfxCallbackDrawable::MakeSurfaceDrawable(const GraphicsFilter aFilter)
   198 {
   199     SurfaceFormat format =
   200         gfxPlatform::GetPlatform()->Optimal2DFormatForContent(gfxContentType::COLOR_ALPHA);
   201     RefPtr<DrawTarget> dt =
   202         gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(mSize.ToIntSize(),
   203                                                                      format);
   204     if (!dt)
   205         return nullptr;
   207     nsRefPtr<gfxContext> ctx = new gfxContext(dt);
   208     Draw(ctx, gfxRect(0, 0, mSize.width, mSize.height), false, aFilter);
   210     RefPtr<SourceSurface> surface = dt->Snapshot();
   211     nsRefPtr<gfxSurfaceDrawable> drawable = new gfxSurfaceDrawable(surface, mSize);
   212     return drawable.forget();
   213 }
   215 bool
   216 gfxCallbackDrawable::Draw(gfxContext* aContext,
   217                           const gfxRect& aFillRect,
   218                           bool aRepeat,
   219                           const GraphicsFilter& aFilter,
   220                           const gfxMatrix& aTransform)
   221 {
   222     if (aRepeat && !mSurfaceDrawable) {
   223         mSurfaceDrawable = MakeSurfaceDrawable(aFilter);
   224     }
   226     if (mSurfaceDrawable)
   227         return mSurfaceDrawable->Draw(aContext, aFillRect, aRepeat, aFilter,
   228                                       aTransform);
   230     if (mCallback)
   231         return (*mCallback)(aContext, aFillRect, aFilter, aTransform);
   233     return false;
   234 }
   236 gfxPatternDrawable::gfxPatternDrawable(gfxPattern* aPattern,
   237                                        const gfxIntSize aSize)
   238  : gfxDrawable(aSize)
   239  , mPattern(aPattern)
   240 {
   241 }
   243 gfxPatternDrawable::~gfxPatternDrawable()
   244 {
   245 }
   247 class DrawingCallbackFromDrawable : public gfxDrawingCallback {
   248 public:
   249     DrawingCallbackFromDrawable(gfxDrawable* aDrawable)
   250      : mDrawable(aDrawable) {
   251         NS_ASSERTION(aDrawable, "aDrawable is null!");
   252     }
   254     virtual ~DrawingCallbackFromDrawable() {}
   256     virtual bool operator()(gfxContext* aContext,
   257                               const gfxRect& aFillRect,
   258                               const GraphicsFilter& aFilter,
   259                               const gfxMatrix& aTransform = gfxMatrix())
   260     {
   261         return mDrawable->Draw(aContext, aFillRect, false, aFilter,
   262                                aTransform);
   263     }
   264 private:
   265     nsRefPtr<gfxDrawable> mDrawable;
   266 };
   268 already_AddRefed<gfxCallbackDrawable>
   269 gfxPatternDrawable::MakeCallbackDrawable()
   270 {
   271     nsRefPtr<gfxDrawingCallback> callback =
   272         new DrawingCallbackFromDrawable(this);
   273     nsRefPtr<gfxCallbackDrawable> callbackDrawable =
   274         new gfxCallbackDrawable(callback, mSize);
   275     return callbackDrawable.forget();
   276 }
   278 bool
   279 gfxPatternDrawable::Draw(gfxContext* aContext,
   280                          const gfxRect& aFillRect,
   281                          bool aRepeat,
   282                          const GraphicsFilter& aFilter,
   283                          const gfxMatrix& aTransform)
   284 {
   285     if (!mPattern)
   286         return false;
   288     if (aRepeat) {
   289         // We can't use mPattern directly: We want our repeated tiles to have
   290         // the size mSize, which might not be the case in mPattern.
   291         // So we need to draw mPattern into a surface of size mSize, create
   292         // a pattern from the surface and draw that pattern.
   293         // gfxCallbackDrawable and gfxSurfaceDrawable already know how to do
   294         // those things, so we use them here. Drawing mPattern into the surface
   295         // will happen through this Draw() method with aRepeat = false.
   296         nsRefPtr<gfxCallbackDrawable> callbackDrawable = MakeCallbackDrawable();
   297         return callbackDrawable->Draw(aContext, aFillRect, true, aFilter,
   298                                       aTransform);
   299     }
   301     aContext->NewPath();
   302     gfxMatrix oldMatrix = mPattern->GetMatrix();
   303     mPattern->SetMatrix(gfxMatrix(aTransform).Multiply(oldMatrix));
   304     aContext->SetPattern(mPattern);
   305     aContext->Rectangle(aFillRect);
   306     aContext->Fill();
   307     mPattern->SetMatrix(oldMatrix);
   308     return true;
   309 }

mercurial