summaryrefslogtreecommitdiffstats
path: root/gfx/2d/HelpersCairo.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/2d/HelpersCairo.h')
-rw-r--r--gfx/2d/HelpersCairo.h333
1 files changed, 333 insertions, 0 deletions
diff --git a/gfx/2d/HelpersCairo.h b/gfx/2d/HelpersCairo.h
new file mode 100644
index 0000000000..e3c707944b
--- /dev/null
+++ b/gfx/2d/HelpersCairo.h
@@ -0,0 +1,333 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_HELPERSCAIRO_H_
+#define MOZILLA_GFX_HELPERSCAIRO_H_
+
+#include "2D.h"
+#include "cairo.h"
+#include "Logging.h"
+
+namespace mozilla {
+namespace gfx {
+
+static inline cairo_operator_t GfxOpToCairoOp(CompositionOp op) {
+ switch (op) {
+ case CompositionOp::OP_CLEAR:
+ return CAIRO_OPERATOR_CLEAR;
+ case CompositionOp::OP_OVER:
+ return CAIRO_OPERATOR_OVER;
+ case CompositionOp::OP_ADD:
+ return CAIRO_OPERATOR_ADD;
+ case CompositionOp::OP_ATOP:
+ return CAIRO_OPERATOR_ATOP;
+ case CompositionOp::OP_OUT:
+ return CAIRO_OPERATOR_OUT;
+ case CompositionOp::OP_IN:
+ return CAIRO_OPERATOR_IN;
+ case CompositionOp::OP_SOURCE:
+ return CAIRO_OPERATOR_SOURCE;
+ case CompositionOp::OP_DEST_IN:
+ return CAIRO_OPERATOR_DEST_IN;
+ case CompositionOp::OP_DEST_OUT:
+ return CAIRO_OPERATOR_DEST_OUT;
+ case CompositionOp::OP_DEST_OVER:
+ return CAIRO_OPERATOR_DEST_OVER;
+ case CompositionOp::OP_DEST_ATOP:
+ return CAIRO_OPERATOR_DEST_ATOP;
+ case CompositionOp::OP_XOR:
+ return CAIRO_OPERATOR_XOR;
+ case CompositionOp::OP_MULTIPLY:
+ return CAIRO_OPERATOR_MULTIPLY;
+ case CompositionOp::OP_SCREEN:
+ return CAIRO_OPERATOR_SCREEN;
+ case CompositionOp::OP_OVERLAY:
+ return CAIRO_OPERATOR_OVERLAY;
+ case CompositionOp::OP_DARKEN:
+ return CAIRO_OPERATOR_DARKEN;
+ case CompositionOp::OP_LIGHTEN:
+ return CAIRO_OPERATOR_LIGHTEN;
+ case CompositionOp::OP_COLOR_DODGE:
+ return CAIRO_OPERATOR_COLOR_DODGE;
+ case CompositionOp::OP_COLOR_BURN:
+ return CAIRO_OPERATOR_COLOR_BURN;
+ case CompositionOp::OP_HARD_LIGHT:
+ return CAIRO_OPERATOR_HARD_LIGHT;
+ case CompositionOp::OP_SOFT_LIGHT:
+ return CAIRO_OPERATOR_SOFT_LIGHT;
+ case CompositionOp::OP_DIFFERENCE:
+ return CAIRO_OPERATOR_DIFFERENCE;
+ case CompositionOp::OP_EXCLUSION:
+ return CAIRO_OPERATOR_EXCLUSION;
+ case CompositionOp::OP_HUE:
+ return CAIRO_OPERATOR_HSL_HUE;
+ case CompositionOp::OP_SATURATION:
+ return CAIRO_OPERATOR_HSL_SATURATION;
+ case CompositionOp::OP_COLOR:
+ return CAIRO_OPERATOR_HSL_COLOR;
+ case CompositionOp::OP_LUMINOSITY:
+ return CAIRO_OPERATOR_HSL_LUMINOSITY;
+ case CompositionOp::OP_COUNT:
+ break;
+ }
+
+ return CAIRO_OPERATOR_OVER;
+}
+
+static inline cairo_antialias_t GfxAntialiasToCairoAntialias(
+ AntialiasMode antialias) {
+ switch (antialias) {
+ case AntialiasMode::NONE:
+ return CAIRO_ANTIALIAS_NONE;
+ case AntialiasMode::GRAY:
+ return CAIRO_ANTIALIAS_GRAY;
+ case AntialiasMode::SUBPIXEL:
+ return CAIRO_ANTIALIAS_SUBPIXEL;
+ default:
+ return CAIRO_ANTIALIAS_DEFAULT;
+ }
+}
+
+static inline AntialiasMode CairoAntialiasToGfxAntialias(
+ cairo_antialias_t aAntialias) {
+ switch (aAntialias) {
+ case CAIRO_ANTIALIAS_NONE:
+ return AntialiasMode::NONE;
+ case CAIRO_ANTIALIAS_GRAY:
+ return AntialiasMode::GRAY;
+ case CAIRO_ANTIALIAS_SUBPIXEL:
+ return AntialiasMode::SUBPIXEL;
+ default:
+ return AntialiasMode::DEFAULT;
+ }
+}
+
+static inline cairo_filter_t GfxSamplingFilterToCairoFilter(
+ SamplingFilter filter) {
+ switch (filter) {
+ case SamplingFilter::GOOD:
+ return CAIRO_FILTER_GOOD;
+ case SamplingFilter::LINEAR:
+ return CAIRO_FILTER_BILINEAR;
+ case SamplingFilter::POINT:
+ return CAIRO_FILTER_NEAREST;
+ default:
+ MOZ_CRASH("GFX: bad Cairo filter");
+ }
+
+ return CAIRO_FILTER_BILINEAR;
+}
+
+static inline cairo_extend_t GfxExtendToCairoExtend(ExtendMode extend) {
+ switch (extend) {
+ case ExtendMode::CLAMP:
+ return CAIRO_EXTEND_PAD;
+ // Cairo doesn't support tiling in only 1 direction,
+ // So we have to fallback and tile in both.
+ case ExtendMode::REPEAT_X:
+ case ExtendMode::REPEAT_Y:
+ case ExtendMode::REPEAT:
+ return CAIRO_EXTEND_REPEAT;
+ case ExtendMode::REFLECT:
+ return CAIRO_EXTEND_REFLECT;
+ }
+
+ return CAIRO_EXTEND_PAD;
+}
+
+static inline cairo_format_t GfxFormatToCairoFormat(SurfaceFormat format) {
+ switch (format) {
+ case SurfaceFormat::A8R8G8B8_UINT32:
+ return CAIRO_FORMAT_ARGB32;
+ case SurfaceFormat::X8R8G8B8_UINT32:
+ return CAIRO_FORMAT_RGB24;
+ case SurfaceFormat::A8:
+ return CAIRO_FORMAT_A8;
+ case SurfaceFormat::R5G6B5_UINT16:
+ return CAIRO_FORMAT_RGB16_565;
+ default:
+ gfxCriticalError() << "Unknown image format " << (int)format;
+ return CAIRO_FORMAT_ARGB32;
+ }
+}
+
+static inline cairo_format_t CairoContentToCairoFormat(
+ cairo_content_t content) {
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ return CAIRO_FORMAT_RGB24;
+ case CAIRO_CONTENT_ALPHA:
+ return CAIRO_FORMAT_A8;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ return CAIRO_FORMAT_ARGB32;
+ default:
+ gfxCriticalError() << "Unknown cairo content type " << (int)content;
+ return CAIRO_FORMAT_A8; // least likely to cause OOB reads
+ }
+}
+
+static inline cairo_content_t GfxFormatToCairoContent(SurfaceFormat format) {
+ switch (format) {
+ case SurfaceFormat::A8R8G8B8_UINT32:
+ return CAIRO_CONTENT_COLOR_ALPHA;
+ case SurfaceFormat::X8R8G8B8_UINT32:
+ case SurfaceFormat::R5G6B5_UINT16: // fall through
+ return CAIRO_CONTENT_COLOR;
+ case SurfaceFormat::A8:
+ return CAIRO_CONTENT_ALPHA;
+ default:
+ gfxCriticalError() << "Unknown image content format " << (int)format;
+ return CAIRO_CONTENT_COLOR_ALPHA;
+ }
+}
+
+static inline cairo_line_join_t GfxLineJoinToCairoLineJoin(JoinStyle style) {
+ switch (style) {
+ case JoinStyle::BEVEL:
+ return CAIRO_LINE_JOIN_BEVEL;
+ case JoinStyle::ROUND:
+ return CAIRO_LINE_JOIN_ROUND;
+ case JoinStyle::MITER:
+ return CAIRO_LINE_JOIN_MITER;
+ case JoinStyle::MITER_OR_BEVEL:
+ return CAIRO_LINE_JOIN_MITER;
+ }
+
+ return CAIRO_LINE_JOIN_MITER;
+}
+
+static inline cairo_line_cap_t GfxLineCapToCairoLineCap(CapStyle style) {
+ switch (style) {
+ case CapStyle::BUTT:
+ return CAIRO_LINE_CAP_BUTT;
+ case CapStyle::ROUND:
+ return CAIRO_LINE_CAP_ROUND;
+ case CapStyle::SQUARE:
+ return CAIRO_LINE_CAP_SQUARE;
+ }
+
+ return CAIRO_LINE_CAP_BUTT;
+}
+
+static inline SurfaceFormat CairoContentToGfxFormat(cairo_content_t content) {
+ switch (content) {
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ return SurfaceFormat::A8R8G8B8_UINT32;
+ case CAIRO_CONTENT_COLOR:
+ // BEWARE! format may be 565
+ return SurfaceFormat::X8R8G8B8_UINT32;
+ case CAIRO_CONTENT_ALPHA:
+ return SurfaceFormat::A8;
+ }
+
+ return SurfaceFormat::B8G8R8A8;
+}
+
+static inline SurfaceFormat CairoFormatToGfxFormat(cairo_format_t format) {
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ return SurfaceFormat::A8R8G8B8_UINT32;
+ case CAIRO_FORMAT_RGB24:
+ return SurfaceFormat::X8R8G8B8_UINT32;
+ case CAIRO_FORMAT_A8:
+ return SurfaceFormat::A8;
+ case CAIRO_FORMAT_RGB16_565:
+ return SurfaceFormat::R5G6B5_UINT16;
+ default:
+ gfxCriticalError() << "Unknown cairo format " << format;
+ return SurfaceFormat::UNKNOWN;
+ }
+}
+
+static inline FontHinting CairoHintingToGfxHinting(
+ cairo_hint_style_t aHintStyle) {
+ switch (aHintStyle) {
+ case CAIRO_HINT_STYLE_NONE:
+ return FontHinting::NONE;
+ case CAIRO_HINT_STYLE_SLIGHT:
+ return FontHinting::LIGHT;
+ case CAIRO_HINT_STYLE_MEDIUM:
+ return FontHinting::NORMAL;
+ case CAIRO_HINT_STYLE_FULL:
+ return FontHinting::FULL;
+ default:
+ return FontHinting::NORMAL;
+ }
+}
+
+SurfaceFormat GfxFormatForCairoSurface(cairo_surface_t* surface);
+
+static inline void GfxMatrixToCairoMatrix(const Matrix& mat,
+ cairo_matrix_t& retval) {
+ cairo_matrix_init(&retval, mat._11, mat._12, mat._21, mat._22, mat._31,
+ mat._32);
+}
+
+static inline void SetCairoStrokeOptions(cairo_t* aCtx,
+ const StrokeOptions& aStrokeOptions) {
+ cairo_set_line_width(aCtx, aStrokeOptions.mLineWidth);
+
+ cairo_set_miter_limit(aCtx, aStrokeOptions.mMiterLimit);
+
+ if (aStrokeOptions.mDashPattern) {
+ // Convert array of floats to array of doubles
+ std::vector<double> dashes(aStrokeOptions.mDashLength);
+ bool nonZero = false;
+ for (size_t i = 0; i < aStrokeOptions.mDashLength; ++i) {
+ if (aStrokeOptions.mDashPattern[i] != 0) {
+ nonZero = true;
+ }
+ dashes[i] = aStrokeOptions.mDashPattern[i];
+ }
+ // Avoid all-zero patterns that would trigger the CAIRO_STATUS_INVALID_DASH
+ // context error state.
+ if (nonZero) {
+ cairo_set_dash(aCtx, &dashes[0], aStrokeOptions.mDashLength,
+ aStrokeOptions.mDashOffset);
+ }
+ }
+
+ cairo_set_line_join(aCtx,
+ GfxLineJoinToCairoLineJoin(aStrokeOptions.mLineJoin));
+
+ cairo_set_line_cap(aCtx, GfxLineCapToCairoLineCap(aStrokeOptions.mLineCap));
+}
+
+static inline cairo_fill_rule_t GfxFillRuleToCairoFillRule(FillRule rule) {
+ switch (rule) {
+ case FillRule::FILL_WINDING:
+ return CAIRO_FILL_RULE_WINDING;
+ case FillRule::FILL_EVEN_ODD:
+ return CAIRO_FILL_RULE_EVEN_ODD;
+ }
+
+ return CAIRO_FILL_RULE_WINDING;
+}
+
+// RAII class for temporarily changing the cairo matrix transform. It will use
+// the given matrix transform while it is in scope. When it goes out of scope
+// it will put the cairo context back the way it was.
+
+class CairoTempMatrix {
+ public:
+ CairoTempMatrix(cairo_t* aCtx, const Matrix& aMatrix) : mCtx(aCtx) {
+ cairo_get_matrix(aCtx, &mSaveMatrix);
+ cairo_matrix_t matrix;
+ GfxMatrixToCairoMatrix(aMatrix, matrix);
+ cairo_set_matrix(aCtx, &matrix);
+ }
+
+ ~CairoTempMatrix() { cairo_set_matrix(mCtx, &mSaveMatrix); }
+
+ private:
+ cairo_t* mCtx;
+ cairo_matrix_t mSaveMatrix;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_HELPERSCAIRO_H_ */