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 "PathSkia.h"
11 # include "skia/include/core/SkFont.h"
15 # include "PathCairo.h"
16 # include "DrawTargetCairo.h"
17 # include "HelpersCairo.h"
26 Atomic
<uint32_t> UnscaledFont::sDeletionCounter(0);
28 UnscaledFont::~UnscaledFont() { sDeletionCounter
++; }
30 Atomic
<uint32_t> ScaledFont::sDeletionCounter(0);
32 ScaledFont::~ScaledFont() { sDeletionCounter
++; }
34 ScaledFontBase::~ScaledFontBase() {
36 SkSafeUnref
<SkTypeface
>(mTypeface
);
38 #ifdef USE_CAIRO_SCALED_FONT
39 cairo_scaled_font_destroy(mScaledFont
);
43 ScaledFontBase::ScaledFontBase(const RefPtr
<UnscaledFont
>& aUnscaledFont
,
45 : ScaledFont(aUnscaledFont
)
50 #ifdef USE_CAIRO_SCALED_FONT
59 SkTypeface
* ScaledFontBase::GetSkTypeface() {
61 SkTypeface
* typeface
= CreateSkTypeface();
62 if (!mTypeface
.compareExchange(nullptr, typeface
)) {
63 SkSafeUnref(typeface
);
70 #ifdef USE_CAIRO_SCALED_FONT
71 cairo_scaled_font_t
* ScaledFontBase::GetCairoScaledFont() {
76 cairo_font_options_t
* fontOptions
= cairo_font_options_create();
77 cairo_font_face_t
* fontFace
= CreateCairoFontFace(fontOptions
);
79 cairo_font_options_destroy(fontOptions
);
83 cairo_matrix_t sizeMatrix
;
84 cairo_matrix_t identityMatrix
;
86 cairo_matrix_init_scale(&sizeMatrix
, mSize
, mSize
);
87 cairo_matrix_init_identity(&identityMatrix
);
89 cairo_scaled_font_t
* scaledFont
= cairo_scaled_font_create(
90 fontFace
, &sizeMatrix
, &identityMatrix
, fontOptions
);
92 cairo_font_options_destroy(fontOptions
);
93 cairo_font_face_destroy(fontFace
);
95 if (cairo_scaled_font_status(scaledFont
) != CAIRO_STATUS_SUCCESS
) {
96 cairo_scaled_font_destroy(scaledFont
);
100 PrepareCairoScaledFont(scaledFont
);
101 mScaledFont
= scaledFont
;
107 SkPath
ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer
& aBuffer
) {
108 SkTypeface
* typeFace
= GetSkTypeface();
109 MOZ_ASSERT(typeFace
);
111 SkFont
font(sk_ref_sp(typeFace
), SkFloatToScalar(mSize
));
113 std::vector
<uint16_t> indices
;
114 indices
.resize(aBuffer
.mNumGlyphs
);
115 for (unsigned int i
= 0; i
< aBuffer
.mNumGlyphs
; i
++) {
116 indices
[i
] = aBuffer
.mGlyphs
[i
].mIndex
;
122 } ctx
= {aBuffer
.mGlyphs
};
125 indices
.data(), indices
.size(),
126 [](const SkPath
* glyphPath
, const SkMatrix
& scaleMatrix
, void* ctxPtr
) {
127 Context
& ctx
= *reinterpret_cast<Context
*>(ctxPtr
);
129 SkMatrix
transMatrix(scaleMatrix
);
130 transMatrix
.postTranslate(SkFloatToScalar(ctx
.mGlyph
->mPosition
.x
),
131 SkFloatToScalar(ctx
.mGlyph
->mPosition
.y
));
132 ctx
.mPath
.addPath(*glyphPath
, transMatrix
);
142 already_AddRefed
<Path
> ScaledFontBase::GetPathForGlyphs(
143 const GlyphBuffer
& aBuffer
, const DrawTarget
* aTarget
) {
145 if (aTarget
->GetBackendType() == BackendType::SKIA
) {
146 SkPath path
= GetSkiaPathForGlyphs(aBuffer
);
147 return MakeAndAddRef
<PathSkia
>(path
, FillRule::FILL_WINDING
);
151 if (aTarget
->GetBackendType() == BackendType::CAIRO
) {
152 MOZ_ASSERT(mScaledFont
);
154 DrawTarget
* dt
= const_cast<DrawTarget
*>(aTarget
);
155 cairo_t
* ctx
= static_cast<cairo_t
*>(
156 dt
->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT
));
158 bool isNewContext
= !ctx
;
160 ctx
= cairo_create(DrawTargetCairo::GetDummySurface());
162 GfxMatrixToCairoMatrix(aTarget
->GetTransform(), mat
);
163 cairo_set_matrix(ctx
, &mat
);
166 cairo_set_scaled_font(ctx
, mScaledFont
);
168 // Convert our GlyphBuffer into an array of Cairo glyphs.
169 std::vector
<cairo_glyph_t
> glyphs(aBuffer
.mNumGlyphs
);
170 for (uint32_t i
= 0; i
< aBuffer
.mNumGlyphs
; ++i
) {
171 glyphs
[i
].index
= aBuffer
.mGlyphs
[i
].mIndex
;
172 glyphs
[i
].x
= aBuffer
.mGlyphs
[i
].mPosition
.x
;
173 glyphs
[i
].y
= aBuffer
.mGlyphs
[i
].mPosition
.y
;
178 cairo_glyph_path(ctx
, &glyphs
[0], aBuffer
.mNumGlyphs
);
180 RefPtr
<PathCairo
> newPath
= new PathCairo(ctx
);
185 return newPath
.forget();
189 RefPtr
<PathBuilder
> builder
= aTarget
->CreatePathBuilder();
190 SkPath skPath
= GetSkiaPathForGlyphs(aBuffer
);
191 RefPtr
<Path
> path
= MakeAndAddRef
<PathSkia
>(skPath
, FillRule::FILL_WINDING
);
192 path
->StreamToSink(builder
);
193 return builder
->Finish();
198 void ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer
& aBuffer
,
199 PathBuilder
* aBuilder
,
200 const Matrix
* aTransformHint
) {
201 BackendType backendType
= aBuilder
->GetBackendType();
203 if (backendType
== BackendType::SKIA
) {
204 PathBuilderSkia
* builder
= static_cast<PathBuilderSkia
*>(aBuilder
);
205 builder
->AppendPath(GetSkiaPathForGlyphs(aBuffer
));
210 if (backendType
== BackendType::CAIRO
) {
211 MOZ_ASSERT(mScaledFont
);
213 PathBuilderCairo
* builder
= static_cast<PathBuilderCairo
*>(aBuilder
);
214 cairo_t
* ctx
= cairo_create(DrawTargetCairo::GetDummySurface());
216 if (aTransformHint
) {
218 GfxMatrixToCairoMatrix(*aTransformHint
, mat
);
219 cairo_set_matrix(ctx
, &mat
);
222 // Convert our GlyphBuffer into an array of Cairo glyphs.
223 std::vector
<cairo_glyph_t
> glyphs(aBuffer
.mNumGlyphs
);
224 for (uint32_t i
= 0; i
< aBuffer
.mNumGlyphs
; ++i
) {
225 glyphs
[i
].index
= aBuffer
.mGlyphs
[i
].mIndex
;
226 glyphs
[i
].x
= aBuffer
.mGlyphs
[i
].mPosition
.x
;
227 glyphs
[i
].y
= aBuffer
.mGlyphs
[i
].mPosition
.y
;
230 cairo_set_scaled_font(ctx
, mScaledFont
);
231 cairo_glyph_path(ctx
, &glyphs
[0], aBuffer
.mNumGlyphs
);
233 RefPtr
<PathCairo
> cairoPath
= new PathCairo(ctx
);
236 cairoPath
->AppendPathToBuilder(builder
);
241 if (backendType
== BackendType::RECORDING
) {
242 SkPath skPath
= GetSkiaPathForGlyphs(aBuffer
);
243 RefPtr
<Path
> path
= MakeAndAddRef
<PathSkia
>(skPath
, FillRule::FILL_WINDING
);
244 path
->StreamToSink(aBuilder
);
248 MOZ_ASSERT(false, "Path not being copied");
252 } // namespace mozilla