1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2014 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
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrStencilAndCoverTextContext.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrAtlasTextContext.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrContext.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrPath.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrPathRange.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrRenderTargetContext.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrResourceProvider.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrTextUtils.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkAutoKern.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDraw.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDrawFilter.h"
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDrawProcs.h"
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGlyphCache.h"
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGr.h"
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPath.h"
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPointPriv.h"
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTextBlobRunIterator.h"
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTextFormatParams.h"
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTextMapStateProc.h"
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "ops/GrDrawPathOp.h"
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate<typename Key, typename Val> static void delete_hash_map_entry(const Key&, Val* val) {
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(*val);
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    delete *val;
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate<typename T> static void delete_hash_table_entry(T* val) {
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(*val);
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    delete *val;
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrAtlasTextContext* fallbackTextContext)
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : fFallbackTextContext(fallbackTextContext)
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fCacheSize(0) {
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrStencilAndCoverTextContext*
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrStencilAndCoverTextContext::Create(GrAtlasTextContext* fallbackTextContext) {
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return new GrStencilAndCoverTextContext(fallbackTextContext);;
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() {
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBlobIdCache.foreach(delete_hash_map_entry<uint32_t, TextBlob*>);
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBlobKeyCache.foreach(delete_hash_table_entry<TextBlob*>);
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) {
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (skPaint.getMaskFilter()) {
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkPathEffect* pe = skPaint.getPathEffect()) {
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) {
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // No hairlines. They would require new paths with customized strokes for every new draw matrix.
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrokeWidth();
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::drawText(GrContext* context, GrRenderTargetContext* rtc,
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            const GrClip& clip, const SkPaint& skPaint,
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            const SkMatrix& viewMatrix, const SkSurfaceProps& props,
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            const char text[], size_t byteLength, SkScalar x,
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            SkScalar y, const SkIRect& clipBounds) {
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (context->abandoned()) {
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (this->canDraw(skPaint, viewMatrix)) {
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (skPaint.getTextSize() > 0) {
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            TextRun run(skPaint);
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            run.setText(text, byteLength, x, y);
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            run.draw(context, rtc, clip, viewMatrix, props, 0, 0, clipBounds, fFallbackTextContext,
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     skPaint);
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFallbackTextContext->drawText(context, rtc->textTarget(), clip, skPaint, viewMatrix, props,
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                   text, byteLength, x, y, clipBounds);
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::drawPosText(GrContext* context, GrRenderTargetContext* rtc,
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                               const GrClip& clip, const SkPaint& skPaint,
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                               const SkMatrix& viewMatrix,
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                               const SkSurfaceProps& props, const char text[],
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                               size_t byteLength, const SkScalar pos[],
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                               int scalarsPerPosition, const SkPoint& offset,
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                               const SkIRect& clipBounds) {
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (context->abandoned()) {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (this->canDraw(skPaint, viewMatrix)) {
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (skPaint.getTextSize() > 0) {
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            TextRun run(skPaint);
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            run.setPosText(text, byteLength, pos, scalarsPerPosition, offset);
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            run.draw(context, rtc, clip, viewMatrix, props, 0, 0, clipBounds, fFallbackTextContext,
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                     skPaint);
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFallbackTextContext->drawPosText(context, rtc->textTarget(), clip, skPaint, viewMatrix, props,
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                      text, byteLength, pos, scalarsPerPosition, offset,
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                      clipBounds);
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrContext* context,
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        GrRenderTargetContext* rtc,
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        const GrClip& clip,
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        const SkPaint& skPaint,
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        const SkMatrix& viewMatrix,
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        const SkSurfaceProps& props,
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        const SkTextBlob* blob,
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        SkScalar x, SkScalar y,
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        SkDrawFilter* drawFilter,
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                        const SkIRect& clipBounds) {
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrTextUtils::Paint paint(&skPaint, &rtc->colorSpaceInfo());
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrTextUtils::RunPaint runPaint(&paint, drawFilter, props);
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTextBlobRunIterator it(blob);
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (;!it.done(); it.next()) {
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!runPaint.modifyForRun(it)) {
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t textLen = it.glyphCount() * sizeof(uint16_t);
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint& offset = it.offset();
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        switch (it.positioning()) {
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkTextBlob::kDefault_Positioning:
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->drawText(context, rtc, clip, runPaint, viewMatrix, props,
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                               (const char*)it.glyphs(), textLen, x + offset.x(), y + offset.y(),
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                               clipBounds);
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkTextBlob::kHorizontal_Positioning:
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->drawPosText(context, rtc, clip, runPaint, viewMatrix, props,
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                  (const char*)it.glyphs(), textLen, it.pos(), 1,
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                  SkPoint::Make(x, y + offset.y()), clipBounds);
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkTextBlob::kFull_Positioning:
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->drawPosText(context, rtc, clip, runPaint, viewMatrix, props,
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                  (const char*)it.glyphs(), textLen, it.pos(), 2,
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                  SkPoint::Make(x, y), clipBounds);
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrRenderTargetContext* rtc,
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                const GrClip& clip, const SkPaint& skPaint,
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                const SkMatrix& viewMatrix,
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                const SkSurfaceProps& props,
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                const SkTextBlob* skBlob, SkScalar x, SkScalar y,
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                SkDrawFilter* drawFilter,
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                const SkIRect& clipBounds) {
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (context->abandoned()) {
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!this->internalCanDraw(skPaint)) {
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFallbackTextContext->drawTextBlob(context, rtc->textTarget(), clip, skPaint, viewMatrix,
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                           props, skBlob, x, y, drawFilter, clipBounds);
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (drawFilter || skPaint.getPathEffect()) {
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // This draw can't be cached.
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->uncachedDrawTextBlob(context, rtc, clip, skPaint, viewMatrix, props, skBlob, x, y,
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                   drawFilter, clipBounds);
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint);
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    TextBlob::Iter iter(blob);
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (TextRun *run = iter.get(), *nextRun; run; run = nextRun) {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        nextRun = iter.next();
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        run->draw(context, rtc, clip, viewMatrix, props, x, y, clipBounds, fFallbackTextContext,
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                  skPaint);
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        run->releaseGlyphCache();
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic inline int style_key_cnt(const GrStyle& style) {
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int cnt = GrStyle::KeySize(style, GrStyle::Apply::kPathEffectAndStrokeRec);
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We should be able to make a key because we filtered out arbitrary path effects.
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(cnt > 0);
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return cnt;
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic inline void write_style_key(uint32_t* dst, const GrStyle& style) {
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Pass 1 for the scale since the GPU will apply the style not GrStyle::applyToPath().
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrStyle::WriteKey(dst, style, GrStyle::Apply::kPathEffectAndStrokeRec, SK_Scalar1);
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst GrStencilAndCoverTextContext::TextBlob&
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   const SkPaint& skPaint) {
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // The font-related parameters are baked into the text blob and will override this skPaint, so
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // the only remaining properties that can affect a TextBlob are the ones related to stroke.
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkPaint::kFill_Style == skPaint.getStyle()) { // Fast path.
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (TextBlob** found = fBlobIdCache.find(skBlob->uniqueID())) {
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLRUList.remove(*found);
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLRUList.addToTail(*found);
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return **found;
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint);
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->purgeToFit(*blob);
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlobIdCache.set(skBlob->uniqueID(), blob);
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fLRUList.addToTail(blob);
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCacheSize += blob->cpuMemorySize();
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *blob;
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrStyle style(skPaint);
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkSTArray<4, uint32_t, true> key;
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        key.reset(1 + style_key_cnt(style));
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        key[0] = skBlob->uniqueID();
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        write_style_key(&key[1], style);
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (TextBlob** found = fBlobKeyCache.find(key)) {
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLRUList.remove(*found);
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLRUList.addToTail(*found);
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return **found;
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TextBlob* blob = new TextBlob(key, skBlob, skPaint);
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->purgeToFit(*blob);
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlobKeyCache.set(blob);
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fLRUList.addToTail(blob);
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCacheSize += blob->cpuMemorySize();
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *blob;
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::purgeToFit(const TextBlob& blob) {
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const size_t maxCacheSize = 4 * 1024 * 1024; // Allow up to 4 MB for caching text blobs.
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize();
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (fCacheSize && fCacheSize > maxSizeForNewBlob) {
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TextBlob* lru = fLRUList.head();
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (1 == lru->key().count()) {
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // 1-length keys are unterstood to be the blob id.
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlobIdCache.remove(lru->key()[0]);
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlobKeyCache.remove(lru->key());
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fLRUList.remove(lru);
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCacheSize -= lru->cpuMemorySize();
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        delete lru;
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot////////////////////////////////////////////////////////////////////////////////////////////////////
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob,
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                  const SkPaint& skPaint) {
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCpuMemorySize = sizeof(TextBlob);
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint runPaint(skPaint);
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (SkTextBlobRunIterator iter(skBlob); !iter.done(); iter.next()) {
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        iter.applyFontToPaint(&runPaint); // No need to re-seed the paint.
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (runPaint.getTextSize() <= 0) {
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TextRun* run = this->addToTail(runPaint);
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* text = reinterpret_cast<const char*>(iter.glyphs());
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t byteLength = sizeof(uint16_t) * iter.glyphCount();
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint& runOffset = iter.offset();
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        switch (iter.positioning()) {
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkTextBlob::kDefault_Positioning:
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                run->setText(text, byteLength, runOffset.fX, runOffset.fY);
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkTextBlob::kHorizontal_Positioning:
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0, runOffset.fY));
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkTextBlob::kFull_Positioning:
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0, 0));
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCpuMemorySize += run->computeSizeInCache();
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot////////////////////////////////////////////////////////////////////////////////////////////////////
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass GrStencilAndCoverTextContext::FallbackBlobBuilder {
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FallbackBlobBuilder() : fBuffIdx(0), fCount(0) {}
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isInitialized() const { return fBuilder != nullptr; }
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void init(const SkPaint& font, SkScalar textRatio);
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void appendGlyph(uint16_t glyphId, const SkPoint& pos);
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkTextBlob> makeIfNeeded(int* count);
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    enum { kWriteBufferSize = 1024 };
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void flush();
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    std::unique_ptr<SkTextBlobBuilder> fBuilder;
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint                            fFont;
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int                                fBuffIdx;
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int                                fCount;
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint16_t                           fGlyphIds[kWriteBufferSize];
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint                            fPositions[kWriteBufferSize];
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot////////////////////////////////////////////////////////////////////////////////////////////////////
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : fStyle(fontAndStroke)
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fFont(fontAndStroke)
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fTotalGlyphCount(0)
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fFallbackGlyphCount(0)
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fDetachedGlyphCache(nullptr)
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fLastDrawnGlyphsID(SK_InvalidUniqueID) {
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fFont.getTextSize() > 0);
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fStyle.hasNonDashPathEffect()); // Arbitrary path effects not supported.
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!fStyle.isSimpleHairline()); // Hairlines are not supported.
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Setting to "fill" ensures that no strokes get baked into font outlines. (We use the GPU path
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // rendering API for stroking).
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFont.setStyle(SkPaint::kFill_Style);
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fFont.isFakeBoldText() && fStyle.isSimpleFill()) {
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkStrokeRec& stroke = fStyle.strokeRec();
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Instead of letting fake bold get baked into the glyph outlines, do it with GPU stroke.
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(),
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    kStdFakeBoldInterpKeys,
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    kStdFakeBoldInterpValues,
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    kStdFakeBoldInterpLength);
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar extra = fFont.getTextSize() * fakeBoldScale;
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle);
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        strokeRec.setStrokeStyle(stroke.needToApply() ? stroke.getWidth() + extra : extra,
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                 true /*strokeAndFill*/);
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fStyle = GrStyle(strokeRec, fStyle.refPathEffect());
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFont.setFakeBoldText(false);
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fFont.getPathEffect() && !fStyle.isDashed()) {
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkStrokeRec& stroke = fStyle.strokeRec();
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We can draw the glyphs from canonically sized paths.
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextSize();
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Compensate for the glyphs being scaled by fTextRatio.
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fStyle.isSimpleFill()) {
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkStrokeRec strokeRec(SkStrokeRec::kFill_InitStyle);
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            strokeRec.setStrokeStyle(stroke.getWidth() / fTextRatio,
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                     SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle());
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fStyle = GrStyle(strokeRec, fStyle.refPathEffect());
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFont.setLinearText(true);
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFont.setLCDRenderText(false);
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFont.setAutohinted(false);
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFont.setHinting(SkPaint::kNo_Hinting);
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFont.setSubpixelText(true);
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFont.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() &&
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              0 == fFont.getTextSkewX() &&
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              !fFont.isFakeBoldText() &&
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              !fFont.isVerticalText();
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTextRatio = fTextInverseRatio = 1.0f;
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fUsingRawGlyphPaths = false;
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Generate the key that will be used to cache the GPU glyph path objects.
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fUsingRawGlyphPaths && fStyle.isSimpleFill()) {
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::GenerateDomain();
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkTypeface* typeface = fFont.getTypeface();
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrUniqueKey::Builder builder(&fGlyphPathsKey, kRawFillPathGlyphDomain, 1);
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDomain();
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int styleDataCount = GrStyle::KeySize(fStyle, GrStyle::Apply::kPathEffectAndStrokeRec);
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Key should be valid since we opted out of drawing arbitrary path effects.
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(styleDataCount >= 0);
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fUsingRawGlyphPaths) {
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkTypeface* typeface = fFont.getTypeface();
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + styleDataCount);
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount;
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (styleDataCount) {
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                write_style_key(&builder[2], fStyle);
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkGlyphCache* glyphCache = this->getGlyphCache();
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkTypeface* typeface = glyphCache->getScalerContext()->getTypeface();
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkDescriptor* desc = &glyphCache->getDescriptor();
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int descDataCount = (desc->getLength() + 3) / 4;
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain,
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         2 + styleDataCount + descDataCount);
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID() : 0;
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            reinterpret_cast<uint32_t&>(builder[1]) = styleDataCount | (descDataCount << 16);
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (styleDataCount) {
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                write_style_key(&builder[2], fStyle);
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memcpy(&builder[2 + styleDataCount], desc, desc->getLength());
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrStencilAndCoverTextContext::TextRun::~TextRun() {
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->releaseGlyphCache();
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t byteLength,
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    SkScalar x, SkScalar y) {
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(byteLength == 0 || text != nullptr);
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkGlyphCache* glyphCache = this->getGlyphCache();
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(fFont.getTextEncoding(),
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                        fFont.isDevKernText(),
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                        true);
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTotalGlyphCount = fFont.countText(text, byteLength);
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType,
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            fTotalGlyphCount));
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* stop = text + byteLength;
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Measure first if needed.
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fFont.getTextAlign() != SkPaint::kLeft_Align) {
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar   stopX = 0;
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar   stopY = 0;
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* textPtr = text;
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (textPtr < stop) {
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // We don't need x, y here, since all subpixel variants will have the
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // same advance.
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkGlyph& glyph = glyphCacheProc(glyphCache, &textPtr);
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            stopX += SkFloatToScalar(glyph.fAdvanceX);
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            stopY += SkFloatToScalar(glyph.fAdvanceY);
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(textPtr == stop);
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar alignX = stopX * fTextRatio;
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar alignY = stopY * fTextRatio;
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fFont.getTextAlign() == SkPaint::kCenter_Align) {
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            alignX = SkScalarHalf(alignX);
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            alignY = SkScalarHalf(alignY);
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        x -= alignX;
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        y -= alignY;
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkAutoKern autokern;
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FallbackBlobBuilder fallback;
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (text < stop) {
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkGlyph& glyph = glyphCacheProc(glyphCache, &text);
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        x += autokern.adjust(glyph) * fTextRatio;
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glyph.fWidth) {
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->appendGlyph(glyph, SkPoint::Make(x, y), &fallback);
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        x += SkFloatToScalar(glyph.fAdvanceX) * fTextRatio;
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        y += SkFloatToScalar(glyph.fAdvanceY) * fTextRatio;
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFallbackTextBlob = fallback.makeIfNeeded(&fFallbackGlyphCount);
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength,
479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                       const SkScalar pos[], int scalarsPerPosition,
480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                       const SkPoint& offset) {
481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(byteLength == 0 || text != nullptr);
482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkGlyphCache* glyphCache = this->getGlyphCache();
485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(fFont.getTextEncoding(),
486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                        fFont.isDevKernText(),
487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                        true);
488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTotalGlyphCount = fFont.countText(text, byteLength);
490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType,
491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            fTotalGlyphCount));
492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* stop = text + byteLength;
494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTextAlignProc alignProc(fFont.getTextAlign());
497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FallbackBlobBuilder fallback;
498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (text < stop) {
499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkGlyph& glyph = glyphCacheProc(glyphCache, &text);
500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glyph.fWidth) {
501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkPoint tmsLoc;
502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            tmsProc(pos, &tmsLoc);
503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkPoint loc;
504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            alignProc(tmsLoc, glyph, &loc);
505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->appendGlyph(glyph, loc, &fallback);
507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        pos += scalarsPerPosition;
509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFallbackTextBlob = fallback.makeIfNeeded(&fFallbackGlyphCount);
512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<GrPathRange> GrStencilAndCoverTextContext::TextRun::createGlyphs(
515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    GrResourceProvider* resourceProvider) const {
516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<GrPathRange> glyphs =
517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            resourceProvider->findByUniqueKey<GrPathRange>(fGlyphPathsKey);
518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!glyphs) {
519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fUsingRawGlyphPaths) {
520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkScalerContextEffects noeffects;
521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            glyphs = resourceProvider->createGlyphs(fFont.getTypeface(), noeffects,
522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    nullptr, fStyle);
523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkGlyphCache* cache = this->getGlyphCache();
525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            glyphs = resourceProvider->createGlyphs(cache->getScalerContext()->getTypeface(),
526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    cache->getScalerContext()->getEffects(),
527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    &cache->getDescriptor(),
528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    fStyle);
529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        resourceProvider->assignUniqueKeyToResource(fGlyphPathsKey, glyphs.get());
531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return glyphs;
533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotinline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& glyph,
536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                               const SkPoint& pos,
537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                               FallbackBlobBuilder* fallback) {
538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Stick the glyphs we can't draw into the fallback text blob.
539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fallback->isInitialized()) {
541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fallback->init(fFont, fTextRatio);
542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fallback->appendGlyph(glyph.getGlyphID(), pos);
544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fInstanceData->append(glyph.getGlyphID(), fTextInverseRatio * pos.x(),
546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              fTextInverseRatio * pos.y());
547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 GrRenderTargetContext* renderTargetContext,
552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 const GrClip& clip, const SkMatrix& viewMatrix,
553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 const SkSurfaceProps& props, SkScalar x,
554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 SkScalar y, const SkIRect& clipBounds,
555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 GrAtlasTextContext* fallbackTextContext,
556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 const SkPaint& originalSkPaint) const {
557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fInstanceData);
558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fInstanceData->count()) {
560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sk_sp<GrPathRange> glyphs(this->createGlyphs(ctx->contextPriv().resourceProvider()));
561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fLastDrawnGlyphsID != glyphs->uniqueID()) {
562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Either this is the first draw or the glyphs object was purged since last draw.
563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->count());
564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fLastDrawnGlyphsID = glyphs->uniqueID();
565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrPaint grPaint;
568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!SkPaintToGrPaint(ctx, renderTargetContext->colorSpaceInfo(), originalSkPaint,
569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              viewMatrix, &grPaint)) {
570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // the entire dst. Realistically this is a moot point, because any context that supports
575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // NV_path_rendering will also support NV_blend_equation_advanced.
576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // For clipping we'll just skip any optimizations based on the bounds. This does, however,
577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // hurt GrOp combining.
578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkRect bounds = SkRect::MakeIWH(renderTargetContext->width(),
579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                              renderTargetContext->height());
580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // The run's "font" overrides the anti-aliasing of the passed in SkPaint!
582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrAAType aaType = GrChooseAAType(this->aa(), renderTargetContext->fsaaType(),
583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         GrAllowMixedSamples::kYes, *renderTargetContext->caps());
584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::unique_ptr<GrDrawOp> op = GrDrawPathRangeOp::Make(
586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y,
587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                std::move(grPaint), GrPathRendering::kWinding_FillType, aaType, glyphs.get(),
588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fInstanceData.get(), bounds);
589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        renderTargetContext->addDrawOp(clip, std::move(op));
591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fFallbackTextBlob) {
594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPaint fallbackSkPaint(originalSkPaint);
595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fStyle.strokeRec().applyToPaint(&fallbackSkPaint);
596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fStyle.isSimpleFill()) {
597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fallbackSkPaint.setStrokeWidth(fStyle.strokeRec().getWidth() * fTextRatio);
598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fallbackTextContext->drawTextBlob(ctx, renderTargetContext->textTarget(), clip,
601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                          fallbackSkPaint, viewMatrix, props,
602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                          fFallbackTextBlob.get(), x, y, nullptr, clipBounds);
603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkGlyphCache* GrStencilAndCoverTextContext::TextRun::getGlyphCache() const {
607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fDetachedGlyphCache) {
608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDetachedGlyphCache = SkGlyphCache::DetachCacheUsingPaint(fFont, nullptr,
609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                  SkScalerContextFlags::kNone,
610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                  nullptr);
611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fDetachedGlyphCache;
613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::TextRun::releaseGlyphCache() const {
617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDetachedGlyphCache) {
618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkGlyphCache::AttachCache(fDetachedGlyphCache);
619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDetachedGlyphCache = nullptr;
620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t GrStencilAndCoverTextContext::TextRun::computeSizeInCache() const {
624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t size = sizeof(TextRun) + fGlyphPathsKey.size();
625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // The instance data always reserves enough space for every glyph.
626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size += (fTotalGlyphCount + fFallbackGlyphCount) * (sizeof(uint16_t) + 2 * sizeof(float));
627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fInstanceData) {
628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size += sizeof(InstanceData);
629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fFallbackTextBlob) {
631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size += sizeof(SkTextBlob);
632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return size;
634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot////////////////////////////////////////////////////////////////////////////////////////////////////
637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font,
639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                             SkScalar textRatio) {
640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!this->isInitialized());
641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBuilder.reset(new SkTextBlobBuilder);
642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFont = font;
643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will already account for align.
644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color glyphs
646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved.
647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFont.setSubpixelText(false);
648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFont.setTextSize(fFont.getTextSize() * textRatio);
649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBuffIdx = 0;
650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::FallbackBlobBuilder::appendGlyph(uint16_t glyphId,
653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    const SkPoint& pos) {
654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInitialized());
655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fBuffIdx >= kWriteBufferSize) {
656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->flush();
657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fGlyphIds[fBuffIdx] = glyphId;
659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPositions[fBuffIdx] = pos;
660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBuffIdx++;
661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCount++;
662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() {
665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->isInitialized());
666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fBuffIdx <= kWriteBufferSize);
667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fBuffIdx) {
668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // This will automatically merge with previous runs since we use the same font.
671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkTextBlobBuilder::RunBuffer& buff = fBuilder->allocRunPos(fFont, fBuffIdx);
672fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(buff.glyphs, fGlyphIds, fBuffIdx * sizeof(uint16_t));
673fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(buff.pos, SkPointPriv::AsScalars(fPositions[0]), fBuffIdx * 2 * sizeof(SkScalar));
674fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBuffIdx = 0;
675fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
676fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
677fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkTextBlob> GrStencilAndCoverTextContext::FallbackBlobBuilder::makeIfNeeded(int *count) {
678fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *count = fCount;
679fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fCount) {
680fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->flush();
681fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fBuilder->make();
682fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
683fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return nullptr;
684fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
685