• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright 2010 Google Inc.
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8          http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15  */
16 
17 
18 #include "GrTextContext.h"
19 #include "GrAtlas.h"
20 #include "GrContext.h"
21 #include "GrTextStrike.h"
22 #include "GrTextStrike_impl.h"
23 #include "GrFontScaler.h"
24 #include "GrIndexBuffer.h"
25 #include "GrGpuVertex.h"
26 #include "GrDrawTarget.h"
27 
28 enum {
29     kGlyphMaskStage = GrPaint::kTotalStages,
30 };
31 
flushGlyphs()32 void GrTextContext::flushGlyphs() {
33     if (fCurrVertex > 0) {
34         GrDrawTarget::AutoStateRestore asr(fDrawTarget);
35 
36         // setup our sampler state for our text texture/atlas
37         GrSamplerState::Filter filter;
38         if (fExtMatrix.isIdentity()) {
39             filter = GrSamplerState::kNearest_Filter;
40         } else {
41             filter = GrSamplerState::kBilinear_Filter;
42         }
43         GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode,
44                                GrSamplerState::kRepeat_WrapMode,
45                                filter);
46         fDrawTarget->setSamplerState(kGlyphMaskStage, sampler);
47 
48         GrAssert(GrIsALIGN4(fCurrVertex));
49         int nIndices = fCurrVertex + (fCurrVertex >> 1);
50         GrAssert(fCurrTexture);
51         fDrawTarget->setTexture(kGlyphMaskStage, fCurrTexture);
52 
53         if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
54             if (kOne_BlendCoeff != fPaint.fSrcBlendCoeff ||
55                 kISA_BlendCoeff != fPaint.fDstBlendCoeff ||
56                 fPaint.hasTexture()) {
57                 GrPrintf("LCD Text will not draw correctly.\n");
58             }
59             // setup blend so that we get mask * paintColor + (1-mask)*dstColor
60             fDrawTarget->setBlendConstant(fPaint.fColor);
61             fDrawTarget->setBlendFunc(kConstC_BlendCoeff, kISC_BlendCoeff);
62             // don't modulate by the paint's color in the frag since we're
63             // already doing it via the blend const.
64             fDrawTarget->setColor(0xffffffff);
65         } else {
66             // set back to normal in case we took LCD path previously.
67             fDrawTarget->setBlendFunc(fPaint.fSrcBlendCoeff, fPaint.fDstBlendCoeff);
68             fDrawTarget->setColor(fPaint.fColor);
69         }
70 
71         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
72 
73         fDrawTarget->drawIndexed(kTriangles_PrimitiveType,
74                                  0, 0, fCurrVertex, nIndices);
75         fDrawTarget->releaseReservedGeometry();
76         fVertices = NULL;
77         fMaxVertices = 0;
78         fCurrVertex = 0;
79         fCurrTexture->unref();
80         fCurrTexture = NULL;
81     }
82 }
83 
GrTextContext(GrContext * context,const GrPaint & paint,const GrMatrix * extMatrix)84 GrTextContext::GrTextContext(GrContext* context,
85                              const GrPaint& paint,
86                              const GrMatrix* extMatrix) : fPaint(paint) {
87     fContext = context;
88     fStrike = NULL;
89 
90     fCurrTexture = NULL;
91     fCurrVertex = 0;
92 
93     if (NULL != extMatrix) {
94         fExtMatrix = *extMatrix;
95     } else {
96         fExtMatrix = GrMatrix::I();
97     }
98     if (context->getClip().hasConservativeBounds()) {
99         if (!fExtMatrix.isIdentity()) {
100             GrMatrix inverse;
101             GrRect r = context->getClip().getConservativeBounds();
102             if (fExtMatrix.invert(&inverse)) {
103                 inverse.mapRect(&r);
104                 r.roundOut(&fClipRect);
105             }
106         } else {
107             context->getClip().getConservativeBounds().roundOut(&fClipRect);
108         }
109     } else {
110         fClipRect.setLargest();
111     }
112 
113     // save the context's original matrix off and restore in destructor
114     // this must be done before getTextTarget.
115     fOrigViewMatrix = fContext->getMatrix();
116     fContext->setMatrix(fExtMatrix);
117 
118     fDrawTarget = fContext->getTextTarget(fPaint);
119 
120     fVertices = NULL;
121     fMaxVertices = 0;
122 
123     fVertexLayout =
124         GrDrawTarget::kTextFormat_VertexLayoutBit |
125         GrDrawTarget::StageTexCoordVertexLayoutBit(kGlyphMaskStage, 0);
126 
127     int stageMask = paint.getActiveStageMask();
128     if (stageMask) {
129         GrMatrix inverseViewMatrix;
130         if (fOrigViewMatrix.invert(&inverseViewMatrix)) {
131             fDrawTarget->preConcatSamplerMatrices(stageMask,
132                                                   inverseViewMatrix);
133         }
134         for (int i = 0; i < GrPaint::kTotalStages; ++i) {
135             if ((1 << i) & stageMask) {
136                 fVertexLayout |=
137                     GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
138                 GrAssert(i != kGlyphMaskStage);
139             }
140         }
141     }
142 
143 }
144 
~GrTextContext()145 GrTextContext::~GrTextContext() {
146     this->flushGlyphs();
147     fContext->setMatrix(fOrigViewMatrix);
148 }
149 
flush()150 void GrTextContext::flush() {
151     this->flushGlyphs();
152 }
153 
setRectFan(GrGpuTextVertex v[4],int l,int t,int r,int b,int stride)154 static inline void setRectFan(GrGpuTextVertex v[4], int l, int t, int r, int b,
155                               int stride) {
156     v[0 * stride].setI(l, t);
157     v[1 * stride].setI(l, b);
158     v[2 * stride].setI(r, b);
159     v[3 * stride].setI(r, t);
160 }
161 
drawPackedGlyph(GrGlyph::PackedID packed,GrFixed vx,GrFixed vy,GrFontScaler * scaler)162 void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
163                                     GrFixed vx, GrFixed vy,
164                                     GrFontScaler* scaler) {
165     if (NULL == fStrike) {
166         fStrike = fContext->getFontCache()->getStrike(scaler);
167     }
168 
169     GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
170     if (NULL == glyph || glyph->fBounds.isEmpty()) {
171         return;
172     }
173 
174     vx += GrIntToFixed(glyph->fBounds.fLeft);
175     vy += GrIntToFixed(glyph->fBounds.fTop);
176 
177     // keep them as ints until we've done the clip-test
178     GrFixed width = glyph->fBounds.width();
179     GrFixed height = glyph->fBounds.height();
180 
181     // check if we clipped out
182     if (true || NULL == glyph->fAtlas) {
183         int x = vx >> 16;
184         int y = vy >> 16;
185         if (fClipRect.quickReject(x, y, x + width, y + height)) {
186 //            Gr_clz(3);    // so we can set a break-point in the debugger
187             return;
188         }
189     }
190 
191     if (NULL == glyph->fAtlas) {
192         if (fStrike->getGlyphAtlas(glyph, scaler)) {
193             goto HAS_ATLAS;
194         }
195 
196         // before we purge the cache, we must flush any accumulated draws
197         this->flushGlyphs();
198         fContext->flushText();
199 
200         // try to purge
201         fContext->getFontCache()->purgeExceptFor(fStrike);
202         if (fStrike->getGlyphAtlas(glyph, scaler)) {
203             goto HAS_ATLAS;
204         }
205 
206         if (NULL == glyph->fPath) {
207             GrPath* path = new GrPath;
208             if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
209                 // flag the glyph as being dead?
210                 delete path;
211                 return;
212             }
213             glyph->fPath = path;
214         }
215 
216         GrPoint translate;
217         translate.set(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
218                       GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
219         fContext->drawPath(fPaint, *glyph->fPath, kWinding_PathFill,
220                            &translate);
221         return;
222     }
223 
224 HAS_ATLAS:
225     GrAssert(glyph->fAtlas);
226 
227     // now promote them to fixed
228     width = GrIntToFixed(width);
229     height = GrIntToFixed(height);
230 
231     GrTexture* texture = glyph->fAtlas->texture();
232     GrAssert(texture);
233 
234     if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
235         this->flushGlyphs();
236         fCurrTexture = texture;
237         fCurrTexture->ref();
238     }
239 
240     if (NULL == fVertices) {
241         // If we need to reserve vertices allow the draw target to suggest
242         // a number of verts to reserve and whether to perform a flush.
243         fMaxVertices = kMinRequestedVerts;
244         bool flush = fDrawTarget->geometryHints(fVertexLayout,
245                                                &fMaxVertices,
246                                                NULL);
247         if (flush) {
248             this->flushGlyphs();
249             fContext->flushText();
250             fDrawTarget = fContext->getTextTarget(fPaint);
251             fMaxVertices = kDefaultRequestedVerts;
252             // ignore return, no point in flushing again.
253             fDrawTarget->geometryHints(fVertexLayout,
254                                        &fMaxVertices,
255                                        NULL);
256         }
257 
258         int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->size() / (6 * sizeof(uint16_t));
259         if (fMaxVertices < kMinRequestedVerts) {
260             fMaxVertices = kDefaultRequestedVerts;
261         } else if (fMaxVertices > maxQuadVertices) {
262             // don't exceed the limit of the index buffer
263             fMaxVertices = maxQuadVertices;
264         }
265         bool success = fDrawTarget->reserveAndLockGeometry(fVertexLayout,
266                                                            fMaxVertices, 0,
267                                                    GrTCast<void**>(&fVertices),
268                                                            NULL);
269         GrAlwaysAssert(success);
270     }
271 
272     GrFixed tx = GrIntToFixed(glyph->fAtlasLocation.fX);
273     GrFixed ty = GrIntToFixed(glyph->fAtlasLocation.fY);
274 
275 #if GR_GL_TEXT_TEXTURE_NORMALIZED
276     int x = vx >> 16;
277     int y = vy >> 16;
278     int w = width >> 16;
279     int h = height >> 16;
280 
281     setRectFan(&fVertices[2*fCurrVertex], x, y, x + w, y + h, 2);
282     setRectFan(&fVertices[2*fCurrVertex+1],
283                texture->normalizeFixedX(tx),
284                texture->normalizeFixedY(ty),
285                texture->normalizeFixedX(tx + width),
286                texture->normalizeFixedY(ty + height),
287                2);
288 #else
289     fVertices[2*fCurrVertex].setXRectFan(vx, vy, vx + width, vy + height,
290                                         2 * sizeof(GrGpuTextVertex));
291     fVertices[2*fCurrVertex+1].setXRectFan(texture->normalizeFixedX(tx),
292                                           texture->normalizeFixedY(ty),
293                                           texture->normalizeFixedX(tx + width),
294                                           texture->normalizeFixedY(ty + height),
295                                           2 * sizeof(GrGpuTextVertex));
296 #endif
297     fCurrVertex += 4;
298 }
299 
300 
301