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