no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / gfx / 2d / ScaledFontBase.cpp
blobcd52df3ccd61c8fcdae2694047059bef8c89e66d
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/. */
7 #include "ScaledFontBase.h"
9 #include "PathSkia.h"
10 #include "skia/include/core/SkFont.h"
12 #ifdef USE_CAIRO
13 # include "PathCairo.h"
14 # include "DrawTargetCairo.h"
15 # include "HelpersCairo.h"
16 #endif
18 #include <vector>
19 #include <cmath>
21 namespace mozilla {
22 namespace gfx {
24 Atomic<uint32_t> UnscaledFont::sDeletionCounter(0);
26 UnscaledFont::~UnscaledFont() { sDeletionCounter++; }
28 Atomic<uint32_t> ScaledFont::sDeletionCounter(0);
30 ScaledFont::~ScaledFont() { sDeletionCounter++; }
32 ScaledFontBase::~ScaledFontBase() {
33 SkSafeUnref<SkTypeface>(mTypeface);
34 cairo_scaled_font_destroy(mScaledFont);
37 ScaledFontBase::ScaledFontBase(const RefPtr<UnscaledFont>& aUnscaledFont,
38 Float aSize)
39 : ScaledFont(aUnscaledFont),
40 mTypeface(nullptr),
41 mScaledFont(nullptr),
42 mSize(aSize) {}
44 SkTypeface* ScaledFontBase::GetSkTypeface() {
45 if (!mTypeface) {
46 SkTypeface* typeface = CreateSkTypeface();
47 if (!mTypeface.compareExchange(nullptr, typeface)) {
48 SkSafeUnref(typeface);
51 return mTypeface;
54 cairo_scaled_font_t* ScaledFontBase::GetCairoScaledFont() {
55 if (mScaledFont) {
56 return mScaledFont;
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;
66 cairo_matrix_t sizeMatrix;
67 cairo_matrix_t identityMatrix;
69 cairo_matrix_init_scale(&sizeMatrix, mSize, mSize);
70 cairo_matrix_init_identity(&identityMatrix);
72 cairo_scaled_font_t* scaledFont = cairo_scaled_font_create(
73 fontFace, &sizeMatrix, &identityMatrix, fontOptions);
75 cairo_font_options_destroy(fontOptions);
76 cairo_font_face_destroy(fontFace);
78 if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
79 cairo_scaled_font_destroy(scaledFont);
80 return nullptr;
83 PrepareCairoScaledFont(scaledFont);
84 mScaledFont = scaledFont;
85 return mScaledFont;
88 SkPath ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer& aBuffer) {
89 SkTypeface* typeFace = GetSkTypeface();
90 MOZ_ASSERT(typeFace);
92 SkFont font(sk_ref_sp(typeFace), SkFloatToScalar(mSize));
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;
100 struct Context {
101 const Glyph* mGlyph;
102 SkPath mPath;
103 } ctx = {aBuffer.mGlyphs};
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);
115 ++ctx.mGlyph;
117 &ctx);
119 return ctx.mPath;
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);
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;
136 DrawTarget* dt = const_cast<DrawTarget*>(aTarget);
137 cairo_t* ctx = static_cast<cairo_t*>(
138 dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
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);
148 cairo_set_scaled_font(ctx, cairoScaledFont);
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;
158 cairo_new_path(ctx);
160 cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
162 RefPtr<PathCairo> newPath = new PathCairo(ctx);
163 if (isNewContext) {
164 cairo_destroy(ctx);
167 return newPath.forget();
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();
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;
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;
194 PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
195 cairo_t* ctx = cairo_create(DrawTargetCairo::GetDummySurface());
197 if (aTransformHint) {
198 cairo_matrix_t mat;
199 GfxMatrixToCairoMatrix(*aTransformHint, mat);
200 cairo_set_matrix(ctx, &mat);
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;
211 cairo_set_scaled_font(ctx, cairoScaledFont);
212 cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
214 RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
215 cairo_destroy(ctx);
217 cairoPath->AppendPathToBuilder(builder);
218 return;
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;
227 MOZ_ASSERT(false, "Path not being copied");
230 } // namespace gfx
231 } // namespace mozilla