Backed out changeset 1b14354719c0 (bug 1895254) for causing bustages on NavigationTra...
[gecko.git] / gfx / thebes / gfxDrawable.cpp
blobde0ea1948a88cdeaa9c0cc37f5381c6223f44972
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/. */
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"
16 using namespace mozilla;
17 using namespace mozilla::gfx;
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";
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;
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());
43 IntSize size = mSourceSurface->GetSize();
44 if (!IntRect(IntPoint(), size).Contains(intRect)) {
45 return false;
48 DrawInternal(aDrawTarget, aOp, aAntialiasMode, aFillRect, intRect,
49 ExtendMode::CLAMP, aSamplingFilter, aOpacity, gfxMatrix());
50 return true;
53 bool gfxSurfaceDrawable::Draw(gfxContext* aContext, const gfxRect& aFillRect,
54 ExtendMode aExtendMode,
55 const SamplingFilter aSamplingFilter,
56 gfxFloat aOpacity, const gfxMatrix& aTransform)
59 if (!mSourceSurface) {
60 return true;
63 DrawInternal(aContext->GetDrawTarget(), aContext->CurrentOp(),
64 aContext->CurrentAntialiasMode(), aFillRect, IntRect(),
65 aExtendMode, aSamplingFilter, aOpacity, aTransform);
66 return true;
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();
77 SurfacePattern pattern(mSourceSurface, aExtendMode, patternTransform,
78 aSamplingFilter, aSamplingRect);
80 Rect fillRect = ToRect(aFillRect);
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));
92 gfxCallbackDrawable::gfxCallbackDrawable(gfxDrawingCallback* aCallback,
93 const IntSize aSize)
94 : gfxDrawable(aSize), mCallback(aCallback) {}
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;
103 RefPtr<DrawTarget> dt =
104 aContext->GetDrawTarget()->CreateSimilarDrawTarget(mSize, format);
106 if (!dt || !dt->IsValid()) {
107 return nullptr;
110 gfxContext ctx(dt);
111 Draw(&ctx, gfxRect(0, 0, mSize.width, mSize.height), ExtendMode::CLAMP,
112 aSamplingFilter);
114 RefPtr<SourceSurface> surface = dt->Snapshot();
115 if (surface) {
116 RefPtr<gfxSurfaceDrawable> drawable =
117 new gfxSurfaceDrawable(surface, mSize);
118 return drawable.forget();
120 return nullptr;
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;
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);
144 if (mSurfaceDrawable)
145 return mSurfaceDrawable->Draw(aContext, aFillRect, aExtendMode,
146 aSamplingFilter, aOpacity, aTransform);
148 if (mCallback)
149 return (*mCallback)(aContext, aFillRect, aSamplingFilter, aTransform);
151 return false;
154 gfxPatternDrawable::gfxPatternDrawable(gfxPattern* aPattern,
155 const IntSize aSize)
156 : gfxDrawable(aSize), mPattern(aPattern) {}
158 gfxPatternDrawable::~gfxPatternDrawable() = default;
160 class DrawingCallbackFromDrawable : public gfxDrawingCallback {
161 public:
162 explicit DrawingCallbackFromDrawable(gfxDrawable* aDrawable)
163 : mDrawable(aDrawable) {
164 NS_ASSERTION(aDrawable, "aDrawable is null!");
167 virtual ~DrawingCallbackFromDrawable() = default;
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);
176 private:
177 RefPtr<gfxDrawable> mDrawable;
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();
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();
194 if (!mPattern) return false;
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);
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;