tor-browser

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

HelpersSkia.h (12835B)


      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_HELPERSSKIA_H_
      8 #define MOZILLA_GFX_HELPERSSKIA_H_
      9 
     10 #include "2D.h"
     11 #include "skia/include/core/SkCanvas.h"
     12 #include "skia/include/core/SkFontTypes.h"
     13 #include "skia/include/core/SkPathEffect.h"
     14 #include "skia/include/core/SkPathTypes.h"
     15 #include "skia/include/core/SkShader.h"
     16 #include "skia/include/core/SkTileMode.h"
     17 #include "skia/include/effects/SkDashPathEffect.h"
     18 #include "mozilla/Assertions.h"
     19 #include <cmath>
     20 #include <vector>
     21 #include "nsDebug.h"
     22 
     23 namespace mozilla {
     24 namespace gfx {
     25 
     26 static inline SkColorType GfxFormatToSkiaColorType(SurfaceFormat format) {
     27  switch (format) {
     28    case SurfaceFormat::B8G8R8A8:
     29    case SurfaceFormat::B8G8R8X8:
     30      return kBGRA_8888_SkColorType;
     31    case SurfaceFormat::R5G6B5_UINT16:
     32      return kRGB_565_SkColorType;
     33    case SurfaceFormat::A8:
     34      return kAlpha_8_SkColorType;
     35    case SurfaceFormat::R8G8B8A8:
     36    case SurfaceFormat::R8G8B8X8:
     37      return kRGBA_8888_SkColorType;
     38    case SurfaceFormat::A8R8G8B8:
     39    case SurfaceFormat::X8R8G8B8:
     40 #ifndef FUZZING
     41      MOZ_DIAGNOSTIC_CRASH("A8R8G8B8 unsupported by Skia");
     42 #endif
     43      return kRGBA_8888_SkColorType;
     44    default:
     45 #ifndef FUZZING
     46      MOZ_DIAGNOSTIC_CRASH("Unknown surface format");
     47 #endif
     48      switch (BytesPerPixel(format)) {
     49        case 4:
     50          return kRGBA_8888_SkColorType;
     51        default:
     52          return kAlpha_8_SkColorType;
     53      }
     54  }
     55 }
     56 
     57 static inline SurfaceFormat SkiaColorTypeToGfxFormat(
     58    SkColorType aColorType, SkAlphaType aAlphaType = kPremul_SkAlphaType) {
     59  switch (aColorType) {
     60    case kBGRA_8888_SkColorType:
     61      return aAlphaType == kOpaque_SkAlphaType ? SurfaceFormat::B8G8R8X8
     62                                               : SurfaceFormat::B8G8R8A8;
     63    case kRGB_565_SkColorType:
     64      return SurfaceFormat::R5G6B5_UINT16;
     65    case kAlpha_8_SkColorType:
     66      return SurfaceFormat::A8;
     67    default:
     68      return SurfaceFormat::B8G8R8A8;
     69  }
     70 }
     71 
     72 static inline SkAlphaType GfxFormatToSkiaAlphaType(SurfaceFormat format) {
     73  return IsOpaque(format) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
     74 }
     75 
     76 static inline SkImageInfo MakeSkiaImageInfo(const IntSize& aSize,
     77                                            SurfaceFormat aFormat) {
     78  return SkImageInfo::Make(aSize.width, aSize.height,
     79                           GfxFormatToSkiaColorType(aFormat),
     80                           GfxFormatToSkiaAlphaType(aFormat));
     81 }
     82 
     83 static inline void GfxMatrixToSkiaMatrix(const Matrix& mat, SkMatrix& retval) {
     84  retval.setAll(SkFloatToScalar(mat._11), SkFloatToScalar(mat._21),
     85                SkFloatToScalar(mat._31), SkFloatToScalar(mat._12),
     86                SkFloatToScalar(mat._22), SkFloatToScalar(mat._32), 0, 0,
     87                SK_Scalar1);
     88 }
     89 
     90 static inline void GfxMatrixToSkiaMatrix(const Matrix4x4& aMatrix,
     91                                         SkMatrix& aResult) {
     92  aResult.setAll(SkFloatToScalar(aMatrix._11), SkFloatToScalar(aMatrix._21),
     93                 SkFloatToScalar(aMatrix._41), SkFloatToScalar(aMatrix._12),
     94                 SkFloatToScalar(aMatrix._22), SkFloatToScalar(aMatrix._42),
     95                 SkFloatToScalar(aMatrix._14), SkFloatToScalar(aMatrix._24),
     96                 SkFloatToScalar(aMatrix._44));
     97 }
     98 
     99 static inline SkPaint::Cap CapStyleToSkiaCap(CapStyle aCap) {
    100  switch (aCap) {
    101    case CapStyle::BUTT:
    102      return SkPaint::kButt_Cap;
    103    case CapStyle::ROUND:
    104      return SkPaint::kRound_Cap;
    105    case CapStyle::SQUARE:
    106      return SkPaint::kSquare_Cap;
    107  }
    108  return SkPaint::kDefault_Cap;
    109 }
    110 
    111 static inline SkPaint::Join JoinStyleToSkiaJoin(JoinStyle aJoin) {
    112  switch (aJoin) {
    113    case JoinStyle::BEVEL:
    114      return SkPaint::kBevel_Join;
    115    case JoinStyle::ROUND:
    116      return SkPaint::kRound_Join;
    117    case JoinStyle::MITER:
    118    case JoinStyle::MITER_OR_BEVEL:
    119      return SkPaint::kMiter_Join;
    120  }
    121  return SkPaint::kDefault_Join;
    122 }
    123 
    124 static inline bool StrokeOptionsToPaint(SkPaint& aPaint,
    125                                        const StrokeOptions& aOptions,
    126                                        bool aUsePathEffects = true) {
    127  // Skia renders 0 width strokes with a width of 1 (and in black),
    128  // so we should just skip the draw call entirely.
    129  // Skia does not handle non-finite line widths.
    130  if (!aOptions.mLineWidth || !std::isfinite(aOptions.mLineWidth)) {
    131    return false;
    132  }
    133  aPaint.setStrokeWidth(SkFloatToScalar(aOptions.mLineWidth));
    134  aPaint.setStrokeMiter(SkFloatToScalar(aOptions.mMiterLimit));
    135  aPaint.setStrokeCap(CapStyleToSkiaCap(aOptions.mLineCap));
    136  aPaint.setStrokeJoin(JoinStyleToSkiaJoin(aOptions.mLineJoin));
    137 
    138  if (aOptions.mDashLength > 0 && aUsePathEffects) {
    139    // Skia only supports dash arrays that are multiples of 2.
    140    uint32_t dashCount;
    141 
    142    if (aOptions.mDashLength % 2 == 0) {
    143      dashCount = aOptions.mDashLength;
    144    } else {
    145      dashCount = aOptions.mDashLength * 2;
    146    }
    147 
    148    std::vector<SkScalar> pattern;
    149    pattern.resize(dashCount);
    150 
    151    for (uint32_t i = 0; i < dashCount; i++) {
    152      pattern[i] =
    153          SkFloatToScalar(aOptions.mDashPattern[i % aOptions.mDashLength]);
    154    }
    155 
    156    auto dash = SkDashPathEffect::Make({&pattern.front(), dashCount},
    157                                       SkFloatToScalar(aOptions.mDashOffset));
    158    aPaint.setPathEffect(dash);
    159  }
    160 
    161  aPaint.setStyle(SkPaint::kStroke_Style);
    162  return true;
    163 }
    164 
    165 static inline SkBlendMode GfxOpToSkiaOp(CompositionOp op) {
    166  switch (op) {
    167    case CompositionOp::OP_CLEAR:
    168      return SkBlendMode::kClear;
    169    case CompositionOp::OP_OVER:
    170      return SkBlendMode::kSrcOver;
    171    case CompositionOp::OP_ADD:
    172      return SkBlendMode::kPlus;
    173    case CompositionOp::OP_ATOP:
    174      return SkBlendMode::kSrcATop;
    175    case CompositionOp::OP_OUT:
    176      return SkBlendMode::kSrcOut;
    177    case CompositionOp::OP_IN:
    178      return SkBlendMode::kSrcIn;
    179    case CompositionOp::OP_SOURCE:
    180      return SkBlendMode::kSrc;
    181    case CompositionOp::OP_DEST_IN:
    182      return SkBlendMode::kDstIn;
    183    case CompositionOp::OP_DEST_OUT:
    184      return SkBlendMode::kDstOut;
    185    case CompositionOp::OP_DEST_OVER:
    186      return SkBlendMode::kDstOver;
    187    case CompositionOp::OP_DEST_ATOP:
    188      return SkBlendMode::kDstATop;
    189    case CompositionOp::OP_XOR:
    190      return SkBlendMode::kXor;
    191    case CompositionOp::OP_MULTIPLY:
    192      return SkBlendMode::kMultiply;
    193    case CompositionOp::OP_SCREEN:
    194      return SkBlendMode::kScreen;
    195    case CompositionOp::OP_OVERLAY:
    196      return SkBlendMode::kOverlay;
    197    case CompositionOp::OP_DARKEN:
    198      return SkBlendMode::kDarken;
    199    case CompositionOp::OP_LIGHTEN:
    200      return SkBlendMode::kLighten;
    201    case CompositionOp::OP_COLOR_DODGE:
    202      return SkBlendMode::kColorDodge;
    203    case CompositionOp::OP_COLOR_BURN:
    204      return SkBlendMode::kColorBurn;
    205    case CompositionOp::OP_HARD_LIGHT:
    206      return SkBlendMode::kHardLight;
    207    case CompositionOp::OP_SOFT_LIGHT:
    208      return SkBlendMode::kSoftLight;
    209    case CompositionOp::OP_DIFFERENCE:
    210      return SkBlendMode::kDifference;
    211    case CompositionOp::OP_EXCLUSION:
    212      return SkBlendMode::kExclusion;
    213    case CompositionOp::OP_HUE:
    214      return SkBlendMode::kHue;
    215    case CompositionOp::OP_SATURATION:
    216      return SkBlendMode::kSaturation;
    217    case CompositionOp::OP_COLOR:
    218      return SkBlendMode::kColor;
    219    case CompositionOp::OP_LUMINOSITY:
    220      return SkBlendMode::kLuminosity;
    221    case CompositionOp::OP_COUNT:
    222      break;
    223  }
    224 
    225  return SkBlendMode::kSrcOver;
    226 }
    227 
    228 /* There's quite a bit of inconsistency about
    229 * whether float colors should be rounded with .5f.
    230 * We choose to do it to match cairo which also
    231 * happens to match the Direct3D specs */
    232 static inline U8CPU ColorFloatToByte(Float color) {
    233  // XXX: do a better job converting to int
    234  return U8CPU(color * 255.f + .5f);
    235 };
    236 
    237 static inline SkColor ColorToSkColor(const DeviceColor& color, Float aAlpha) {
    238  return SkColorSetARGB(ColorFloatToByte(color.a * aAlpha),
    239                        ColorFloatToByte(color.r), ColorFloatToByte(color.g),
    240                        ColorFloatToByte(color.b));
    241 }
    242 
    243 static inline SkPoint PointToSkPoint(const Point& aPoint) {
    244  return SkPoint::Make(SkFloatToScalar(aPoint.x), SkFloatToScalar(aPoint.y));
    245 }
    246 
    247 static inline SkRect RectToSkRect(const Rect& aRect) {
    248  return SkRect::MakeXYWH(
    249      SkFloatToScalar(aRect.X()), SkFloatToScalar(aRect.Y()),
    250      SkFloatToScalar(aRect.Width()), SkFloatToScalar(aRect.Height()));
    251 }
    252 
    253 static inline SkRect IntRectToSkRect(const IntRect& aRect) {
    254  return SkRect::MakeXYWH(SkIntToScalar(aRect.X()), SkIntToScalar(aRect.Y()),
    255                          SkIntToScalar(aRect.Width()),
    256                          SkIntToScalar(aRect.Height()));
    257 }
    258 
    259 static inline SkIRect RectToSkIRect(const Rect& aRect) {
    260  return SkIRect::MakeXYWH(int32_t(aRect.X()), int32_t(aRect.Y()),
    261                           int32_t(aRect.Width()), int32_t(aRect.Height()));
    262 }
    263 
    264 static inline SkIRect IntRectToSkIRect(const IntRect& aRect) {
    265  return SkIRect::MakeXYWH(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
    266 }
    267 
    268 static inline IntRect SkIRectToIntRect(const SkIRect& aRect) {
    269  return IntRect(aRect.x(), aRect.y(), aRect.width(), aRect.height());
    270 }
    271 
    272 static inline Point SkPointToPoint(const SkPoint& aPoint) {
    273  return Point(SkScalarToFloat(aPoint.x()), SkScalarToFloat(aPoint.y()));
    274 }
    275 
    276 static inline Rect SkRectToRect(const SkRect& aRect) {
    277  return Rect(SkScalarToFloat(aRect.x()), SkScalarToFloat(aRect.y()),
    278              SkScalarToFloat(aRect.width()), SkScalarToFloat(aRect.height()));
    279 }
    280 
    281 static inline RectDouble SkRectToRectDouble(const SkRect& aRect) {
    282  double x = SkScalarToDouble(aRect.x());
    283  double y = SkScalarToDouble(aRect.y());
    284  return RectDouble(x, y, SkScalarToDouble(aRect.right()) - x,
    285                    SkScalarToDouble(aRect.bottom()) - y);
    286 }
    287 
    288 static inline SkTileMode ExtendModeToTileMode(ExtendMode aMode, Axis aAxis) {
    289  switch (aMode) {
    290    case ExtendMode::CLAMP:
    291      return SkTileMode::kClamp;
    292    case ExtendMode::REPEAT:
    293      return SkTileMode::kRepeat;
    294    case ExtendMode::REFLECT:
    295      return SkTileMode::kMirror;
    296    case ExtendMode::REPEAT_X: {
    297      return aAxis == Axis::X_AXIS ? SkTileMode::kRepeat : SkTileMode::kClamp;
    298    }
    299    case ExtendMode::REPEAT_Y: {
    300      return aAxis == Axis::Y_AXIS ? SkTileMode::kRepeat : SkTileMode::kClamp;
    301    }
    302  }
    303  return SkTileMode::kClamp;
    304 }
    305 
    306 static inline SkFontHinting GfxHintingToSkiaHinting(FontHinting aHinting) {
    307  switch (aHinting) {
    308    case FontHinting::NONE:
    309      return SkFontHinting::kNone;
    310    case FontHinting::LIGHT:
    311      return SkFontHinting::kSlight;
    312    case FontHinting::NORMAL:
    313      return SkFontHinting::kNormal;
    314    case FontHinting::FULL:
    315      return SkFontHinting::kFull;
    316  }
    317  return SkFontHinting::kNormal;
    318 }
    319 
    320 static inline FillRule GetFillRule(SkPathFillType aFillType) {
    321  switch (aFillType) {
    322    case SkPathFillType::kWinding:
    323      return FillRule::FILL_WINDING;
    324    case SkPathFillType::kEvenOdd:
    325      return FillRule::FILL_EVEN_ODD;
    326    case SkPathFillType::kInverseWinding:
    327    case SkPathFillType::kInverseEvenOdd:
    328    default:
    329      NS_WARNING("Unsupported fill type\n");
    330      break;
    331  }
    332 
    333  return FillRule::FILL_EVEN_ODD;
    334 }
    335 
    336 /**
    337 * Returns true if the canvas is backed by pixels.  Returns false if the canvas
    338 * wraps an SkPDFDocument, for example.
    339 *
    340 * Note: It is not clear whether the test used to implement this function may
    341 * result in it returning false in some circumstances even when the canvas
    342 * _is_ pixel backed.  In other words maybe it is possible for such a canvas to
    343 * have kUnknown_SkPixelGeometry?
    344 */
    345 static inline bool IsBackedByPixels(const SkCanvas* aCanvas) {
    346  SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
    347  if (!aCanvas->getProps(&props) ||
    348      props.pixelGeometry() == kUnknown_SkPixelGeometry) {
    349    return false;
    350  }
    351  return true;
    352 }
    353 
    354 /**
    355 * Computes appropriate resolution scale to be used with SkPath::getFillPath
    356 * based on the scaling of the supplied transform.
    357 */
    358 float ComputeResScaleForStroking(const Matrix& aTransform);
    359 
    360 /**
    361 * This is a wrapper around SkGeometry's SkConic that can be used to convert
    362 * conic sections in an SkPath to a sequence of quadratic curves. The quads
    363 * vector is organized such that for the Nth quad, it's control points are
    364 * 2*N, 2*N+1, 2*N+2. This function returns the resulting number of quads.
    365 */
    366 int ConvertConicToQuads(const Point& aP0, const Point& aP1, const Point& aP2,
    367                        float aWeight, std::vector<Point>& aQuads);
    368 
    369 }  // namespace gfx
    370 }  // namespace mozilla
    371 
    372 #endif /* MOZILLA_GFX_HELPERSSKIA_H_ */