michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef MOZILLA_GFX_HELPERSCAIRO_H_ michael@0: #define MOZILLA_GFX_HELPERSCAIRO_H_ michael@0: michael@0: #include "2D.h" michael@0: #include "cairo.h" michael@0: #include "Logging.h" michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: michael@0: static inline cairo_operator_t michael@0: GfxOpToCairoOp(CompositionOp op) michael@0: { michael@0: switch (op) michael@0: { michael@0: case CompositionOp::OP_OVER: michael@0: return CAIRO_OPERATOR_OVER; michael@0: case CompositionOp::OP_ADD: michael@0: return CAIRO_OPERATOR_ADD; michael@0: case CompositionOp::OP_ATOP: michael@0: return CAIRO_OPERATOR_ATOP; michael@0: case CompositionOp::OP_OUT: michael@0: return CAIRO_OPERATOR_OUT; michael@0: case CompositionOp::OP_IN: michael@0: return CAIRO_OPERATOR_IN; michael@0: case CompositionOp::OP_SOURCE: michael@0: return CAIRO_OPERATOR_SOURCE; michael@0: case CompositionOp::OP_DEST_IN: michael@0: return CAIRO_OPERATOR_DEST_IN; michael@0: case CompositionOp::OP_DEST_OUT: michael@0: return CAIRO_OPERATOR_DEST_OUT; michael@0: case CompositionOp::OP_DEST_OVER: michael@0: return CAIRO_OPERATOR_DEST_OVER; michael@0: case CompositionOp::OP_DEST_ATOP: michael@0: return CAIRO_OPERATOR_DEST_ATOP; michael@0: case CompositionOp::OP_XOR: michael@0: return CAIRO_OPERATOR_XOR; michael@0: case CompositionOp::OP_MULTIPLY: michael@0: return CAIRO_OPERATOR_MULTIPLY; michael@0: case CompositionOp::OP_SCREEN: michael@0: return CAIRO_OPERATOR_SCREEN; michael@0: case CompositionOp::OP_OVERLAY: michael@0: return CAIRO_OPERATOR_OVERLAY; michael@0: case CompositionOp::OP_DARKEN: michael@0: return CAIRO_OPERATOR_DARKEN; michael@0: case CompositionOp::OP_LIGHTEN: michael@0: return CAIRO_OPERATOR_LIGHTEN; michael@0: case CompositionOp::OP_COLOR_DODGE: michael@0: return CAIRO_OPERATOR_COLOR_DODGE; michael@0: case CompositionOp::OP_COLOR_BURN: michael@0: return CAIRO_OPERATOR_COLOR_BURN; michael@0: case CompositionOp::OP_HARD_LIGHT: michael@0: return CAIRO_OPERATOR_HARD_LIGHT; michael@0: case CompositionOp::OP_SOFT_LIGHT: michael@0: return CAIRO_OPERATOR_SOFT_LIGHT; michael@0: case CompositionOp::OP_DIFFERENCE: michael@0: return CAIRO_OPERATOR_DIFFERENCE; michael@0: case CompositionOp::OP_EXCLUSION: michael@0: return CAIRO_OPERATOR_EXCLUSION; michael@0: case CompositionOp::OP_HUE: michael@0: return CAIRO_OPERATOR_HSL_HUE; michael@0: case CompositionOp::OP_SATURATION: michael@0: return CAIRO_OPERATOR_HSL_SATURATION; michael@0: case CompositionOp::OP_COLOR: michael@0: return CAIRO_OPERATOR_HSL_COLOR; michael@0: case CompositionOp::OP_LUMINOSITY: michael@0: return CAIRO_OPERATOR_HSL_LUMINOSITY; michael@0: case CompositionOp::OP_COUNT: michael@0: break; michael@0: } michael@0: michael@0: return CAIRO_OPERATOR_OVER; michael@0: } michael@0: michael@0: static inline cairo_antialias_t michael@0: GfxAntialiasToCairoAntialias(AntialiasMode antialias) michael@0: { michael@0: switch (antialias) michael@0: { michael@0: case AntialiasMode::NONE: michael@0: return CAIRO_ANTIALIAS_NONE; michael@0: case AntialiasMode::GRAY: michael@0: return CAIRO_ANTIALIAS_GRAY; michael@0: case AntialiasMode::SUBPIXEL: michael@0: return CAIRO_ANTIALIAS_SUBPIXEL; michael@0: case AntialiasMode::DEFAULT: michael@0: return CAIRO_ANTIALIAS_DEFAULT; michael@0: } michael@0: return CAIRO_ANTIALIAS_DEFAULT; michael@0: } michael@0: michael@0: static inline cairo_filter_t michael@0: GfxFilterToCairoFilter(Filter filter) michael@0: { michael@0: switch (filter) michael@0: { michael@0: case Filter::GOOD: michael@0: return CAIRO_FILTER_GOOD; michael@0: case Filter::LINEAR: michael@0: return CAIRO_FILTER_BILINEAR; michael@0: case Filter::POINT: michael@0: return CAIRO_FILTER_NEAREST; michael@0: } michael@0: michael@0: return CAIRO_FILTER_BILINEAR; michael@0: } michael@0: michael@0: static inline cairo_extend_t michael@0: GfxExtendToCairoExtend(ExtendMode extend) michael@0: { michael@0: switch (extend) michael@0: { michael@0: case ExtendMode::CLAMP: michael@0: return CAIRO_EXTEND_PAD; michael@0: case ExtendMode::REPEAT: michael@0: return CAIRO_EXTEND_REPEAT; michael@0: case ExtendMode::REFLECT: michael@0: return CAIRO_EXTEND_REFLECT; michael@0: } michael@0: michael@0: return CAIRO_EXTEND_PAD; michael@0: } michael@0: michael@0: static inline cairo_format_t michael@0: GfxFormatToCairoFormat(SurfaceFormat format) michael@0: { michael@0: switch (format) michael@0: { michael@0: case SurfaceFormat::B8G8R8A8: michael@0: return CAIRO_FORMAT_ARGB32; michael@0: case SurfaceFormat::B8G8R8X8: michael@0: return CAIRO_FORMAT_RGB24; michael@0: case SurfaceFormat::A8: michael@0: return CAIRO_FORMAT_A8; michael@0: case SurfaceFormat::R5G6B5: michael@0: return CAIRO_FORMAT_RGB16_565; michael@0: default: michael@0: gfxWarning() << "Unknown image format"; michael@0: return CAIRO_FORMAT_ARGB32; michael@0: } michael@0: } michael@0: michael@0: static inline cairo_content_t michael@0: GfxFormatToCairoContent(SurfaceFormat format) michael@0: { michael@0: switch (format) michael@0: { michael@0: case SurfaceFormat::B8G8R8A8: michael@0: return CAIRO_CONTENT_COLOR_ALPHA; michael@0: case SurfaceFormat::B8G8R8X8: michael@0: case SurfaceFormat::R5G6B5: //fall through michael@0: return CAIRO_CONTENT_COLOR; michael@0: case SurfaceFormat::A8: michael@0: return CAIRO_CONTENT_ALPHA; michael@0: default: michael@0: gfxWarning() << "Unknown image format"; michael@0: return CAIRO_CONTENT_COLOR_ALPHA; michael@0: } michael@0: } michael@0: michael@0: static inline cairo_line_join_t michael@0: GfxLineJoinToCairoLineJoin(JoinStyle style) michael@0: { michael@0: switch (style) michael@0: { michael@0: case JoinStyle::BEVEL: michael@0: return CAIRO_LINE_JOIN_BEVEL; michael@0: case JoinStyle::ROUND: michael@0: return CAIRO_LINE_JOIN_ROUND; michael@0: case JoinStyle::MITER: michael@0: return CAIRO_LINE_JOIN_MITER; michael@0: case JoinStyle::MITER_OR_BEVEL: michael@0: return CAIRO_LINE_JOIN_MITER; michael@0: } michael@0: michael@0: return CAIRO_LINE_JOIN_MITER; michael@0: } michael@0: michael@0: static inline cairo_line_cap_t michael@0: GfxLineCapToCairoLineCap(CapStyle style) michael@0: { michael@0: switch (style) michael@0: { michael@0: case CapStyle::BUTT: michael@0: return CAIRO_LINE_CAP_BUTT; michael@0: case CapStyle::ROUND: michael@0: return CAIRO_LINE_CAP_ROUND; michael@0: case CapStyle::SQUARE: michael@0: return CAIRO_LINE_CAP_SQUARE; michael@0: } michael@0: michael@0: return CAIRO_LINE_CAP_BUTT; michael@0: } michael@0: michael@0: static inline SurfaceFormat michael@0: CairoContentToGfxFormat(cairo_content_t content) michael@0: { michael@0: switch (content) michael@0: { michael@0: case CAIRO_CONTENT_COLOR_ALPHA: michael@0: return SurfaceFormat::B8G8R8A8; michael@0: case CAIRO_CONTENT_COLOR: michael@0: // BEWARE! format may be 565 michael@0: return SurfaceFormat::B8G8R8X8; michael@0: case CAIRO_CONTENT_ALPHA: michael@0: return SurfaceFormat::A8; michael@0: } michael@0: michael@0: return SurfaceFormat::B8G8R8A8; michael@0: } michael@0: michael@0: static inline void michael@0: GfxMatrixToCairoMatrix(const Matrix& mat, cairo_matrix_t& retval) michael@0: { michael@0: cairo_matrix_init(&retval, mat._11, mat._12, mat._21, mat._22, mat._31, mat._32); michael@0: } michael@0: michael@0: static inline void michael@0: SetCairoStrokeOptions(cairo_t* aCtx, const StrokeOptions& aStrokeOptions) michael@0: { michael@0: cairo_set_line_width(aCtx, aStrokeOptions.mLineWidth); michael@0: michael@0: cairo_set_miter_limit(aCtx, aStrokeOptions.mMiterLimit); michael@0: michael@0: if (aStrokeOptions.mDashPattern) { michael@0: // Convert array of floats to array of doubles michael@0: std::vector dashes(aStrokeOptions.mDashLength); michael@0: for (size_t i = 0; i < aStrokeOptions.mDashLength; ++i) { michael@0: dashes[i] = aStrokeOptions.mDashPattern[i]; michael@0: } michael@0: cairo_set_dash(aCtx, &dashes[0], aStrokeOptions.mDashLength, michael@0: aStrokeOptions.mDashOffset); michael@0: } michael@0: michael@0: cairo_set_line_join(aCtx, GfxLineJoinToCairoLineJoin(aStrokeOptions.mLineJoin)); michael@0: michael@0: cairo_set_line_cap(aCtx, GfxLineCapToCairoLineCap(aStrokeOptions.mLineCap)); michael@0: } michael@0: michael@0: static inline cairo_fill_rule_t michael@0: GfxFillRuleToCairoFillRule(FillRule rule) michael@0: { michael@0: switch (rule) michael@0: { michael@0: case FillRule::FILL_WINDING: michael@0: return CAIRO_FILL_RULE_WINDING; michael@0: case FillRule::FILL_EVEN_ODD: michael@0: return CAIRO_FILL_RULE_EVEN_ODD; michael@0: } michael@0: michael@0: return CAIRO_FILL_RULE_WINDING; michael@0: } michael@0: michael@0: // RAII class for temporarily changing the cairo matrix transform. It will use michael@0: // the given matrix transform while it is in scope. When it goes out of scope michael@0: // it will put the cairo context back the way it was. michael@0: michael@0: class CairoTempMatrix michael@0: { michael@0: public: michael@0: CairoTempMatrix(cairo_t* aCtx, const Matrix& aMatrix) michael@0: : mCtx(aCtx) michael@0: { michael@0: cairo_get_matrix(aCtx, &mSaveMatrix); michael@0: cairo_matrix_t matrix; michael@0: GfxMatrixToCairoMatrix(aMatrix, matrix); michael@0: cairo_set_matrix(aCtx, &matrix); michael@0: } michael@0: michael@0: ~CairoTempMatrix() michael@0: { michael@0: cairo_set_matrix(mCtx, &mSaveMatrix); michael@0: } michael@0: michael@0: private: michael@0: cairo_t* mCtx; michael@0: cairo_matrix_t mSaveMatrix; michael@0: }; michael@0: michael@0: } michael@0: } michael@0: michael@0: #endif /* MOZILLA_GFX_HELPERSCAIRO_H_ */