1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/core/SkGlyph.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h"
11cb93a386Sopenharmony_ci#include "src/core/SkScalerContext.h"
12cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCubic.h"
13cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsQuad.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ciSkMask SkGlyph::mask() const {
16cb93a386Sopenharmony_ci    SkMask mask;
17cb93a386Sopenharmony_ci    mask.fImage = (uint8_t*)fImage;
18cb93a386Sopenharmony_ci    mask.fBounds.setXYWH(fLeft, fTop, fWidth, fHeight);
19cb93a386Sopenharmony_ci    mask.fRowBytes = this->rowBytes();
20cb93a386Sopenharmony_ci    mask.fFormat = fMaskFormat;
21cb93a386Sopenharmony_ci    return mask;
22cb93a386Sopenharmony_ci}
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ciSkMask SkGlyph::mask(SkPoint position) const {
25cb93a386Sopenharmony_ci    SkMask answer = this->mask();
26cb93a386Sopenharmony_ci    answer.fBounds.offset(SkScalarFloorToInt(position.x()), SkScalarFloorToInt(position.y()));
27cb93a386Sopenharmony_ci    return answer;
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_civoid SkGlyph::zeroMetrics() {
31cb93a386Sopenharmony_ci    fAdvanceX = 0;
32cb93a386Sopenharmony_ci    fAdvanceY = 0;
33cb93a386Sopenharmony_ci    fWidth    = 0;
34cb93a386Sopenharmony_ci    fHeight   = 0;
35cb93a386Sopenharmony_ci    fTop      = 0;
36cb93a386Sopenharmony_ci    fLeft     = 0;
37cb93a386Sopenharmony_ci}
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_cistatic size_t bits_to_bytes(size_t bits) {
40cb93a386Sopenharmony_ci    return (bits + 7) >> 3;
41cb93a386Sopenharmony_ci}
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_cistatic size_t format_alignment(SkMask::Format format) {
44cb93a386Sopenharmony_ci    switch (format) {
45cb93a386Sopenharmony_ci        case SkMask::kBW_Format:
46cb93a386Sopenharmony_ci        case SkMask::kA8_Format:
47cb93a386Sopenharmony_ci        case SkMask::k3D_Format:
48cb93a386Sopenharmony_ci        case SkMask::kSDF_Format:
49cb93a386Sopenharmony_ci            return alignof(uint8_t);
50cb93a386Sopenharmony_ci        case SkMask::kARGB32_Format:
51cb93a386Sopenharmony_ci            return alignof(uint32_t);
52cb93a386Sopenharmony_ci        case SkMask::kLCD16_Format:
53cb93a386Sopenharmony_ci            return alignof(uint16_t);
54cb93a386Sopenharmony_ci        default:
55cb93a386Sopenharmony_ci            SK_ABORT("Unknown mask format.");
56cb93a386Sopenharmony_ci            break;
57cb93a386Sopenharmony_ci    }
58cb93a386Sopenharmony_ci    return 0;
59cb93a386Sopenharmony_ci}
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_cistatic size_t format_rowbytes(int width, SkMask::Format format) {
62cb93a386Sopenharmony_ci    return format == SkMask::kBW_Format ? bits_to_bytes(width)
63cb93a386Sopenharmony_ci                                        : width * format_alignment(format);
64cb93a386Sopenharmony_ci}
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_cisize_t SkGlyph::formatAlignment() const {
67cb93a386Sopenharmony_ci    return format_alignment(this->maskFormat());
68cb93a386Sopenharmony_ci}
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_cisize_t SkGlyph::allocImage(SkArenaAlloc* alloc) {
71cb93a386Sopenharmony_ci    SkASSERT(!this->isEmpty());
72cb93a386Sopenharmony_ci    auto size = this->imageSize();
73cb93a386Sopenharmony_ci    fImage = alloc->makeBytesAlignedTo(size, this->formatAlignment());
74cb93a386Sopenharmony_ci
75cb93a386Sopenharmony_ci    return size;
76cb93a386Sopenharmony_ci}
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_cibool SkGlyph::setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
79cb93a386Sopenharmony_ci    if (!this->setImageHasBeenCalled()) {
80cb93a386Sopenharmony_ci        // It used to be that getImage() could change the fMaskFormat. Extra checking to make
81cb93a386Sopenharmony_ci        // sure there are no regressions.
82cb93a386Sopenharmony_ci        SkDEBUGCODE(SkMask::Format oldFormat = this->maskFormat());
83cb93a386Sopenharmony_ci        this->allocImage(alloc);
84cb93a386Sopenharmony_ci        scalerContext->getImage(*this);
85cb93a386Sopenharmony_ci        SkASSERT(oldFormat == this->maskFormat());
86cb93a386Sopenharmony_ci        return true;
87cb93a386Sopenharmony_ci    }
88cb93a386Sopenharmony_ci    return false;
89cb93a386Sopenharmony_ci}
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_cibool SkGlyph::setImage(SkArenaAlloc* alloc, const void* image) {
92cb93a386Sopenharmony_ci    if (!this->setImageHasBeenCalled()) {
93cb93a386Sopenharmony_ci        this->allocImage(alloc);
94cb93a386Sopenharmony_ci        memcpy(fImage, image, this->imageSize());
95cb93a386Sopenharmony_ci        return true;
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci    return false;
98cb93a386Sopenharmony_ci}
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_cisize_t SkGlyph::setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from) {
101cb93a386Sopenharmony_ci    // Since the code no longer tries to find replacement glyphs, the image should always be
102cb93a386Sopenharmony_ci    // nullptr.
103cb93a386Sopenharmony_ci    SkASSERT(fImage == nullptr);
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci    // TODO(herb): remove "if" when we are sure there are no colliding glyphs.
106cb93a386Sopenharmony_ci    if (fImage == nullptr) {
107cb93a386Sopenharmony_ci        fAdvanceX = from.fAdvanceX;
108cb93a386Sopenharmony_ci        fAdvanceY = from.fAdvanceY;
109cb93a386Sopenharmony_ci        fWidth = from.fWidth;
110cb93a386Sopenharmony_ci        fHeight = from.fHeight;
111cb93a386Sopenharmony_ci        fTop = from.fTop;
112cb93a386Sopenharmony_ci        fLeft = from.fLeft;
113cb93a386Sopenharmony_ci        fForceBW = from.fForceBW;
114cb93a386Sopenharmony_ci        fMaskFormat = from.fMaskFormat;
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci        // From glyph may not have an image because the glyph is too large.
117cb93a386Sopenharmony_ci        if (from.fImage != nullptr && this->setImage(alloc, from.image())) {
118cb93a386Sopenharmony_ci            return this->imageSize();
119cb93a386Sopenharmony_ci        }
120cb93a386Sopenharmony_ci    }
121cb93a386Sopenharmony_ci    return 0;
122cb93a386Sopenharmony_ci}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_cisize_t SkGlyph::rowBytes() const {
125cb93a386Sopenharmony_ci    return format_rowbytes(fWidth, fMaskFormat);
126cb93a386Sopenharmony_ci}
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_cisize_t SkGlyph::rowBytesUsingFormat(SkMask::Format format) const {
129cb93a386Sopenharmony_ci    return format_rowbytes(fWidth, format);
130cb93a386Sopenharmony_ci}
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_cisize_t SkGlyph::imageSize() const {
133cb93a386Sopenharmony_ci    if (this->isEmpty() || this->imageTooLarge()) { return 0; }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    size_t size = this->rowBytes() * fHeight;
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci    if (fMaskFormat == SkMask::k3D_Format) {
138cb93a386Sopenharmony_ci        size *= 3;
139cb93a386Sopenharmony_ci    }
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    return size;
142cb93a386Sopenharmony_ci}
143cb93a386Sopenharmony_ci
144cb93a386Sopenharmony_civoid SkGlyph::installPath(SkArenaAlloc* alloc, const SkPath* path) {
145cb93a386Sopenharmony_ci    SkASSERT(fPathData == nullptr);
146cb93a386Sopenharmony_ci    SkASSERT(!this->setPathHasBeenCalled());
147cb93a386Sopenharmony_ci    fPathData = alloc->make<SkGlyph::PathData>();
148cb93a386Sopenharmony_ci    if (path != nullptr) {
149cb93a386Sopenharmony_ci        fPathData->fPath = *path;
150cb93a386Sopenharmony_ci        fPathData->fPath.updateBoundsCache();
151cb93a386Sopenharmony_ci        fPathData->fPath.getGenerationID();
152cb93a386Sopenharmony_ci        fPathData->fHasPath = true;
153cb93a386Sopenharmony_ci    }
154cb93a386Sopenharmony_ci}
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_cibool SkGlyph::setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
157cb93a386Sopenharmony_ci    if (!this->setPathHasBeenCalled()) {
158cb93a386Sopenharmony_ci        SkPath path;
159cb93a386Sopenharmony_ci        if (scalerContext->getPath(this->getPackedID(), &path)) {
160cb93a386Sopenharmony_ci            this->installPath(alloc, &path);
161cb93a386Sopenharmony_ci        } else {
162cb93a386Sopenharmony_ci            this->installPath(alloc, nullptr);
163cb93a386Sopenharmony_ci        }
164cb93a386Sopenharmony_ci        return this->path() != nullptr;
165cb93a386Sopenharmony_ci    }
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci    return false;
168cb93a386Sopenharmony_ci}
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_cibool SkGlyph::setPath(SkArenaAlloc* alloc, const SkPath* path) {
171cb93a386Sopenharmony_ci    if (!this->setPathHasBeenCalled()) {
172cb93a386Sopenharmony_ci        this->installPath(alloc, path);
173cb93a386Sopenharmony_ci        return this->path() != nullptr;
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci    return false;
176cb93a386Sopenharmony_ci}
177cb93a386Sopenharmony_ci
178cb93a386Sopenharmony_ciconst SkPath* SkGlyph::path() const {
179cb93a386Sopenharmony_ci    // setPath must have been called previously.
180cb93a386Sopenharmony_ci    SkASSERT(this->setPathHasBeenCalled());
181cb93a386Sopenharmony_ci    if (fPathData->fHasPath) {
182cb93a386Sopenharmony_ci        return &fPathData->fPath;
183cb93a386Sopenharmony_ci    }
184cb93a386Sopenharmony_ci    return nullptr;
185cb93a386Sopenharmony_ci}
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_cistatic std::tuple<SkScalar, SkScalar> calculate_path_gap(
188cb93a386Sopenharmony_ci        SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) {
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci    // Left and Right of an ever expanding gap around the path.
191cb93a386Sopenharmony_ci    SkScalar left  = SK_ScalarMax,
192cb93a386Sopenharmony_ci             right = SK_ScalarMin;
193cb93a386Sopenharmony_ci    auto expandGap = [&left, &right](SkScalar v) {
194cb93a386Sopenharmony_ci        left  = std::min(left, v);
195cb93a386Sopenharmony_ci        right = std::max(right, v);
196cb93a386Sopenharmony_ci    };
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ci    // Handle all the different verbs for the path.
199cb93a386Sopenharmony_ci    SkPoint pts[4];
200cb93a386Sopenharmony_ci    auto addLine = [&expandGap, &pts](SkScalar offset) {
201cb93a386Sopenharmony_ci        SkScalar t = sk_ieee_float_divide(offset - pts[0].fY, pts[1].fY - pts[0].fY);
202cb93a386Sopenharmony_ci        if (0 <= t && t < 1) {   // this handles divide by zero above
203cb93a386Sopenharmony_ci            expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX));
204cb93a386Sopenharmony_ci        }
205cb93a386Sopenharmony_ci    };
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_ci    auto addQuad = [&expandGap, &pts](SkScalar offset) {
208cb93a386Sopenharmony_ci        SkDQuad quad;
209cb93a386Sopenharmony_ci        quad.set(pts);
210cb93a386Sopenharmony_ci        double roots[2];
211cb93a386Sopenharmony_ci        int count = quad.horizontalIntersect(offset, roots);
212cb93a386Sopenharmony_ci        while (--count >= 0) {
213cb93a386Sopenharmony_ci            expandGap(quad.ptAtT(roots[count]).asSkPoint().fX);
214cb93a386Sopenharmony_ci        }
215cb93a386Sopenharmony_ci    };
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci    auto addCubic = [&expandGap, &pts](SkScalar offset) {
218cb93a386Sopenharmony_ci        SkDCubic cubic;
219cb93a386Sopenharmony_ci        cubic.set(pts);
220cb93a386Sopenharmony_ci        double roots[3];
221cb93a386Sopenharmony_ci        int count = cubic.horizontalIntersect(offset, roots);
222cb93a386Sopenharmony_ci        while (--count >= 0) {
223cb93a386Sopenharmony_ci            expandGap(cubic.ptAtT(roots[count]).asSkPoint().fX);
224cb93a386Sopenharmony_ci        }
225cb93a386Sopenharmony_ci    };
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    // Handle when a verb's points are in the gap between top and bottom.
228cb93a386Sopenharmony_ci    auto addPts = [&expandGap, &pts, topOffset, bottomOffset](int ptCount) {
229cb93a386Sopenharmony_ci        for (int i = 0; i < ptCount; ++i) {
230cb93a386Sopenharmony_ci            if (topOffset < pts[i].fY && pts[i].fY < bottomOffset) {
231cb93a386Sopenharmony_ci                expandGap(pts[i].fX);
232cb93a386Sopenharmony_ci            }
233cb93a386Sopenharmony_ci        }
234cb93a386Sopenharmony_ci    };
235cb93a386Sopenharmony_ci
236cb93a386Sopenharmony_ci    SkPath::Iter iter(path, false);
237cb93a386Sopenharmony_ci    SkPath::Verb verb;
238cb93a386Sopenharmony_ci    while (SkPath::kDone_Verb != (verb = iter.next(pts))) {
239cb93a386Sopenharmony_ci        switch (verb) {
240cb93a386Sopenharmony_ci            case SkPath::kMove_Verb: {
241cb93a386Sopenharmony_ci                break;
242cb93a386Sopenharmony_ci            }
243cb93a386Sopenharmony_ci            case SkPath::kLine_Verb: {
244cb93a386Sopenharmony_ci                addLine(topOffset);
245cb93a386Sopenharmony_ci                addLine(bottomOffset);
246cb93a386Sopenharmony_ci                addPts(2);
247cb93a386Sopenharmony_ci                break;
248cb93a386Sopenharmony_ci            }
249cb93a386Sopenharmony_ci            case SkPath::kQuad_Verb: {
250cb93a386Sopenharmony_ci                SkScalar quadTop = std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY);
251cb93a386Sopenharmony_ci                if (bottomOffset < quadTop) { break; }
252cb93a386Sopenharmony_ci                SkScalar quadBottom = std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY);
253cb93a386Sopenharmony_ci                if (topOffset > quadBottom) { break; }
254cb93a386Sopenharmony_ci                addQuad(topOffset);
255cb93a386Sopenharmony_ci                addQuad(bottomOffset);
256cb93a386Sopenharmony_ci                addPts(3);
257cb93a386Sopenharmony_ci                break;
258cb93a386Sopenharmony_ci            }
259cb93a386Sopenharmony_ci            case SkPath::kConic_Verb: {
260cb93a386Sopenharmony_ci                SkASSERT(0);  // no support for text composed of conics
261cb93a386Sopenharmony_ci                break;
262cb93a386Sopenharmony_ci            }
263cb93a386Sopenharmony_ci            case SkPath::kCubic_Verb: {
264cb93a386Sopenharmony_ci                SkScalar quadTop =
265cb93a386Sopenharmony_ci                        std::min(std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
266cb93a386Sopenharmony_ci                if (bottomOffset < quadTop) { break; }
267cb93a386Sopenharmony_ci                SkScalar quadBottom =
268cb93a386Sopenharmony_ci                        std::max(std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
269cb93a386Sopenharmony_ci                if (topOffset > quadBottom) { break; }
270cb93a386Sopenharmony_ci                addCubic(topOffset);
271cb93a386Sopenharmony_ci                addCubic(bottomOffset);
272cb93a386Sopenharmony_ci                addPts(4);
273cb93a386Sopenharmony_ci                break;
274cb93a386Sopenharmony_ci            }
275cb93a386Sopenharmony_ci            case SkPath::kClose_Verb: {
276cb93a386Sopenharmony_ci                break;
277cb93a386Sopenharmony_ci            }
278cb93a386Sopenharmony_ci            default: {
279cb93a386Sopenharmony_ci                SkASSERT(0);
280cb93a386Sopenharmony_ci                break;
281cb93a386Sopenharmony_ci            }
282cb93a386Sopenharmony_ci        }
283cb93a386Sopenharmony_ci    }
284cb93a386Sopenharmony_ci
285cb93a386Sopenharmony_ci    return std::tie(left, right);
286cb93a386Sopenharmony_ci}
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_civoid SkGlyph::ensureIntercepts(const SkScalar* bounds, SkScalar scale, SkScalar xPos,
289cb93a386Sopenharmony_ci                               SkScalar* array, int* count, SkArenaAlloc* alloc) {
290cb93a386Sopenharmony_ci
291cb93a386Sopenharmony_ci    auto offsetResults = [scale, xPos](
292cb93a386Sopenharmony_ci            const SkGlyph::Intercept* intercept,SkScalar* array, int* count) {
293cb93a386Sopenharmony_ci        if (array) {
294cb93a386Sopenharmony_ci            array += *count;
295cb93a386Sopenharmony_ci            for (int index = 0; index < 2; index++) {
296cb93a386Sopenharmony_ci                *array++ = intercept->fInterval[index] * scale + xPos;
297cb93a386Sopenharmony_ci            }
298cb93a386Sopenharmony_ci        }
299cb93a386Sopenharmony_ci        *count += 2;
300cb93a386Sopenharmony_ci    };
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci    const SkGlyph::Intercept* match =
303cb93a386Sopenharmony_ci            [this](const SkScalar bounds[2]) -> const SkGlyph::Intercept* {
304cb93a386Sopenharmony_ci                if (!fPathData) {
305cb93a386Sopenharmony_ci                    return nullptr;
306cb93a386Sopenharmony_ci                }
307cb93a386Sopenharmony_ci                const SkGlyph::Intercept* intercept = fPathData->fIntercept;
308cb93a386Sopenharmony_ci                while (intercept) {
309cb93a386Sopenharmony_ci                    if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) {
310cb93a386Sopenharmony_ci                        return intercept;
311cb93a386Sopenharmony_ci                    }
312cb93a386Sopenharmony_ci                    intercept = intercept->fNext;
313cb93a386Sopenharmony_ci                }
314cb93a386Sopenharmony_ci                return nullptr;
315cb93a386Sopenharmony_ci            }(bounds);
316cb93a386Sopenharmony_ci
317cb93a386Sopenharmony_ci    if (match) {
318cb93a386Sopenharmony_ci        if (match->fInterval[0] < match->fInterval[1]) {
319cb93a386Sopenharmony_ci            offsetResults(match, array, count);
320cb93a386Sopenharmony_ci        }
321cb93a386Sopenharmony_ci        return;
322cb93a386Sopenharmony_ci    }
323cb93a386Sopenharmony_ci
324cb93a386Sopenharmony_ci    SkGlyph::Intercept* intercept = alloc->make<SkGlyph::Intercept>();
325cb93a386Sopenharmony_ci    intercept->fNext = fPathData->fIntercept;
326cb93a386Sopenharmony_ci    intercept->fBounds[0] = bounds[0];
327cb93a386Sopenharmony_ci    intercept->fBounds[1] = bounds[1];
328cb93a386Sopenharmony_ci    intercept->fInterval[0] = SK_ScalarMax;
329cb93a386Sopenharmony_ci    intercept->fInterval[1] = SK_ScalarMin;
330cb93a386Sopenharmony_ci    fPathData->fIntercept = intercept;
331cb93a386Sopenharmony_ci    const SkPath* path = &(fPathData->fPath);
332cb93a386Sopenharmony_ci    const SkRect& pathBounds = path->getBounds();
333cb93a386Sopenharmony_ci    if (pathBounds.fBottom < bounds[0] || bounds[1] < pathBounds.fTop) {
334cb93a386Sopenharmony_ci        return;
335cb93a386Sopenharmony_ci    }
336cb93a386Sopenharmony_ci
337cb93a386Sopenharmony_ci    std::tie(intercept->fInterval[0], intercept->fInterval[1])
338cb93a386Sopenharmony_ci            = calculate_path_gap(bounds[0], bounds[1], *path);
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ci    if (intercept->fInterval[0] >= intercept->fInterval[1]) {
341cb93a386Sopenharmony_ci        intercept->fInterval[0] = SK_ScalarMax;
342cb93a386Sopenharmony_ci        intercept->fInterval[1] = SK_ScalarMin;
343cb93a386Sopenharmony_ci        return;
344cb93a386Sopenharmony_ci    }
345cb93a386Sopenharmony_ci    offsetResults(intercept, array, count);
346cb93a386Sopenharmony_ci}
347