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
12struct SkShaper::Impl {
13    sk_sp<SkTypeface> fTypeface;
14};
15
16SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
17    fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
18}
19
20SkShaper::~SkShaper() {}
21
22bool SkShaper::good() const { return true; }
23
24// This example only uses public API, so we don't use SkUTF8_NextUnichar.
25unsigned 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
32SkPoint 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