tor-browser

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

ScaledFontBase.cpp (7014B)


      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 #include "ScaledFontBase.h"
      8 
      9 #include "PathSkia.h"
     10 #include "skia/include/core/SkFont.h"
     11 
     12 #ifdef USE_CAIRO
     13 #  include "PathCairo.h"
     14 #  include "DrawTargetCairo.h"
     15 #  include "HelpersCairo.h"
     16 #endif
     17 
     18 #include <vector>
     19 #include <cmath>
     20 
     21 namespace mozilla {
     22 namespace gfx {
     23 
     24 Atomic<uint32_t> UnscaledFont::sDeletionCounter(0);
     25 
     26 UnscaledFont::~UnscaledFont() { sDeletionCounter++; }
     27 
     28 Atomic<uint32_t> ScaledFont::sDeletionCounter(0);
     29 
     30 ScaledFont::~ScaledFont() { sDeletionCounter++; }
     31 
     32 ScaledFontBase::~ScaledFontBase() {
     33  SkSafeUnref<SkTypeface>(mTypeface);
     34  cairo_scaled_font_destroy(mScaledFont);
     35 }
     36 
     37 ScaledFontBase::ScaledFontBase(const RefPtr<UnscaledFont>& aUnscaledFont,
     38                               Float aSize)
     39    : ScaledFont(aUnscaledFont),
     40      mTypeface(nullptr),
     41      mScaledFont(nullptr),
     42      mSize(aSize) {}
     43 
     44 SkTypeface* ScaledFontBase::GetSkTypeface() {
     45  if (!mTypeface) {
     46    SkTypeface* typeface = CreateSkTypeface();
     47    if (!mTypeface.compareExchange(nullptr, typeface)) {
     48      SkSafeUnref(typeface);
     49    }
     50  }
     51  return mTypeface;
     52 }
     53 
     54 cairo_scaled_font_t* ScaledFontBase::GetCairoScaledFont() {
     55  if (mScaledFont) {
     56    return mScaledFont;
     57  }
     58 
     59  cairo_font_options_t* fontOptions = cairo_font_options_create();
     60  cairo_font_face_t* fontFace = CreateCairoFontFace(fontOptions);
     61  if (!fontFace) {
     62    cairo_font_options_destroy(fontOptions);
     63    return nullptr;
     64  }
     65 
     66  cairo_matrix_t sizeMatrix;
     67  cairo_matrix_t identityMatrix;
     68 
     69  cairo_matrix_init_scale(&sizeMatrix, mSize, mSize);
     70  cairo_matrix_init_identity(&identityMatrix);
     71 
     72  cairo_scaled_font_t* scaledFont = cairo_scaled_font_create(
     73      fontFace, &sizeMatrix, &identityMatrix, fontOptions);
     74 
     75  cairo_font_options_destroy(fontOptions);
     76  cairo_font_face_destroy(fontFace);
     77 
     78  if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
     79    cairo_scaled_font_destroy(scaledFont);
     80    return nullptr;
     81  }
     82 
     83  PrepareCairoScaledFont(scaledFont);
     84  mScaledFont = scaledFont;
     85  return mScaledFont;
     86 }
     87 
     88 SkPath ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer& aBuffer) {
     89  SkTypeface* typeFace = GetSkTypeface();
     90  MOZ_ASSERT(typeFace);
     91 
     92  SkFont font(sk_ref_sp(typeFace), SkFloatToScalar(mSize));
     93 
     94  std::vector<uint16_t> indices;
     95  indices.resize(aBuffer.mNumGlyphs);
     96  for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
     97    indices[i] = aBuffer.mGlyphs[i].mIndex;
     98  }
     99 
    100  struct Context {
    101    const Glyph* mGlyph;
    102    SkPath mPath;
    103  } ctx = {aBuffer.mGlyphs};
    104 
    105  font.getPaths(
    106      {indices.data(), indices.size()},
    107      [](const SkPath* glyphPath, const SkMatrix& scaleMatrix, void* ctxPtr) {
    108        Context& ctx = *reinterpret_cast<Context*>(ctxPtr);
    109        if (glyphPath) {
    110          SkMatrix transMatrix(scaleMatrix);
    111          transMatrix.postTranslate(SkFloatToScalar(ctx.mGlyph->mPosition.x),
    112                                    SkFloatToScalar(ctx.mGlyph->mPosition.y));
    113          ctx.mPath.addPath(*glyphPath, transMatrix);
    114        }
    115        ++ctx.mGlyph;
    116      },
    117      &ctx);
    118 
    119  return ctx.mPath;
    120 }
    121 
    122 already_AddRefed<Path> ScaledFontBase::GetPathForGlyphs(
    123    const GlyphBuffer& aBuffer, const DrawTarget* aTarget) {
    124  if (aTarget->GetBackendType() == BackendType::SKIA) {
    125    SkPath path = GetSkiaPathForGlyphs(aBuffer);
    126    return MakeAndAddRef<PathSkia>(path, FillRule::FILL_WINDING);
    127  }
    128 #ifdef USE_CAIRO
    129  if (aTarget->GetBackendType() == BackendType::CAIRO) {
    130    auto* cairoScaledFont = GetCairoScaledFont();
    131    if (!cairoScaledFont) {
    132      MOZ_ASSERT_UNREACHABLE("Invalid scaled font");
    133      return nullptr;
    134    }
    135 
    136    DrawTarget* dt = const_cast<DrawTarget*>(aTarget);
    137    cairo_t* ctx = static_cast<cairo_t*>(
    138        dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
    139 
    140    bool isNewContext = !ctx;
    141    if (!ctx) {
    142      ctx = cairo_create(DrawTargetCairo::GetDummySurface());
    143      cairo_matrix_t mat;
    144      GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
    145      cairo_set_matrix(ctx, &mat);
    146    }
    147 
    148    cairo_set_scaled_font(ctx, cairoScaledFont);
    149 
    150    // Convert our GlyphBuffer into an array of Cairo glyphs.
    151    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    152    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
    153      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
    154      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
    155      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    156    }
    157 
    158    cairo_new_path(ctx);
    159 
    160    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
    161 
    162    RefPtr<PathCairo> newPath = new PathCairo(ctx);
    163    if (isNewContext) {
    164      cairo_destroy(ctx);
    165    }
    166 
    167    return newPath.forget();
    168  }
    169 #endif
    170  RefPtr<PathBuilder> builder = aTarget->CreatePathBuilder();
    171  SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
    172  RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
    173  path->StreamToSink(builder);
    174  return builder->Finish();
    175 }
    176 
    177 void ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer& aBuffer,
    178                                         PathBuilder* aBuilder,
    179                                         const Matrix* aTransformHint) {
    180  BackendType backendType = aBuilder->GetBackendType();
    181  if (backendType == BackendType::SKIA) {
    182    PathBuilderSkia* builder = static_cast<PathBuilderSkia*>(aBuilder);
    183    builder->AppendPath(GetSkiaPathForGlyphs(aBuffer));
    184    return;
    185  }
    186 #ifdef USE_CAIRO
    187  if (backendType == BackendType::CAIRO) {
    188    auto* cairoScaledFont = GetCairoScaledFont();
    189    if (!cairoScaledFont) {
    190      MOZ_ASSERT_UNREACHABLE("Invalid scaled font");
    191      return;
    192    }
    193 
    194    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
    195    cairo_t* ctx = cairo_create(DrawTargetCairo::GetDummySurface());
    196 
    197    if (aTransformHint) {
    198      cairo_matrix_t mat;
    199      GfxMatrixToCairoMatrix(*aTransformHint, mat);
    200      cairo_set_matrix(ctx, &mat);
    201    }
    202 
    203    // Convert our GlyphBuffer into an array of Cairo glyphs.
    204    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
    205    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
    206      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
    207      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
    208      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
    209    }
    210 
    211    cairo_set_scaled_font(ctx, cairoScaledFont);
    212    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
    213 
    214    RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
    215    cairo_destroy(ctx);
    216 
    217    cairoPath->AppendPathToBuilder(builder);
    218    return;
    219  }
    220 #endif
    221  if (backendType == BackendType::RECORDING) {
    222    SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
    223    RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
    224    path->StreamToSink(aBuilder);
    225    return;
    226  }
    227  MOZ_ASSERT(false, "Path not being copied");
    228 }
    229 
    230 }  // namespace gfx
    231 }  // namespace mozilla