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