tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_ */