mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
2b03a82ba0
This removes a lot of old cruft in thebes to instantiate Cairo scaled fonts. Instead, we only instantiate the Cairo scaled font inside Moz2D when we actually need it for DrawTargetCairo. This thus gets rid of the duplicated code we had inside both Moz2D and thebes to deal with Cairo scaled fonts. Differential Revision: https://phabricator.services.mozilla.com/D47297 --HG-- extra : moz-landing-system : lando
253 lines
6.9 KiB
C++
253 lines
6.9 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "ScaledFontBase.h"
|
|
|
|
#ifdef USE_SKIA
|
|
# include "PathSkia.h"
|
|
# include "skia/include/core/SkFont.h"
|
|
#endif
|
|
|
|
#ifdef USE_CAIRO
|
|
# include "PathCairo.h"
|
|
# include "DrawTargetCairo.h"
|
|
# include "HelpersCairo.h"
|
|
#endif
|
|
|
|
#include <vector>
|
|
#include <cmath>
|
|
|
|
namespace mozilla {
|
|
namespace gfx {
|
|
|
|
Atomic<uint32_t> UnscaledFont::sDeletionCounter(0);
|
|
|
|
UnscaledFont::~UnscaledFont() { sDeletionCounter++; }
|
|
|
|
Atomic<uint32_t> ScaledFont::sDeletionCounter(0);
|
|
|
|
ScaledFont::~ScaledFont() { sDeletionCounter++; }
|
|
|
|
ScaledFontBase::~ScaledFontBase() {
|
|
#ifdef USE_SKIA
|
|
SkSafeUnref<SkTypeface>(mTypeface);
|
|
#endif
|
|
#ifdef USE_CAIRO_SCALED_FONT
|
|
cairo_scaled_font_destroy(mScaledFont);
|
|
#endif
|
|
}
|
|
|
|
ScaledFontBase::ScaledFontBase(const RefPtr<UnscaledFont>& aUnscaledFont,
|
|
Float aSize)
|
|
: ScaledFont(aUnscaledFont)
|
|
#ifdef USE_SKIA
|
|
,
|
|
mTypeface(nullptr)
|
|
#endif
|
|
#ifdef USE_CAIRO_SCALED_FONT
|
|
,
|
|
mScaledFont(nullptr)
|
|
#endif
|
|
,
|
|
mSize(aSize) {
|
|
}
|
|
|
|
#ifdef USE_SKIA
|
|
SkTypeface* ScaledFontBase::GetSkTypeface() {
|
|
if (!mTypeface) {
|
|
SkTypeface* typeface = CreateSkTypeface();
|
|
if (!mTypeface.compareExchange(nullptr, typeface)) {
|
|
SkSafeUnref(typeface);
|
|
}
|
|
}
|
|
return mTypeface;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_CAIRO_SCALED_FONT
|
|
cairo_scaled_font_t* ScaledFontBase::GetCairoScaledFont() {
|
|
if (mScaledFont) {
|
|
return mScaledFont;
|
|
}
|
|
|
|
cairo_font_options_t* fontOptions = cairo_font_options_create();
|
|
cairo_font_face_t* fontFace = CreateCairoFontFace(fontOptions);
|
|
if (!fontFace) {
|
|
cairo_font_options_destroy(fontOptions);
|
|
return nullptr;
|
|
}
|
|
|
|
cairo_matrix_t sizeMatrix;
|
|
cairo_matrix_t identityMatrix;
|
|
|
|
cairo_matrix_init_scale(&sizeMatrix, mSize, mSize);
|
|
cairo_matrix_init_identity(&identityMatrix);
|
|
|
|
cairo_scaled_font_t* scaledFont = cairo_scaled_font_create(
|
|
fontFace, &sizeMatrix, &identityMatrix, fontOptions);
|
|
|
|
cairo_font_options_destroy(fontOptions);
|
|
cairo_font_face_destroy(fontFace);
|
|
|
|
if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
|
|
cairo_scaled_font_destroy(scaledFont);
|
|
return nullptr;
|
|
}
|
|
|
|
PrepareCairoScaledFont(scaledFont);
|
|
mScaledFont = scaledFont;
|
|
return mScaledFont;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SKIA
|
|
SkPath ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer& aBuffer) {
|
|
SkTypeface* typeFace = GetSkTypeface();
|
|
MOZ_ASSERT(typeFace);
|
|
|
|
SkFont font(sk_ref_sp(typeFace), SkFloatToScalar(mSize));
|
|
|
|
std::vector<uint16_t> indices;
|
|
indices.resize(aBuffer.mNumGlyphs);
|
|
for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
|
|
indices[i] = aBuffer.mGlyphs[i].mIndex;
|
|
}
|
|
|
|
struct Context {
|
|
const Glyph* mGlyph;
|
|
SkPath mPath;
|
|
} ctx = {aBuffer.mGlyphs};
|
|
|
|
font.getPaths(
|
|
indices.data(), indices.size(),
|
|
[](const SkPath* glyphPath, const SkMatrix& scaleMatrix, void* ctxPtr) {
|
|
Context& ctx = *reinterpret_cast<Context*>(ctxPtr);
|
|
if (glyphPath) {
|
|
SkMatrix transMatrix(scaleMatrix);
|
|
transMatrix.postTranslate(SkFloatToScalar(ctx.mGlyph->mPosition.x),
|
|
SkFloatToScalar(ctx.mGlyph->mPosition.y));
|
|
ctx.mPath.addPath(*glyphPath, transMatrix);
|
|
}
|
|
++ctx.mGlyph;
|
|
},
|
|
&ctx);
|
|
|
|
return ctx.mPath;
|
|
}
|
|
#endif
|
|
|
|
already_AddRefed<Path> ScaledFontBase::GetPathForGlyphs(
|
|
const GlyphBuffer& aBuffer, const DrawTarget* aTarget) {
|
|
#ifdef USE_SKIA
|
|
if (aTarget->GetBackendType() == BackendType::SKIA) {
|
|
SkPath path = GetSkiaPathForGlyphs(aBuffer);
|
|
return MakeAndAddRef<PathSkia>(path, FillRule::FILL_WINDING);
|
|
}
|
|
#endif
|
|
#ifdef USE_CAIRO
|
|
if (aTarget->GetBackendType() == BackendType::CAIRO) {
|
|
MOZ_ASSERT(mScaledFont);
|
|
|
|
DrawTarget* dt = const_cast<DrawTarget*>(aTarget);
|
|
cairo_t* ctx = static_cast<cairo_t*>(
|
|
dt->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT));
|
|
|
|
bool isNewContext = !ctx;
|
|
if (!ctx) {
|
|
ctx = cairo_create(DrawTargetCairo::GetDummySurface());
|
|
cairo_matrix_t mat;
|
|
GfxMatrixToCairoMatrix(aTarget->GetTransform(), mat);
|
|
cairo_set_matrix(ctx, &mat);
|
|
}
|
|
|
|
cairo_set_scaled_font(ctx, mScaledFont);
|
|
|
|
// Convert our GlyphBuffer into an array of Cairo glyphs.
|
|
std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
|
|
for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
|
|
glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
|
|
glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
|
|
glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
|
|
}
|
|
|
|
cairo_new_path(ctx);
|
|
|
|
cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
|
|
|
|
RefPtr<PathCairo> newPath = new PathCairo(ctx);
|
|
if (isNewContext) {
|
|
cairo_destroy(ctx);
|
|
}
|
|
|
|
return newPath.forget();
|
|
}
|
|
#endif
|
|
#ifdef USE_SKIA
|
|
RefPtr<PathBuilder> builder = aTarget->CreatePathBuilder();
|
|
SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
|
|
RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
|
|
path->StreamToSink(builder);
|
|
return builder->Finish();
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
void ScaledFontBase::CopyGlyphsToBuilder(const GlyphBuffer& aBuffer,
|
|
PathBuilder* aBuilder,
|
|
const Matrix* aTransformHint) {
|
|
BackendType backendType = aBuilder->GetBackendType();
|
|
#ifdef USE_SKIA
|
|
if (backendType == BackendType::SKIA) {
|
|
PathBuilderSkia* builder = static_cast<PathBuilderSkia*>(aBuilder);
|
|
builder->AppendPath(GetSkiaPathForGlyphs(aBuffer));
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef USE_CAIRO
|
|
if (backendType == BackendType::CAIRO) {
|
|
MOZ_ASSERT(mScaledFont);
|
|
|
|
PathBuilderCairo* builder = static_cast<PathBuilderCairo*>(aBuilder);
|
|
cairo_t* ctx = cairo_create(DrawTargetCairo::GetDummySurface());
|
|
|
|
if (aTransformHint) {
|
|
cairo_matrix_t mat;
|
|
GfxMatrixToCairoMatrix(*aTransformHint, mat);
|
|
cairo_set_matrix(ctx, &mat);
|
|
}
|
|
|
|
// Convert our GlyphBuffer into an array of Cairo glyphs.
|
|
std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
|
|
for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
|
|
glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
|
|
glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
|
|
glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
|
|
}
|
|
|
|
cairo_set_scaled_font(ctx, mScaledFont);
|
|
cairo_glyph_path(ctx, &glyphs[0], aBuffer.mNumGlyphs);
|
|
|
|
RefPtr<PathCairo> cairoPath = new PathCairo(ctx);
|
|
cairo_destroy(ctx);
|
|
|
|
cairoPath->AppendPathToBuilder(builder);
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef USE_SKIA
|
|
if (backendType == BackendType::RECORDING) {
|
|
SkPath skPath = GetSkiaPathForGlyphs(aBuffer);
|
|
RefPtr<Path> path = MakeAndAddRef<PathSkia>(skPath, FillRule::FILL_WINDING);
|
|
path->StreamToSink(aBuilder);
|
|
return;
|
|
}
|
|
#endif
|
|
MOZ_ASSERT(false, "Path not being copied");
|
|
}
|
|
|
|
} // namespace gfx
|
|
} // namespace mozilla
|