summaryrefslogtreecommitdiffstats
path: root/gfx/2d/DrawTargetOffset.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/DrawTargetOffset.cpp')
-rw-r--r--gfx/2d/DrawTargetOffset.cpp226
1 files changed, 226 insertions, 0 deletions
diff --git a/gfx/2d/DrawTargetOffset.cpp b/gfx/2d/DrawTargetOffset.cpp
new file mode 100644
index 0000000000..cc49cf0493
--- /dev/null
+++ b/gfx/2d/DrawTargetOffset.cpp
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DrawTargetOffset.h"
+#include "Logging.h"
+#include "PathHelpers.h"
+
+namespace mozilla {
+namespace gfx {
+
+DrawTargetOffset::DrawTargetOffset() = default;
+
+bool DrawTargetOffset::Init(DrawTarget* aDrawTarget, IntPoint aOrigin) {
+ mDrawTarget = aDrawTarget;
+ mOrigin = aOrigin;
+ mDrawTarget->SetTransform(Matrix::Translation(-mOrigin.x, -mOrigin.y));
+ mFormat = mDrawTarget->GetFormat();
+ SetPermitSubpixelAA(IsOpaque(mFormat));
+ return true;
+}
+
+already_AddRefed<SourceSurface> DrawTargetOffset::Snapshot() {
+ RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot();
+
+ if (!snapshot) {
+ return nullptr;
+ }
+
+ return MakeAndAddRef<SourceSurfaceOffset>(snapshot, mOrigin);
+}
+
+void DrawTargetOffset::DetachAllSnapshots() {}
+
+// Skip the mClippedOut check since this is only used for Flush() which
+// should happen even if we're clipped.
+#define OFFSET_COMMAND(command) \
+ void DrawTargetOffset::command() { mDrawTarget->command(); }
+#define OFFSET_COMMAND1(command, type1) \
+ void DrawTargetOffset::command(type1 arg1) { mDrawTarget->command(arg1); }
+#define OFFSET_COMMAND3(command, type1, type2, type3) \
+ void DrawTargetOffset::command(type1 arg1, type2 arg2, type3 arg3) { \
+ mDrawTarget->command(arg1, arg2, arg3); \
+ }
+#define OFFSET_COMMAND4(command, type1, type2, type3, type4) \
+ void DrawTargetOffset::command(type1 arg1, type2 arg2, type3 arg3, \
+ type4 arg4) { \
+ mDrawTarget->command(arg1, arg2, arg3, arg4); \
+ }
+#define OFFSET_COMMAND5(command, type1, type2, type3, type4, type5) \
+ void DrawTargetOffset::command(type1 arg1, type2 arg2, type3 arg3, \
+ type4 arg4, type5 arg5) { \
+ mDrawTarget->command(arg1, arg2, arg3, arg4, arg5); \
+ }
+
+OFFSET_COMMAND(Flush)
+OFFSET_COMMAND1(ClearRect, const Rect&)
+OFFSET_COMMAND4(MaskSurface, const Pattern&, SourceSurface*, Point,
+ const DrawOptions&)
+OFFSET_COMMAND4(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&,
+ const DrawOptions&)
+OFFSET_COMMAND5(StrokeGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&,
+ const StrokeOptions&, const DrawOptions&)
+OFFSET_COMMAND3(FillRoundedRect, const RoundedRect&, const Pattern&,
+ const DrawOptions&)
+
+bool DrawTargetOffset::Draw3DTransformedSurface(SourceSurface* aSrc,
+ const Matrix4x4& aMatrix) {
+ return mDrawTarget->Draw3DTransformedSurface(aSrc, aMatrix);
+}
+
+OFFSET_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&)
+
+void DrawTargetOffset::DrawFilter(FilterNode* aNode, const Rect& aSourceRect,
+ const Point& aDestPoint,
+ const DrawOptions& aOptions) {
+ auto clone = mTransform;
+ bool invertible = clone.Invert();
+ // aSourceRect is in filter space. The filter outputs from aSourceRect need
+ // to be drawn at aDestPoint in user space.
+ Rect userSpaceSource = Rect(aDestPoint, aSourceRect.Size());
+ if (invertible) {
+ // Try to reduce the source rect so that it's not much bigger
+ // than the draw target. The result is not minimal. Examples
+ // are left as an exercise for the reader.
+ auto destRect = Rect(mDrawTarget->GetRect() + mOrigin);
+ Rect userSpaceBounds = clone.TransformBounds(destRect);
+ userSpaceSource = userSpaceSource.Intersect(userSpaceBounds);
+ }
+
+ // Compute how much we moved the top-left of the source rect by, and use that
+ // to compute the new dest point, and move our intersected source rect back
+ // into the (new) filter space.
+ Point shift = userSpaceSource.TopLeft() - aDestPoint;
+ Rect filterSpaceSource =
+ Rect(aSourceRect.TopLeft() + shift, userSpaceSource.Size());
+ mDrawTarget->DrawFilter(aNode, filterSpaceSource, aDestPoint + shift,
+ aOptions);
+}
+
+void DrawTargetOffset::PushClip(const Path* aPath) {
+ mDrawTarget->PushClip(aPath);
+}
+
+void DrawTargetOffset::PushClipRect(const Rect& aRect) {
+ mDrawTarget->PushClipRect(aRect);
+}
+
+void DrawTargetOffset::PopClip() { mDrawTarget->PopClip(); }
+
+void DrawTargetOffset::CopySurface(SourceSurface* aSurface,
+ const IntRect& aSourceRect,
+ const IntPoint& aDestination) {
+ IntPoint tileOrigin = mOrigin;
+ // CopySurface ignores the transform, account for that here.
+ mDrawTarget->CopySurface(aSurface, aSourceRect, aDestination - tileOrigin);
+}
+
+void DrawTargetOffset::SetTransform(const Matrix& aTransform) {
+ Matrix mat = aTransform;
+ mat.PostTranslate(Float(-mOrigin.x), Float(-mOrigin.y));
+ mDrawTarget->SetTransform(mat);
+
+ DrawTarget::SetTransform(aTransform);
+}
+
+void DrawTargetOffset::SetPermitSubpixelAA(bool aPermitSubpixelAA) {
+ mDrawTarget->SetPermitSubpixelAA(aPermitSubpixelAA);
+}
+
+void DrawTargetOffset::DrawSurface(SourceSurface* aSurface, const Rect& aDest,
+ const Rect& aSource,
+ const DrawSurfaceOptions& aSurfaceOptions,
+ const DrawOptions& aDrawOptions) {
+ mDrawTarget->DrawSurface(aSurface, aDest, aSource, aSurfaceOptions,
+ aDrawOptions);
+}
+
+void DrawTargetOffset::FillRect(const Rect& aRect, const Pattern& aPattern,
+ const DrawOptions& aDrawOptions) {
+ mDrawTarget->FillRect(aRect, aPattern, aDrawOptions);
+}
+
+void DrawTargetOffset::Stroke(const Path* aPath, const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aDrawOptions) {
+ mDrawTarget->Stroke(aPath, aPattern, aStrokeOptions, aDrawOptions);
+}
+
+void DrawTargetOffset::StrokeRect(const Rect& aRect, const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aDrawOptions) {
+ mDrawTarget->StrokeRect(aRect, aPattern, aStrokeOptions, aDrawOptions);
+}
+
+void DrawTargetOffset::StrokeLine(const Point& aStart, const Point& aEnd,
+ const Pattern& aPattern,
+ const StrokeOptions& aStrokeOptions,
+ const DrawOptions& aDrawOptions) {
+ mDrawTarget->StrokeLine(aStart, aEnd, aPattern, aStrokeOptions, aDrawOptions);
+}
+
+void DrawTargetOffset::Fill(const Path* aPath, const Pattern& aPattern,
+ const DrawOptions& aDrawOptions) {
+ mDrawTarget->Fill(aPath, aPattern, aDrawOptions);
+}
+
+void DrawTargetOffset::PushLayer(bool aOpaque, Float aOpacity,
+ SourceSurface* aMask,
+ const Matrix& aMaskTransform,
+ const IntRect& aBounds, bool aCopyBackground) {
+ IntRect bounds = aBounds - mOrigin;
+
+ mDrawTarget->PushLayer(aOpaque, aOpacity, aMask, aMaskTransform, bounds,
+ aCopyBackground);
+ SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
+}
+
+already_AddRefed<SourceSurface> DrawTargetOffset::IntoLuminanceSource(
+ LuminanceType aLuminanceType, float aOpacity) {
+ RefPtr<SourceSurface> surface =
+ mDrawTarget->IntoLuminanceSource(aLuminanceType, aOpacity);
+
+ if (!surface) {
+ return nullptr;
+ }
+
+ return MakeAndAddRef<SourceSurfaceOffset>(surface, mOrigin);
+}
+
+void DrawTargetOffset::PushLayerWithBlend(bool aOpaque, Float aOpacity,
+ SourceSurface* aMask,
+ const Matrix& aMaskTransform,
+ const IntRect& aBounds,
+ bool aCopyBackground,
+ CompositionOp aOp) {
+ IntRect bounds = aBounds - mOrigin;
+
+ mDrawTarget->PushLayerWithBlend(aOpaque, aOpacity, aMask, aMaskTransform,
+ bounds, aCopyBackground, aOp);
+ SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
+}
+
+void DrawTargetOffset::PopLayer() {
+ mDrawTarget->PopLayer();
+ SetPermitSubpixelAA(mDrawTarget->GetPermitSubpixelAA());
+}
+
+RefPtr<DrawTarget> DrawTargetOffset::CreateClippedDrawTarget(
+ const Rect& aBounds, SurfaceFormat aFormat) {
+ RefPtr<DrawTarget> result;
+ RefPtr<DrawTarget> dt =
+ mDrawTarget->CreateClippedDrawTarget(aBounds, aFormat);
+ if (dt) {
+ result = gfx::Factory::CreateOffsetDrawTarget(dt, mOrigin);
+ if (result) {
+ result->SetTransform(mTransform);
+ }
+ }
+ return result;
+}
+
+} // namespace gfx
+} // namespace mozilla