blob: 59a907e49da9bb78899e457cb72ae512cb30917a [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
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 "GrAtlas.h"
19#include "GrClipIterator.h"
20#include "GrContext.h"
21#include "GrTextContext.h"
22#include "GrTextStrike.h"
23#include "GrTextStrike_impl.h"
24#include "GrFontScaler.h"
25
bsalomon@google.com5782d712011-01-21 21:03:59 +000026static const GrVertexLayout VLAYOUT =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000027 GrDrawTarget::kTextFormat_VertexLayoutBit |
28 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
reed@google.comac10a2d2010-12-22 21:39:39 +000029
30void GrTextContext::flushGlyphs() {
31 if (fCurrVertex > 0) {
32 GrDrawTarget::AutoStateRestore asr(fDrawTarget);
33
34 // setup our sampler state for our text texture/atlas
35
36 GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode,
37 GrSamplerState::kRepeat_WrapMode,
reed@google.comac10a2d2010-12-22 21:39:39 +000038 !fExtMatrix.isIdentity());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000039 fDrawTarget->setSamplerState(0, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +000040
41 GrAssert(GrIsALIGN4(fCurrVertex));
42 int nIndices = fCurrVertex + (fCurrVertex >> 1);
43 GrAssert(fCurrTexture);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +000044 fDrawTarget->setTexture(0, fCurrTexture);
45 fDrawTarget->setTextureMatrix(0, GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +000046 fDrawTarget->setIndexSourceToBuffer(fContext->quadIndexBuffer());
47
48 fDrawTarget->drawIndexed(GrDrawTarget::kTriangles_PrimitiveType,
49 0, 0, fCurrVertex, nIndices);
50
51 fDrawTarget->releaseReservedGeometry();
52 fVertices = NULL;
53 fMaxVertices = 0;
54 fCurrVertex = 0;
55 fCurrTexture->unref();
56 fCurrTexture = NULL;
57 }
58}
59
bsalomon@google.com5782d712011-01-21 21:03:59 +000060GrTextContext::GrTextContext(GrContext* context,
61 const GrPaint& paint,
62 const GrMatrix* extMatrix) : fPaint(paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +000063 fContext = context;
64 fStrike = NULL;
65
66 fCurrTexture = NULL;
67 fCurrVertex = 0;
68 fClipRect = context->getClip().getBounds();
69
70 if (NULL != extMatrix) {
71 fExtMatrix = *extMatrix;
72 } else {
73 fExtMatrix = GrMatrix::I();
74 }
75 if (!fExtMatrix.isIdentity()) {
76 GrMatrix inverse;
77 GrRect r;
78 r.set(fClipRect);
79 if (fExtMatrix.invert(&inverse)) {
80 inverse.mapRect(&r);
81 r.roundOut(&fClipRect);
82 }
83 }
84
bsalomon@google.com5782d712011-01-21 21:03:59 +000085 fOrigViewMatrix = fContext->getMatrix();
86 fContext->setMatrix(fExtMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +000087
88 fVertices = NULL;
89 fMaxVertices = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +000090 fDrawTarget = fContext->getTextTarget(fPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +000091}
92
93GrTextContext::~GrTextContext() {
94 this->flushGlyphs();
bsalomon@google.com5782d712011-01-21 21:03:59 +000095 fContext->setMatrix(fOrigViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +000096}
97
98void GrTextContext::flush() {
99 this->flushGlyphs();
100}
101
102static inline void setRectFan(GrGpuTextVertex v[4], int l, int t, int r, int b,
103 int stride) {
104 v[0 * stride].setI(l, t);
105 v[1 * stride].setI(l, b);
106 v[2 * stride].setI(r, b);
107 v[3 * stride].setI(r, t);
108}
109
110void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
111 GrFixed vx, GrFixed vy,
112 GrFontScaler* scaler) {
113 if (NULL == fStrike) {
114 fStrike = fContext->getFontCache()->getStrike(scaler);
115 }
116
117 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
118 if (NULL == glyph || glyph->fBounds.isEmpty()) {
119 return;
120 }
121
122 vx += GrIntToFixed(glyph->fBounds.fLeft);
123 vy += GrIntToFixed(glyph->fBounds.fTop);
124
125 // keep them as ints until we've done the clip-test
126 GrFixed width = glyph->fBounds.width();
127 GrFixed height = glyph->fBounds.height();
128
129 // check if we clipped out
130 if (true || NULL == glyph->fAtlas) {
131 int x = vx >> 16;
132 int y = vy >> 16;
133 if (fClipRect.quickReject(x, y, x + width, y + height)) {
134// Gr_clz(3); // so we can set a break-point in the debugger
135 return;
136 }
137 }
138
139 if (NULL == glyph->fAtlas) {
140 if (fStrike->getGlyphAtlas(glyph, scaler)) {
141 goto HAS_ATLAS;
142 }
reed@google.com313e4032010-12-22 22:16:59 +0000143 // must do this to flush inorder buffering before we purge
144 fContext->flushText();
145
reed@google.comac10a2d2010-12-22 21:39:39 +0000146 // try to purge
147 fContext->getFontCache()->purgeExceptFor(fStrike);
148 if (fStrike->getGlyphAtlas(glyph, scaler)) {
149 goto HAS_ATLAS;
150 }
151
152 // Draw as a path, so we flush any accumulated glyphs first
153 this->flushGlyphs();
154
155 if (NULL == glyph->fPath) {
156
157 GrPath* path = new GrPath;
158 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
159 // flag the glyph as being dead?
160 delete path;
161 return;
162 }
163 glyph->fPath = path;
164 }
165 GrPath::Iter iter(*glyph->fPath);
reed@google.comac10a2d2010-12-22 21:39:39 +0000166 GrPoint translate;
167 translate.set(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
168 GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000169 fContext->drawPath(fPaint, &iter, GrContext::kWinding_PathFill,
170 &translate);
reed@google.comac10a2d2010-12-22 21:39:39 +0000171 return;
172 }
173
174HAS_ATLAS:
175 GrAssert(glyph->fAtlas);
176
177 // now promote them to fixed
178 width = GrIntToFixed(width);
179 height = GrIntToFixed(height);
180
181 GrTexture* texture = glyph->fAtlas->texture();
182 GrAssert(texture);
183
184 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
185 this->flushGlyphs();
186 fCurrTexture = texture;
187 fCurrTexture->ref();
188 }
189
190 if (NULL == fVertices) {
191 // If we need to reserve vertices allow the draw target to suggest
192 // a number of verts to reserve and whether to perform a flush.
193 fMaxVertices = kMinRequestedVerts;
194 bool flush = fDrawTarget->geometryHints(VLAYOUT,
195 &fMaxVertices,
196 NULL);
197 if (flush) {
198 this->flushGlyphs();
199 fContext->flushText();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000200 fDrawTarget = fContext->getTextTarget(fPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000201 fMaxVertices = kDefaultRequestedVerts;
202 // ignore return, no point in flushing again.
203 fDrawTarget->geometryHints(VLAYOUT,
204 &fMaxVertices,
205 NULL);
206 }
207
208 if (fMaxVertices < kMinRequestedVerts) {
209 fMaxVertices = kDefaultRequestedVerts;
210 } else if (fMaxVertices > (fContext->maxQuadsInIndexBuffer() * 4)) {
211 // don't exceed the limit of the index buffer
212 fMaxVertices = (fContext->maxQuadsInIndexBuffer() * 4);
213 }
214 bool success = fDrawTarget->reserveAndLockGeometry(VLAYOUT,
215 fMaxVertices, 0,
reed@google.com1fcd51e2011-01-05 15:50:27 +0000216 GrTCast<void**>(&fVertices),
reed@google.comac10a2d2010-12-22 21:39:39 +0000217 NULL);
218 GrAlwaysAssert(success);
219 }
220
221 GrFixed tx = GrIntToFixed(glyph->fAtlasLocation.fX);
222 GrFixed ty = GrIntToFixed(glyph->fAtlasLocation.fY);
223
224#if GR_GL_TEXT_TEXTURE_NORMALIZED
225 int x = vx >> 16;
226 int y = vy >> 16;
227 int w = width >> 16;
228 int h = height >> 16;
229
230 setRectFan(&fVertices[2*fCurrVertex], x, y, x + w, y + h, 2);
231 setRectFan(&fVertices[2*fCurrVertex+1],
232 texture->normalizeFixedX(tx),
233 texture->normalizeFixedY(ty),
234 texture->normalizeFixedX(tx + width),
235 texture->normalizeFixedY(ty + height),
236 2);
237#else
238 fVertices[2*fCurrVertex].setXRectFan(vx, vy, vx + width, vy + height,
239 2 * sizeof(GrGpuTextVertex));
240 fVertices[2*fCurrVertex+1].setXRectFan(texture->normalizeFixedX(tx),
241 texture->normalizeFixedY(ty),
242 texture->normalizeFixedX(tx + width),
243 texture->normalizeFixedY(ty + height),
244 2 * sizeof(GrGpuTextVertex));
245#endif
246 fCurrVertex += 4;
247}
248
249