Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/2d/ScaledFontBase.cpp
Line
Count
Source (jump to first uncovered line)
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 "gfxPrefs.h"
10
11
#ifdef USE_SKIA
12
#include "PathSkia.h"
13
#include "skia/include/core/SkPaint.h"
14
#endif
15
16
#ifdef USE_CAIRO
17
#include "PathCairo.h"
18
#include "DrawTargetCairo.h"
19
#include "HelpersCairo.h"
20
#endif
21
22
#include <vector>
23
#include <cmath>
24
25
using namespace std;
26
27
namespace mozilla {
28
namespace gfx {
29
30
Atomic<uint32_t> UnscaledFont::sDeletionCounter(0);
31
32
UnscaledFont::~UnscaledFont()
33
0
{
34
0
  sDeletionCounter++;
35
0
}
36
37
Atomic<uint32_t> ScaledFont::sDeletionCounter(0);
38
39
ScaledFont::~ScaledFont()
40
0
{
41
0
  sDeletionCounter++;
42
0
}
43
44
AntialiasMode
45
ScaledFont::GetDefaultAAMode()
46
0
{
47
0
  if (gfxPrefs::DisableAllTextAA()) {
48
0
    return AntialiasMode::NONE;
49
0
  }
50
0
51
0
  return AntialiasMode::DEFAULT;
52
0
}
53
54
ScaledFontBase::~ScaledFontBase()
55
0
{
56
0
#ifdef USE_SKIA
57
0
  SkSafeUnref<SkTypeface>(mTypeface);
58
0
#endif
59
0
#ifdef USE_CAIRO_SCALED_FONT
60
0
  cairo_scaled_font_destroy(mScaledFont);
61
0
#endif
62
0
}
63
64
ScaledFontBase::ScaledFontBase(const RefPtr<UnscaledFont>& aUnscaledFont,
65
                               Float aSize)
66
  : ScaledFont(aUnscaledFont)
67
#ifdef USE_SKIA
68
  , mTypeface(nullptr)
69
#endif
70
#ifdef USE_CAIRO_SCALED_FONT
71
  , mScaledFont(nullptr)
72
#endif
73
  , mSize(aSize)
74
0
{
75
0
}
76
77
#ifdef USE_SKIA
78
SkTypeface*
79
ScaledFontBase::GetSkTypeface()
80
0
{
81
0
  if (!mTypeface) {
82
0
    SkTypeface* typeface = CreateSkTypeface();
83
0
    if (!mTypeface.compareExchange(nullptr, typeface)) {
84
0
        SkSafeUnref(typeface);
85
0
    }
86
0
  }
87
0
  return mTypeface;
88
0
}
89
#endif
90
91
#ifdef USE_CAIRO_SCALED_FONT
92
bool
93
ScaledFontBase::PopulateCairoScaledFont()
94
0
{
95
0
  cairo_font_face_t* cairoFontFace = GetCairoFontFace();
96
0
  if (!cairoFontFace) {
97
0
    return false;
98
0
  }
99
0
100
0
  cairo_matrix_t sizeMatrix;
101
0
  cairo_matrix_t identityMatrix;
102
0
103
0
  cairo_matrix_init_scale(&sizeMatrix, mSize, mSize);
104
0
  cairo_matrix_init_identity(&identityMatrix);
105
0
106
0
  cairo_font_options_t *fontOptions = cairo_font_options_create();
107
0
108
0
  mScaledFont = cairo_scaled_font_create(cairoFontFace, &sizeMatrix,
109
0
    &identityMatrix, fontOptions);
110
0
111
0
  cairo_font_options_destroy(fontOptions);
112
0
  cairo_font_face_destroy(cairoFontFace);
113
0
114
0
  return (cairo_scaled_font_status(mScaledFont) == CAIRO_STATUS_SUCCESS);
115
0
}
116
#endif
117
118
#ifdef USE_SKIA
119
SkPath
120
ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer &aBuffer)
121
0
{
122
0
  SkTypeface *typeFace = GetSkTypeface();
123
0
  MOZ_ASSERT(typeFace);
124
0
125
0
  SkPaint paint;
126
0
  paint.setTypeface(sk_ref_sp(typeFace));
127
0
  paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
128
0
  paint.setTextSize(SkFloatToScalar(mSize));
129
0
130
0
  std::vector<uint16_t> indices;
131
0
  std::vector<SkPoint> offsets;
132
0
  indices.resize(aBuffer.mNumGlyphs);
133
0
  offsets.resize(aBuffer.mNumGlyphs);
134
0
135
0
  for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
136
0
    indices[i] = aBuffer.mGlyphs[i].mIndex;
137
0
    offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
138
0
    offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
139
0
  }
140
0
141
0
  SkPath path;
142
0
  paint.getPosTextPath(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), &path);
143
0
  return path;
144
0
}
145
#endif
146
147
already_AddRefed<Path>
148
ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
149
0
{
150
0
#ifdef USE_SKIA
151
0
  if (aTarget->GetBackendType() == BackendType::SKIA) {
152
0
    SkPath path = GetSkiaPathForGlyphs(aBuffer);
153
0
    return MakeAndAddRef<PathSkia>(path, FillRule::FILL_WINDING);
154
0
  }
155
0
#endif
156
0
#ifdef USE_CAIRO
157
0
  if (aTarget->GetBackendType() == BackendType::CAIRO) {
158
0
    MOZ_ASSERT(mScaledFont);
159
0
160
0
    DrawTarget *dt = const_cast<DrawTarget*>(aTarget);
161
0
    cairo_t *ctx = static_cast<cairo_t*>(dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
162
0
163
0
    bool isNewContext = !ctx;
164
0
    if (!ctx) {
165
0
      ctx = cairo_create(DrawTargetCairo::GetDummySurface());
166
0
      cairo_matrix_t mat;
167
0
      GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
168
0
      cairo_set_matrix(ctx, &mat);
169
0
    }
170
0
171
0
    cairo_set_scaled_font(ctx, mScaledFont);
172
0
173
0
    // Convert our GlyphBuffer into an array of Cairo glyphs.
174
0
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
175
0
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
176
0
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
177
0
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
178
0
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
179
0
    }
180
0
181
0
    cairo_new_path(ctx);
182
0
183
0
    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
184
0
185
0
    RefPtr<PathCairo> newPath = new PathCairo(ctx);
186
0
    if (isNewContext) {
187
0
      cairo_destroy(ctx);
188
0
    }
189
0
190
0
    return newPath.forget();
191
0
  }
192
0
#endif
193
0
#ifdef USE_SKIA
194
0
  RefPtr<PathBuilder> builder = aTarget->CreatePathBuilder();
195
0
  SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
196
0
  RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
197
0
  path->StreamToSink(builder);
198
0
  return builder->Finish();
199
0
#endif
200
0
  return nullptr;
201
0
}
202
203
void
204
ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, const Matrix *aTransformHint)
205
0
{
206
0
  BackendType backendType = aBuilder->GetBackendType();
207
0
#ifdef USE_SKIA
208
0
  if (backendType == BackendType::SKIA) {
209
0
    PathBuilderSkia *builder = static_cast<PathBuilderSkia*>(aBuilder);
210
0
    builder->AppendPath(GetSkiaPathForGlyphs(aBuffer));
211
0
    return;
212
0
  }
213
0
#endif
214
0
#ifdef USE_CAIRO
215
0
  if (backendType == BackendType::CAIRO) {
216
0
    MOZ_ASSERT(mScaledFont);
217
0
218
0
    PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
219
0
    cairo_t *ctx = cairo_create(DrawTargetCairo::GetDummySurface());
220
0
221
0
    if (aTransformHint) {
222
0
      cairo_matrix_t mat;
223
0
      GfxMatrixToCairoMatrix(*aTransformHint, mat);
224
0
      cairo_set_matrix(ctx, &mat);
225
0
    }
226
0
227
0
    // Convert our GlyphBuffer into an array of Cairo glyphs.
228
0
    std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
229
0
    for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
230
0
      glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
231
0
      glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
232
0
      glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
233
0
    }
234
0
235
0
    cairo_set_scaled_font(ctx, mScaledFont);
236
0
    cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
237
0
238
0
    RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
239
0
    cairo_destroy(ctx);
240
0
241
0
    cairoPath->AppendPathToBuilder(builder);
242
0
    return;
243
0
  }
244
0
#endif
245
0
#ifdef USE_SKIA
246
0
  if (backendType == BackendType::RECORDING) {
247
0
    SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
248
0
    RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
249
0
    path->StreamToSink(aBuilder);
250
0
    return;
251
0
  }
252
0
#endif
253
0
  MOZ_ASSERT(false, "Path not being copied");
254
0
}
255
256
void
257
ScaledFontBase::GetGlyphDesignMetrics(const uint16_t* aGlyphs, uint32_t aNumGlyphs, GlyphMetrics* aGlyphMetrics)
258
0
{
259
0
#ifdef USE_CAIRO_SCALED_FONT
260
0
  if (mScaledFont) {
261
0
    for (uint32_t i = 0; i < aNumGlyphs; i++) {
262
0
      cairo_glyph_t glyph;
263
0
      cairo_text_extents_t extents;
264
0
      glyph.index = aGlyphs[i];
265
0
      glyph.x = 0;
266
0
      glyph.y = 0;
267
0
268
0
      cairo_scaled_font_glyph_extents(mScaledFont, &glyph, 1, &extents);
269
0
270
0
      aGlyphMetrics[i].mXBearing = extents.x_bearing;
271
0
      aGlyphMetrics[i].mXAdvance = extents.x_advance;
272
0
      aGlyphMetrics[i].mYBearing = extents.y_bearing;
273
0
      aGlyphMetrics[i].mYAdvance = extents.y_advance;
274
0
      aGlyphMetrics[i].mWidth = extents.width;
275
0
      aGlyphMetrics[i].mHeight = extents.height;
276
0
277
0
      cairo_font_options_t *options = cairo_font_options_create();
278
0
      cairo_scaled_font_get_font_options(mScaledFont, options);
279
0
280
0
      if (cairo_font_options_get_antialias(options) != CAIRO_ANTIALIAS_NONE) {
281
0
        if (cairo_scaled_font_get_type(mScaledFont) == CAIRO_FONT_TYPE_WIN32) {
282
0
          if (aGlyphMetrics[i].mWidth > 0 && aGlyphMetrics[i].mHeight > 0) {
283
0
            aGlyphMetrics[i].mWidth -= 3.0f;
284
0
            aGlyphMetrics[i].mXBearing += 1.0f;
285
0
          }
286
0
        }
287
#if defined(MOZ2D_HAS_MOZ_CAIRO) && defined(CAIRO_HAS_DWRITE_FONT)
288
        else if (cairo_scaled_font_get_type(mScaledFont) == CAIRO_FONT_TYPE_DWRITE) {
289
          if (aGlyphMetrics[i].mWidth > 0 && aGlyphMetrics[i].mHeight > 0) {
290
            aGlyphMetrics[i].mWidth -= 2.0f;
291
            aGlyphMetrics[i].mXBearing += 1.0f;
292
          }
293
        }
294
#endif
295
      }
296
0
      cairo_font_options_destroy(options);
297
0
    }
298
0
    return;
299
0
  }
300
0
#endif
301
0
302
0
  // Don't know how to get the glyph metrics...
303
0
  MOZ_CRASH("The specific backend type is not supported for GetGlyphDesignMetrics.");
304
0
}
305
306
307
#ifdef USE_CAIRO_SCALED_FONT
308
void
309
ScaledFontBase::SetCairoScaledFont(cairo_scaled_font_t* font)
310
0
{
311
0
  MOZ_ASSERT(!mScaledFont);
312
0
313
0
  if (font == mScaledFont)
314
0
    return;
315
0
316
0
  if (mScaledFont)
317
0
    cairo_scaled_font_destroy(mScaledFont);
318
0
319
0
  mScaledFont = font;
320
0
  cairo_scaled_font_reference(mScaledFont);
321
0
}
322
#endif
323
324
} // namespace gfx
325
} // namespace mozilla