1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 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 "GrAtlasTextOp.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrContext.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrOpFlushState.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrResourceProvider.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGlyphCache.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMathPriv.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMatrixPriv.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPoint3.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "effects/GrBitmapTextGeoProc.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "effects/GrDistanceFieldGeoProc.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "text/GrAtlasGlyphCache.h"
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////////////////////////
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const int kDistanceAdjustLumShift = 5;
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrAtlasTextOp::init() {
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const Geometry& geo = fGeoData[0];
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect bounds;
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    geo.fBlob->computeSubRunBounds(&bounds, geo.fRun, geo.fSubRun, geo.fViewMatrix, geo.fX, geo.fY);
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We don't have tight bounds on the glyph paths in device space. For the purposes of bounds
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // we treat this as a set of non-AA rects rendered with a texture.
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->usesDistanceFields()) {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool isLCD = this->isLCD();
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkMatrix& viewMatrix = geo.fViewMatrix;
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDFGPFlags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDFGPFlags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDFGPFlags |= viewMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDFGPFlags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDFGPFlags |= (kAliasedDistanceField_MaskType == fMaskType)
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              ? kAliased_DistanceFieldEffectFlag
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                              : 0;
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (isLCD) {
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fDFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fDFGPFlags |=
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    (kLCDBGRDistanceField_MaskType == fMaskType) ? kBGR_DistanceFieldEffectFlag : 0;
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkString GrAtlasTextOp::dumpInfo() const {
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkString str;
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fGeoCount; ++i) {
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    i,
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fGeoData[i].fColor,
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fGeoData[i].fX,
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fGeoData[i].fY,
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fGeoData[i].fBlob->runCount());
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str += fProcessors.dumpProcessors();
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    str += INHERITED::dumpInfo();
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return str;
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrDrawOp::FixedFunctionFlags GrAtlasTextOp::fixedFunctionFlags() const {
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return FixedFunctionFlags::kNone;
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotGrDrawOp::RequiresDstTexture GrAtlasTextOp::finalize(const GrCaps& caps,
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                     const GrAppliedClip* clip,
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                     GrPixelConfigIsClamped dstIsClamped) {
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrProcessorAnalysisCoverage coverage;
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrProcessorAnalysisColor color;
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (kColorBitmapMask_MaskType == fMaskType) {
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        color.setToUnknown();
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        color.setToConstant(this->color());
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (fMaskType) {
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kGrayscaleCoverageMask_MaskType:
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAliasedDistanceField_MaskType:
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kGrayscaleDistanceField_MaskType:
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coverage = GrProcessorAnalysisCoverage::kSingleChannel;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kLCDCoverageMask_MaskType:
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kLCDDistanceField_MaskType:
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kLCDBGRDistanceField_MaskType:
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coverage = GrProcessorAnalysisCoverage::kLCD;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kColorBitmapMask_MaskType:
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coverage = GrProcessorAnalysisCoverage::kNone;
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    auto analysis = fProcessors.finalize(color, coverage, clip, false, caps, dstIsClamped,
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         &fGeoData[0].fColor);
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fUsesLocalCoords = analysis.usesLocalCoords();
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCanCombineOnTouchOrOverlap =
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            !analysis.requiresDstTexture() &&
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            !(fProcessors.xferProcessor() && fProcessors.xferProcessor()->xferBarrierType(caps));
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return analysis.requiresDstTexture() ? RequiresDstTexture::kYes : RequiresDstTexture::kNo;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void clip_quads(const SkIRect& clipRect, char* currVertex, const char* blobVertices,
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                       size_t vertexStride, int glyphCount) {
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < glyphCount; ++i) {
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint* blobPositionLT = reinterpret_cast<const SkPoint*>(blobVertices);
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint* blobPositionRB =
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                reinterpret_cast<const SkPoint*>(blobVertices + 3 * vertexStride);
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // positions for bitmap glyphs are pixel boundary aligned
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkIRect positionRect = SkIRect::MakeLTRB(SkScalarRoundToInt(blobPositionLT->fX),
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 SkScalarRoundToInt(blobPositionLT->fY),
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 SkScalarRoundToInt(blobPositionRB->fX),
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 SkScalarRoundToInt(blobPositionRB->fY));
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (clipRect.contains(positionRect)) {
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memcpy(currVertex, blobVertices, 4 * vertexStride);
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currVertex += 4 * vertexStride;
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Pull out some more data that we'll need.
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // In the LCD case the color will be garbage, but we'll overwrite it with the texcoords
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // and it avoids a lot of conditionals.
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            auto color = *reinterpret_cast<const SkColor*>(blobVertices + sizeof(SkPoint));
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            size_t coordOffset = vertexStride - 2*sizeof(uint16_t);
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            auto* blobCoordsLT = reinterpret_cast<const uint16_t*>(blobVertices + coordOffset);
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            auto* blobCoordsRB = reinterpret_cast<const uint16_t*>(blobVertices + 3 * vertexStride +
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                   coordOffset);
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Pull out the texel coordinates and texture index bits
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint16_t coordsRectL = blobCoordsLT[0] >> 1;
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint16_t coordsRectT = blobCoordsLT[1] >> 1;
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint16_t coordsRectR = blobCoordsRB[0] >> 1;
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint16_t coordsRectB = blobCoordsRB[1] >> 1;
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint16_t pageIndexX = blobCoordsLT[0] & 0x1;
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint16_t pageIndexY = blobCoordsLT[1] & 0x1;
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int positionRectWidth = positionRect.width();
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int positionRectHeight = positionRect.height();
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(positionRectWidth == (coordsRectR - coordsRectL));
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(positionRectHeight == (coordsRectB - coordsRectT));
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Clip position and texCoords to the clipRect
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unsigned int delta;
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            delta = SkTMin(SkTMax(clipRect.fLeft - positionRect.fLeft, 0), positionRectWidth);
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectL += delta;
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            positionRect.fLeft += delta;
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            delta = SkTMin(SkTMax(clipRect.fTop - positionRect.fTop, 0), positionRectHeight);
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectT += delta;
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            positionRect.fTop += delta;
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            delta = SkTMin(SkTMax(positionRect.fRight - clipRect.fRight, 0), positionRectWidth);
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectR -= delta;
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            positionRect.fRight -= delta;
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            delta = SkTMin(SkTMax(positionRect.fBottom - clipRect.fBottom, 0), positionRectHeight);
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectB -= delta;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            positionRect.fBottom -= delta;
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Repack texel coordinates and index
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectL = coordsRectL << 1 | pageIndexX;
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectT = coordsRectT << 1 | pageIndexY;
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectR = coordsRectR << 1 | pageIndexX;
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coordsRectB = coordsRectB << 1 | pageIndexY;
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Set new positions and coords
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkPoint* currPosition = reinterpret_cast<SkPoint*>(currVertex);
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fX = positionRect.fLeft;
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fY = positionRect.fTop;
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            uint16_t* currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[0] = coordsRectL;
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[1] = coordsRectT;
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currVertex += vertexStride;
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition = reinterpret_cast<SkPoint*>(currVertex);
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fX = positionRect.fLeft;
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fY = positionRect.fBottom;
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[0] = coordsRectL;
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[1] = coordsRectB;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currVertex += vertexStride;
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition = reinterpret_cast<SkPoint*>(currVertex);
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fX = positionRect.fRight;
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fY = positionRect.fTop;
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[0] = coordsRectR;
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[1] = coordsRectT;
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currVertex += vertexStride;
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition = reinterpret_cast<SkPoint*>(currVertex);
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fX = positionRect.fRight;
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currPosition->fY = positionRect.fBottom;
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color;
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset);
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[0] = coordsRectR;
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currCoords[1] = coordsRectB;
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currVertex += vertexStride;
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        blobVertices += 4 * vertexStride;
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrAtlasTextOp::onPrepareDraws(Target* target) {
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // TODO actually only invert if we don't have RGBA
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMatrix localMatrix;
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->usesLocalCoords() && !fGeoData[0].fViewMatrix.invert(&localMatrix)) {
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("Cannot invert viewmatrix\n");
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrMaskFormat maskFormat = this->maskFormat();
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint32_t atlasPageCount = fFontCache->getAtlasPageCount(maskFormat);
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const sk_sp<GrTextureProxy>* proxies = fFontCache->getProxies(maskFormat);
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!atlasPageCount || !proxies[0]) {
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("Could not allocate backing texture for atlas\n");
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FlushInfo flushInfo;
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flushInfo.fPipeline =
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            target->makePipeline(fSRGBFlags, std::move(fProcessors), target->detachAppliedClip());
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(bool dfPerspective = false);
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->usesDistanceFields()) {
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        flushInfo.fGeometryProcessor = this->setupDfProcessor();
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGCODE(dfPerspective = fGeoData[0].fViewMatrix.hasPerspective());
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat,
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            localMatrix, this->usesLocalCoords());
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flushInfo.fGlyphsToFlush = 0;
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(vertexStride == GrAtlasTextBlob::GetVertexStride(maskFormat, dfPerspective));
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int glyphCount = this->numGlyphs();
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const GrBuffer* vertexBuffer;
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void* vertices = target->makeVertexSpace(
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            vertexStride, glyphCount * kVerticesPerGlyph, &vertexBuffer, &flushInfo.fVertexOffset);
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flushInfo.fIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!vertices || !flushInfo.fVertexBuffer) {
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("Could not allocate vertices\n");
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    char* currVertex = reinterpret_cast<char*>(vertices);
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkAutoGlyphCache glyphCache;
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // each of these is a SubRun
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < fGeoCount; i++) {
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const Geometry& args = fGeoData[i];
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Blob* blob = args.fBlob;
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrAtlasTextBlob::VertexRegenerator regenerator(
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                blob, args.fRun, args.fSubRun, args.fViewMatrix, args.fX, args.fY, args.fColor,
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                target->deferredUploadTarget(), fFontCache, &glyphCache);
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrAtlasTextBlob::VertexRegenerator::Result result;
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result = regenerator.regenerate();
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // Copy regenerated vertices from the blob to our vertex buffer.
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            size_t vertexBytes = result.fGlyphsRegenerated * kVerticesPerGlyph * vertexStride;
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (args.fClipRect.isEmpty()) {
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                memcpy(currVertex, result.fFirstVertex, vertexBytes);
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!dfPerspective);
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                clip_quads(args.fClipRect, currVertex, result.fFirstVertex, vertexStride,
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                           result.fGlyphsRegenerated);
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (this->usesDistanceFields() && !args.fViewMatrix.isIdentity()) {
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // We always do the distance field view matrix transformation after copying rather
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // than during blob vertex generation time in the blob as handling successive
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // arbitrary transformations would be complicated and accumulate error.
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (args.fViewMatrix.hasPerspective()) {
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    auto* pos = reinterpret_cast<SkPoint3*>(currVertex);
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkMatrixPriv::MapHomogeneousPointsWithStride(
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            args.fViewMatrix, pos, vertexStride, pos, vertexStride,
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            result.fGlyphsRegenerated * kVerticesPerGlyph);
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    auto* pos = reinterpret_cast<SkPoint*>(currVertex);
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkMatrixPriv::MapPointsWithStride(
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            args.fViewMatrix, pos, vertexStride,
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            result.fGlyphsRegenerated * kVerticesPerGlyph);
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            flushInfo.fGlyphsToFlush += result.fGlyphsRegenerated;
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!result.fFinished) {
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->flush(target, &flushInfo);
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            currVertex += vertexBytes;
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while (!result.fFinished);
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->flush(target, &flushInfo);
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid GrAtlasTextOp::flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get();
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrMaskFormat maskFormat = this->maskFormat();
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (gp->numTextureSamplers() != (int)fFontCache->getAtlasPageCount(maskFormat)) {
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // During preparation the number of atlas pages has increased.
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Update the proxies used in the GP to match.
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (this->usesDistanceFields()) {
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (this->isLCD()) {
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewProxies(
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->addNewProxies(
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewProxies(
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fFontCache->getProxies(maskFormat), GrSamplerState::ClampNearest());
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrMesh mesh(GrPrimitiveType::kTriangles);
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int maxGlyphsPerDraw =
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    mesh.setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerGlyph, kVerticesPerGlyph,
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                             flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    mesh.setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    target->draw(flushInfo->fGeometryProcessor.get(), flushInfo->fPipeline, mesh);
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flushInfo->fGlyphsToFlush = 0;
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fProcessors != that->fProcessors) {
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fCanCombineOnTouchOrOverlap && GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fMaskType != that->fMaskType) {
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkMatrix& thisFirstMatrix = fGeoData[0].fViewMatrix;
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkMatrix& thatFirstMatrix = that->fGeoData[0].fViewMatrix;
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->usesLocalCoords() && !thisFirstMatrix.cheapEqualTo(thatFirstMatrix)) {
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->usesDistanceFields()) {
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fDFGPFlags != that->fDFGPFlags) {
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fLuminanceColor != that->fLuminanceColor) {
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Keep the batch vertex buffer size below 32K so we don't have to create a special one
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We use the largest possible vertex size for this
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const int kVertexSize = sizeof(SkPoint) + sizeof(SkColor) + 2 * sizeof(uint16_t);
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const int kMaxGlyphs = 32768 / (kVerticesPerGlyph * kVertexSize);
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->fNumGlyphs + that->fNumGlyphs > kMaxGlyphs) {
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNumGlyphs += that->numGlyphs();
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Reallocate space for geo data if necessary and then import that geo's data.
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int newGeoCount = that->fGeoCount + fGeoCount;
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We reallocate at a rate of 1.5x to try to get better total memory usage
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (newGeoCount > fGeoDataAllocSize) {
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int newAllocSize = fGeoDataAllocSize + fGeoDataAllocSize / 2;
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (newAllocSize < newGeoCount) {
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            newAllocSize += newAllocSize / 2;
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fGeoData.realloc(newAllocSize);
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fGeoDataAllocSize = newAllocSize;
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We steal the ref on the blobs from the other AtlasTextOp and set its count to 0 so that
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // it doesn't try to unref them.
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry));
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < that->fGeoCount; ++i) {
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        that->fGeoData.get()[i].fBlob = (Blob*)0x1;
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    that->fGeoCount = 0;
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fGeoCount = newGeoCount;
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->joinBounds(*that);
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// TODO trying to figure out why lcd is so whack
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// (see comments in GrAtlasTextContext::ComputeCanonicalColor)
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor() const {
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const sk_sp<GrTextureProxy>* p = fFontCache->getProxies(this->maskFormat());
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isLCD = this->isLCD();
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMatrix localMatrix = SkMatrix::I();
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->usesLocalCoords()) {
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // If this fails we'll just use I().
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool result = fGeoData[0].fViewMatrix.invert(&localMatrix);
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        (void)result;
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // see if we need to create a new effect
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (isLCD) {
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        float redCorrection = fDistanceAdjustTable->getAdjustment(
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkColorGetR(fLuminanceColor) >> kDistanceAdjustLumShift,
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fUseGammaCorrectDistanceTable);
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        float greenCorrection = fDistanceAdjustTable->getAdjustment(
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkColorGetG(fLuminanceColor) >> kDistanceAdjustLumShift,
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fUseGammaCorrectDistanceTable);
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        float blueCorrection = fDistanceAdjustTable->getAdjustment(
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkColorGetB(fLuminanceColor) >> kDistanceAdjustLumShift,
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fUseGammaCorrectDistanceTable);
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        redCorrection, greenCorrection, blueCorrection);
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return GrDistanceFieldLCDTextGeoProc::Make(p, GrSamplerState::ClampBilerp(), widthAdjust,
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   fDFGPFlags, localMatrix);
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_GAMMA_APPLY_TO_A8
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        float correction = 0;
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (kAliasedDistanceField_MaskType != fMaskType) {
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT,
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                fLuminanceColor);
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                             fUseGammaCorrectDistanceTable);
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return GrDistanceFieldA8TextGeoProc::Make(p, GrSamplerState::ClampBilerp(),
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                  correction, fDFGPFlags, localMatrix);
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return GrDistanceFieldA8TextGeoProc::Make(p, GrSamplerState::ClampBilerp(),
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                  fDFGPFlags, localMatrix);
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
456