HelpersCairo.h (10339B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef MOZILLA_GFX_HELPERSCAIRO_H_ 8 #define MOZILLA_GFX_HELPERSCAIRO_H_ 9 10 #include "2D.h" 11 #include "cairo.h" 12 #include "Logging.h" 13 14 namespace mozilla { 15 namespace gfx { 16 17 static inline cairo_operator_t GfxOpToCairoOp(CompositionOp op) { 18 switch (op) { 19 case CompositionOp::OP_CLEAR: 20 return CAIRO_OPERATOR_CLEAR; 21 case CompositionOp::OP_OVER: 22 return CAIRO_OPERATOR_OVER; 23 case CompositionOp::OP_ADD: 24 return CAIRO_OPERATOR_ADD; 25 case CompositionOp::OP_ATOP: 26 return CAIRO_OPERATOR_ATOP; 27 case CompositionOp::OP_OUT: 28 return CAIRO_OPERATOR_OUT; 29 case CompositionOp::OP_IN: 30 return CAIRO_OPERATOR_IN; 31 case CompositionOp::OP_SOURCE: 32 return CAIRO_OPERATOR_SOURCE; 33 case CompositionOp::OP_DEST_IN: 34 return CAIRO_OPERATOR_DEST_IN; 35 case CompositionOp::OP_DEST_OUT: 36 return CAIRO_OPERATOR_DEST_OUT; 37 case CompositionOp::OP_DEST_OVER: 38 return CAIRO_OPERATOR_DEST_OVER; 39 case CompositionOp::OP_DEST_ATOP: 40 return CAIRO_OPERATOR_DEST_ATOP; 41 case CompositionOp::OP_XOR: 42 return CAIRO_OPERATOR_XOR; 43 case CompositionOp::OP_MULTIPLY: 44 return CAIRO_OPERATOR_MULTIPLY; 45 case CompositionOp::OP_SCREEN: 46 return CAIRO_OPERATOR_SCREEN; 47 case CompositionOp::OP_OVERLAY: 48 return CAIRO_OPERATOR_OVERLAY; 49 case CompositionOp::OP_DARKEN: 50 return CAIRO_OPERATOR_DARKEN; 51 case CompositionOp::OP_LIGHTEN: 52 return CAIRO_OPERATOR_LIGHTEN; 53 case CompositionOp::OP_COLOR_DODGE: 54 return CAIRO_OPERATOR_COLOR_DODGE; 55 case CompositionOp::OP_COLOR_BURN: 56 return CAIRO_OPERATOR_COLOR_BURN; 57 case CompositionOp::OP_HARD_LIGHT: 58 return CAIRO_OPERATOR_HARD_LIGHT; 59 case CompositionOp::OP_SOFT_LIGHT: 60 return CAIRO_OPERATOR_SOFT_LIGHT; 61 case CompositionOp::OP_DIFFERENCE: 62 return CAIRO_OPERATOR_DIFFERENCE; 63 case CompositionOp::OP_EXCLUSION: 64 return CAIRO_OPERATOR_EXCLUSION; 65 case CompositionOp::OP_HUE: 66 return CAIRO_OPERATOR_HSL_HUE; 67 case CompositionOp::OP_SATURATION: 68 return CAIRO_OPERATOR_HSL_SATURATION; 69 case CompositionOp::OP_COLOR: 70 return CAIRO_OPERATOR_HSL_COLOR; 71 case CompositionOp::OP_LUMINOSITY: 72 return CAIRO_OPERATOR_HSL_LUMINOSITY; 73 case CompositionOp::OP_COUNT: 74 break; 75 } 76 77 return CAIRO_OPERATOR_OVER; 78 } 79 80 static inline cairo_antialias_t GfxAntialiasToCairoAntialias( 81 AntialiasMode antialias) { 82 switch (antialias) { 83 case AntialiasMode::NONE: 84 return CAIRO_ANTIALIAS_NONE; 85 case AntialiasMode::GRAY: 86 return CAIRO_ANTIALIAS_GRAY; 87 case AntialiasMode::SUBPIXEL: 88 return CAIRO_ANTIALIAS_SUBPIXEL; 89 default: 90 return CAIRO_ANTIALIAS_DEFAULT; 91 } 92 } 93 94 static inline AntialiasMode CairoAntialiasToGfxAntialias( 95 cairo_antialias_t aAntialias) { 96 switch (aAntialias) { 97 case CAIRO_ANTIALIAS_NONE: 98 return AntialiasMode::NONE; 99 case CAIRO_ANTIALIAS_GRAY: 100 return AntialiasMode::GRAY; 101 case CAIRO_ANTIALIAS_SUBPIXEL: 102 return AntialiasMode::SUBPIXEL; 103 default: 104 return AntialiasMode::DEFAULT; 105 } 106 } 107 108 static inline cairo_filter_t GfxSamplingFilterToCairoFilter( 109 SamplingFilter filter) { 110 switch (filter) { 111 case SamplingFilter::GOOD: 112 return CAIRO_FILTER_GOOD; 113 case SamplingFilter::LINEAR: 114 return CAIRO_FILTER_BILINEAR; 115 case SamplingFilter::POINT: 116 return CAIRO_FILTER_NEAREST; 117 default: 118 MOZ_CRASH("GFX: bad Cairo filter"); 119 } 120 121 return CAIRO_FILTER_BILINEAR; 122 } 123 124 static inline cairo_extend_t GfxExtendToCairoExtend(ExtendMode extend) { 125 switch (extend) { 126 case ExtendMode::CLAMP: 127 return CAIRO_EXTEND_PAD; 128 // Cairo doesn't support tiling in only 1 direction, 129 // So we have to fallback and tile in both. 130 case ExtendMode::REPEAT_X: 131 case ExtendMode::REPEAT_Y: 132 case ExtendMode::REPEAT: 133 return CAIRO_EXTEND_REPEAT; 134 case ExtendMode::REFLECT: 135 return CAIRO_EXTEND_REFLECT; 136 } 137 138 return CAIRO_EXTEND_PAD; 139 } 140 141 static inline cairo_format_t GfxFormatToCairoFormat(SurfaceFormat format) { 142 switch (format) { 143 case SurfaceFormat::B8G8R8A8: 144 case SurfaceFormat::R8G8B8A8: 145 case SurfaceFormat::A8R8G8B8: 146 // case SurfaceFormat::A8R8G8B8_UINT32: 147 return CAIRO_FORMAT_ARGB32; 148 case SurfaceFormat::B8G8R8X8: 149 case SurfaceFormat::R8G8B8X8: 150 case SurfaceFormat::X8R8G8B8: 151 // case SurfaceFormat::X8R8G8B8_UINT32: 152 return CAIRO_FORMAT_RGB24; 153 case SurfaceFormat::A8: 154 return CAIRO_FORMAT_A8; 155 case SurfaceFormat::R5G6B5_UINT16: 156 return CAIRO_FORMAT_RGB16_565; 157 default: 158 gfxCriticalError() << "Unknown image format " << (int)format; 159 return CAIRO_FORMAT_INVALID; 160 } 161 } 162 163 static inline cairo_format_t CairoContentToCairoFormat( 164 cairo_content_t content) { 165 switch (content) { 166 case CAIRO_CONTENT_COLOR: 167 return CAIRO_FORMAT_RGB24; 168 case CAIRO_CONTENT_ALPHA: 169 return CAIRO_FORMAT_A8; 170 case CAIRO_CONTENT_COLOR_ALPHA: 171 return CAIRO_FORMAT_ARGB32; 172 default: 173 gfxCriticalError() << "Unknown cairo content type " << (int)content; 174 return CAIRO_FORMAT_A8; // least likely to cause OOB reads 175 } 176 } 177 178 static inline cairo_content_t GfxFormatToCairoContent(SurfaceFormat format) { 179 switch (format) { 180 case SurfaceFormat::A8R8G8B8_UINT32: 181 return CAIRO_CONTENT_COLOR_ALPHA; 182 case SurfaceFormat::X8R8G8B8_UINT32: 183 case SurfaceFormat::R5G6B5_UINT16: // fall through 184 return CAIRO_CONTENT_COLOR; 185 case SurfaceFormat::A8: 186 return CAIRO_CONTENT_ALPHA; 187 default: 188 gfxCriticalError() << "Unknown image content format " << (int)format; 189 return CAIRO_CONTENT_COLOR_ALPHA; 190 } 191 } 192 193 static inline cairo_line_join_t GfxLineJoinToCairoLineJoin(JoinStyle style) { 194 switch (style) { 195 case JoinStyle::BEVEL: 196 return CAIRO_LINE_JOIN_BEVEL; 197 case JoinStyle::ROUND: 198 return CAIRO_LINE_JOIN_ROUND; 199 case JoinStyle::MITER: 200 return CAIRO_LINE_JOIN_MITER; 201 case JoinStyle::MITER_OR_BEVEL: 202 return CAIRO_LINE_JOIN_MITER; 203 } 204 205 return CAIRO_LINE_JOIN_MITER; 206 } 207 208 static inline cairo_line_cap_t GfxLineCapToCairoLineCap(CapStyle style) { 209 switch (style) { 210 case CapStyle::BUTT: 211 return CAIRO_LINE_CAP_BUTT; 212 case CapStyle::ROUND: 213 return CAIRO_LINE_CAP_ROUND; 214 case CapStyle::SQUARE: 215 return CAIRO_LINE_CAP_SQUARE; 216 } 217 218 return CAIRO_LINE_CAP_BUTT; 219 } 220 221 static inline SurfaceFormat CairoContentToGfxFormat(cairo_content_t content) { 222 switch (content) { 223 case CAIRO_CONTENT_COLOR_ALPHA: 224 return SurfaceFormat::A8R8G8B8_UINT32; 225 case CAIRO_CONTENT_COLOR: 226 // BEWARE! format may be 565 227 return SurfaceFormat::X8R8G8B8_UINT32; 228 case CAIRO_CONTENT_ALPHA: 229 return SurfaceFormat::A8; 230 } 231 232 return SurfaceFormat::B8G8R8A8; 233 } 234 235 static inline SurfaceFormat CairoFormatToGfxFormat(cairo_format_t format) { 236 switch (format) { 237 case CAIRO_FORMAT_ARGB32: 238 return SurfaceFormat::A8R8G8B8_UINT32; 239 case CAIRO_FORMAT_RGB24: 240 return SurfaceFormat::X8R8G8B8_UINT32; 241 case CAIRO_FORMAT_A8: 242 return SurfaceFormat::A8; 243 case CAIRO_FORMAT_RGB16_565: 244 return SurfaceFormat::R5G6B5_UINT16; 245 default: 246 gfxCriticalError() << "Unknown cairo format " << format; 247 return SurfaceFormat::UNKNOWN; 248 } 249 } 250 251 static inline FontHinting CairoHintingToGfxHinting( 252 cairo_hint_style_t aHintStyle) { 253 switch (aHintStyle) { 254 case CAIRO_HINT_STYLE_NONE: 255 return FontHinting::NONE; 256 case CAIRO_HINT_STYLE_SLIGHT: 257 return FontHinting::LIGHT; 258 case CAIRO_HINT_STYLE_MEDIUM: 259 return FontHinting::NORMAL; 260 case CAIRO_HINT_STYLE_FULL: 261 return FontHinting::FULL; 262 default: 263 return FontHinting::NORMAL; 264 } 265 } 266 267 SurfaceFormat GfxFormatForCairoSurface(cairo_surface_t* surface); 268 269 static inline void GfxMatrixToCairoMatrix(const Matrix& mat, 270 cairo_matrix_t& retval) { 271 cairo_matrix_init(&retval, mat._11, mat._12, mat._21, mat._22, mat._31, 272 mat._32); 273 } 274 275 static inline void SetCairoStrokeOptions(cairo_t* aCtx, 276 const StrokeOptions& aStrokeOptions) { 277 cairo_set_line_width(aCtx, aStrokeOptions.mLineWidth); 278 279 cairo_set_miter_limit(aCtx, aStrokeOptions.mMiterLimit); 280 281 if (aStrokeOptions.mDashPattern) { 282 // Convert array of floats to array of doubles 283 std::vector<double> dashes(aStrokeOptions.mDashLength); 284 bool nonZero = false; 285 for (size_t i = 0; i < aStrokeOptions.mDashLength; ++i) { 286 if (aStrokeOptions.mDashPattern[i] != 0) { 287 nonZero = true; 288 } 289 dashes[i] = aStrokeOptions.mDashPattern[i]; 290 } 291 // Avoid all-zero patterns that would trigger the CAIRO_STATUS_INVALID_DASH 292 // context error state. 293 if (nonZero) { 294 cairo_set_dash(aCtx, &dashes[0], aStrokeOptions.mDashLength, 295 aStrokeOptions.mDashOffset); 296 } 297 } 298 299 cairo_set_line_join(aCtx, 300 GfxLineJoinToCairoLineJoin(aStrokeOptions.mLineJoin)); 301 302 cairo_set_line_cap(aCtx, GfxLineCapToCairoLineCap(aStrokeOptions.mLineCap)); 303 } 304 305 static inline cairo_fill_rule_t GfxFillRuleToCairoFillRule(FillRule rule) { 306 switch (rule) { 307 case FillRule::FILL_WINDING: 308 return CAIRO_FILL_RULE_WINDING; 309 case FillRule::FILL_EVEN_ODD: 310 return CAIRO_FILL_RULE_EVEN_ODD; 311 } 312 313 return CAIRO_FILL_RULE_WINDING; 314 } 315 316 // RAII class for temporarily changing the cairo matrix transform. It will use 317 // the given matrix transform while it is in scope. When it goes out of scope 318 // it will put the cairo context back the way it was. 319 320 class CairoTempMatrix { 321 public: 322 CairoTempMatrix(cairo_t* aCtx, const Matrix& aMatrix) : mCtx(aCtx) { 323 cairo_get_matrix(aCtx, &mSaveMatrix); 324 cairo_matrix_t matrix; 325 GfxMatrixToCairoMatrix(aMatrix, matrix); 326 cairo_set_matrix(aCtx, &matrix); 327 } 328 329 ~CairoTempMatrix() { cairo_set_matrix(mCtx, &mSaveMatrix); } 330 331 private: 332 cairo_t* mCtx; 333 cairo_matrix_t mSaveMatrix; 334 }; 335 336 } // namespace gfx 337 } // namespace mozilla 338 339 #endif /* MOZILLA_GFX_HELPERSCAIRO_H_ */