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