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"
10 #include "skia/include/core/SkFont.h"
13 # include "PathCairo.h"
14 # include "DrawTargetCairo.h"
15 # include "HelpersCairo.h"
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
,
39 : ScaledFont(aUnscaledFont
),
44 SkTypeface
* ScaledFontBase::GetSkTypeface() {
46 SkTypeface
* typeface
= CreateSkTypeface();
47 if (!mTypeface
.compareExchange(nullptr, typeface
)) {
48 SkSafeUnref(typeface
);
54 cairo_scaled_font_t
* ScaledFontBase::GetCairoScaledFont() {
59 cairo_font_options_t
* fontOptions
= cairo_font_options_create();
60 cairo_font_face_t
* fontFace
= CreateCairoFontFace(fontOptions
);
62 cairo_font_options_destroy(fontOptions
);
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
);
83 PrepareCairoScaledFont(scaledFont
);
84 mScaledFont
= scaledFont
;
88 SkPath
ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer
& aBuffer
) {
89 SkTypeface
* typeFace
= GetSkTypeface();
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
;
103 } ctx
= {aBuffer
.mGlyphs
};
106 indices
.data(), indices
.size(),
107 [](const SkPath
* glyphPath
, const SkMatrix
& scaleMatrix
, void* ctxPtr
) {
108 Context
& ctx
= *reinterpret_cast<Context
*>(ctxPtr
);
110 SkMatrix
transMatrix(scaleMatrix
);
111 transMatrix
.postTranslate(SkFloatToScalar(ctx
.mGlyph
->mPosition
.x
),
112 SkFloatToScalar(ctx
.mGlyph
->mPosition
.y
));
113 ctx
.mPath
.addPath(*glyphPath
, transMatrix
);
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
);
129 if (aTarget
->GetBackendType() == BackendType::CAIRO
) {
130 auto* cairoScaledFont
= GetCairoScaledFont();
131 if (!cairoScaledFont
) {
132 MOZ_ASSERT_UNREACHABLE("Invalid scaled font");
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
;
142 ctx
= cairo_create(DrawTargetCairo::GetDummySurface());
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
;
160 cairo_glyph_path(ctx
, &glyphs
[0], aBuffer
.mNumGlyphs
);
162 RefPtr
<PathCairo
> newPath
= new PathCairo(ctx
);
167 return newPath
.forget();
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
));
187 if (backendType
== BackendType::CAIRO
) {
188 auto* cairoScaledFont
= GetCairoScaledFont();
189 if (!cairoScaledFont
) {
190 MOZ_ASSERT_UNREACHABLE("Invalid scaled font");
194 PathBuilderCairo
* builder
= static_cast<PathBuilderCairo
*>(aBuilder
);
195 cairo_t
* ctx
= cairo_create(DrawTargetCairo::GetDummySurface());
197 if (aTransformHint
) {
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
);
217 cairoPath
->AppendPathToBuilder(builder
);
221 if (backendType
== BackendType::RECORDING
) {
222 SkPath skPath
= GetSkiaPathForGlyphs(aBuffer
);
223 RefPtr
<Path
> path
= MakeAndAddRef
<PathSkia
>(skPath
, FillRule::FILL_WINDING
);
224 path
->StreamToSink(aBuilder
);
227 MOZ_ASSERT(false, "Path not being copied");
231 } // namespace mozilla