1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "SkShaper.h"
8 #include "SkStream.h"
9 #include "SkTextBlob.h"
10 #include "SkTypeface.h"
11 
12 struct SkShaper::Impl {
13     sk_sp<SkTypeface> fTypeface;
14 };
15 
SkShaper(sk_sp<SkTypeface> tf)16 SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
17     fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
18 }
19 
~SkShaper()20 SkShaper::~SkShaper() {}
21 
good() const22 bool SkShaper::good() const { return true; }
23 
24 // This example only uses public API, so we don't use SkUTF8_NextUnichar.
utf8_lead_byte_to_count(const char * ptr)25 unsigned utf8_lead_byte_to_count(const char* ptr) {
26     uint8_t c = *(const uint8_t*)ptr;
27     SkASSERT(c <= 0xF7);
28     SkASSERT((c & 0xC0) != 0x80);
29     return (((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1;
30 }
31 
shape(SkTextBlobBuilder * builder,const SkPaint & srcPaint,const char * utf8text,size_t textBytes,bool leftToRight,SkPoint point,SkScalar width) const32 SkPoint SkShaper::shape(SkTextBlobBuilder* builder,
33                         const SkPaint& srcPaint,
34                         const char* utf8text,
35                         size_t textBytes,
36                         bool leftToRight,
37                         SkPoint point,
38                         SkScalar width) const {
39     sk_ignore_unused_variable(leftToRight);
40 
41     SkPaint paint(srcPaint);
42     paint.setTypeface(fImpl->fTypeface);
43     paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
44     int glyphCount = paint.countText(utf8text, textBytes);
45     if (glyphCount <= 0) {
46         return point;
47     }
48     SkRect bounds;
49     SkPaint::FontMetrics metrics;
50     paint.getFontMetrics(&metrics);
51     point.fY -= metrics.fAscent;
52     (void)paint.measureText(utf8text, textBytes, &bounds);
53     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
54     const SkTextBlobBuilder::RunBuffer& runBuffer =
55         builder->allocRunTextPosH(paint, glyphCount, point.y(), textBytes, SkString(), &bounds);
56     memcpy(runBuffer.utf8text, utf8text, textBytes);
57     const char* txtPtr = utf8text;
58     for (int i = 0; i < glyphCount; ++i) {
59         // Each charater maps to exactly one glyph via SkGlyphCache::unicharToGlyph().
60         runBuffer.clusters[i] = SkToU32(txtPtr - utf8text);
61         txtPtr += utf8_lead_byte_to_count(txtPtr);
62         SkASSERT(txtPtr <= utf8text + textBytes);
63     }
64     paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
65     (void)paint.textToGlyphs(utf8text, textBytes, runBuffer.glyphs);
66     (void)paint.getTextWidths(utf8text, textBytes, runBuffer.pos);
67     SkScalar x = point.x();
68     for (int i = 0; i < glyphCount; ++i) {
69         SkScalar w = runBuffer.pos[i];
70         runBuffer.pos[i] = x;
71         x += w;
72     }
73     point.fY += metrics.fDescent + metrics.fLeading;
74 
75     return point;
76 }
77