skia2/gm/colrv1.cpp

98 lines
2.7 KiB
C++
Raw Normal View History

Support COLRv1 color fonts Implement support for COLRv1 color gradient vector forms. COLR v1 is an extension to the OpenType COLR tables that introduces support for gradients, transforms and compositing. [1] COLRv1 fonts contain an OpenType COLR table with format v1. In a COLR v1 table, glyphs are defined by a directed, acyclic graph of Paint operations. The task for the Skia implementation is to extract the COLR v1 information from the font using FreeType's COLRv1 API, then traverse the glyph graph and translate information from the font into Skia operations on SkCanvas. Care needs to be taken for transformations to work correctly. FreeType sends a top level transform that includes the scaling from font units to actual glyph size, as well as optional transforms configured on FreeType using FT_Set_Transform. This is set up as the starting transform at the beginning of drawing a COLRv1 glyph. At the stage of setting a clip for a PaintGlyph operation, the glyph outline is retrieved from FreeType unscaled and untransformed. Since the starting transformation is applied to the SkCanvas, the unscaled glyph is properly scaled and positioned. Similarly, computing the initial bounding box for the COLRv1 glyph needs to consider transformations. COLRv1 glyphs have a base glyph entry in the glyf table which can use a minimum of two points for defining a bounding box. This bounding box is an imaged rectangle enclosing those two points at the identity transform. We need to compute the bounding box scaled, but at identity transform, then make a rectangle from it, that we then transform so that we get a large enough area to paint in. If those two points from the glyf table would be transformed first, then we would compute the bounding box, the resulting bounding box ends up too small. As a test font, add a version of the samples-glyf_colr_1.ttf from [2] with one glyph added for testing PaintColrGlyph functionality and compositions. Add a basic GM test that produces color glyphs untransformed, with skew and with rotation and combinations of those. [1] https://github.com/googlefonts/colr-gradients-spec/ [2] https://github.com/googlefonts/color-fonts Bug: skia:11264 Change-Id: I8357cd0c7ac0039bb2eac18f21fa343bf61871eb Reviewed-on: https://skia-review.googlesource.com/c/skia/+/300558 Commit-Queue: Dominik Röttsches <drott@chromium.org> Commit-Queue: Ben Wagner <bungeman@google.com> Auto-Submit: Dominik Röttsches <drott@chromium.org> Reviewed-by: Ben Wagner <bungeman@google.com>
2021-02-11 19:08:44 +00:00
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm/gm.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontMetrics.h"
#include "include/core/SkPaint.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"
#include <string.h>
#include <initializer_list>
namespace skiagm {
class ColrV1GM : public GM {
public:
ColrV1GM(SkScalar skewX, SkScalar rotateDeg) : fSkewX(skewX), fRotateDeg(rotateDeg) { }
protected:
struct EmojiFont {
sk_sp<SkTypeface> fTypeface;
const uint16_t fGlyphs[9] = {19, 33, 34, 20, 21, 22, 23, 24, 25 };
const size_t fGlyphs_bytesize =
SK_ARRAY_COUNT(fGlyphs) * sizeof(uint16_t);
} fEmojiFont;
void onOnceBeforeDraw() override {
fEmojiFont.fTypeface =
MakeResourceAsTypeface("fonts/colrv1_samples.ttf");
}
SkString onShortName() override {
if (fSkewX != 0 || fRotateDeg != 0) {
return SkStringPrintf("colrv1_skew_%g_rotate_%g",
fSkewX,
fRotateDeg);
}
return SkString("colrv1");
}
SkISize onISize() override { return SkISize::Make(1200, 600); }
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
canvas->drawColor(SK_ColorWHITE);
SkPaint paint;
canvas->translate(200, 20);
if (!fEmojiFont.fTypeface) {
*errorMsg = "Did not recognize COLR v1 font format.";
return DrawResult::kSkip;
}
canvas->rotate(fRotateDeg);
canvas->skew(fSkewX, 0);
SkFont font(fEmojiFont.fTypeface);
SkFontMetrics metrics;
SkScalar y = 0;
for (SkScalar textSize : { 12, 18, 30, 120 }) {
font.setSize(textSize);
font.getMetrics(&metrics);
y += -metrics.fAscent;
canvas->drawSimpleText(fEmojiFont.fGlyphs,
fEmojiFont.fGlyphs_bytesize,
SkTextEncoding::kGlyphID,
10, y, font, paint);
y += metrics.fDescent + metrics.fLeading;
}
return DrawResult::kOk;
}
private:
using INHERITED = GM;
SkScalar fSkewX;
SkScalar fRotateDeg;
};
DEF_GM(return new ColrV1GM(0.f, 0.f);)
DEF_GM(return new ColrV1GM(-0.5f, 0.f);)
DEF_GM(return new ColrV1GM(0.f, 20.f);)
DEF_GM(return new ColrV1GM(-0.5f, 20.f);)
} // namespace skiagm