blob: d59f4cee0da6e740cbdc8a6712938232d4ad7ef4 [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.com7d34d2e2011-01-24 17:41:47 +000026static const int TEXT_STAGE = 1;
27
28static const GrVertexLayout BASE_VLAYOUT =
29 GrDrawTarget::kTextFormat_VertexLayoutBit |
30 GrDrawTarget::StageTexCoordVertexLayoutBit(TEXT_STAGE,0);
reed@google.comac10a2d2010-12-22 21:39:39 +000031
32void GrTextContext::flushGlyphs() {
33 if (fCurrVertex > 0) {
34 GrDrawTarget::AutoStateRestore asr(fDrawTarget);
35
36 // setup our sampler state for our text texture/atlas
37
38 GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode,
39 GrSamplerState::kRepeat_WrapMode,
reed@google.comac10a2d2010-12-22 21:39:39 +000040 !fExtMatrix.isIdentity());
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000041 fDrawTarget->setSamplerState(TEXT_STAGE, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +000042
43 GrAssert(GrIsALIGN4(fCurrVertex));
44 int nIndices = fCurrVertex + (fCurrVertex >> 1);
45 GrAssert(fCurrTexture);
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000046 fDrawTarget->setTexture(TEXT_STAGE, fCurrTexture);
47 fDrawTarget->setTextureMatrix(TEXT_STAGE, GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +000048 fDrawTarget->setIndexSourceToBuffer(fContext->quadIndexBuffer());
49
50 fDrawTarget->drawIndexed(GrDrawTarget::kTriangles_PrimitiveType,
51 0, 0, fCurrVertex, nIndices);
reed@google.comac10a2d2010-12-22 21:39:39 +000052 fDrawTarget->releaseReservedGeometry();
53 fVertices = NULL;
54 fMaxVertices = 0;
55 fCurrVertex = 0;
56 fCurrTexture->unref();
57 fCurrTexture = NULL;
58 }
59}
60
bsalomon@google.com5782d712011-01-21 21:03:59 +000061GrTextContext::GrTextContext(GrContext* context,
62 const GrPaint& paint,
63 const GrMatrix* extMatrix) : fPaint(paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +000064 fContext = context;
65 fStrike = NULL;
66
67 fCurrTexture = NULL;
68 fCurrVertex = 0;
69 fClipRect = context->getClip().getBounds();
70
71 if (NULL != extMatrix) {
72 fExtMatrix = *extMatrix;
73 } else {
74 fExtMatrix = GrMatrix::I();
75 }
76 if (!fExtMatrix.isIdentity()) {
77 GrMatrix inverse;
78 GrRect r;
79 r.set(fClipRect);
80 if (fExtMatrix.invert(&inverse)) {
81 inverse.mapRect(&r);
82 r.roundOut(&fClipRect);
83 }
84 }
85
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000086 // save the context's original matrix off and restore in destructor
87 // this must be done before getTextTarget.
bsalomon@google.com5782d712011-01-21 21:03:59 +000088 fOrigViewMatrix = fContext->getMatrix();
89 fContext->setMatrix(fExtMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +000090
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000091 fVertexLayout = BASE_VLAYOUT;
92 if (NULL != paint.getTexture()) {
93 fVertexLayout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
94 GrMatrix inverseViewMatrix;
95 if (fOrigViewMatrix.invert(&inverseViewMatrix)) {
96 fPaint.fTextureMatrix.preConcat(inverseViewMatrix);
97 }
98 }
99
reed@google.comac10a2d2010-12-22 21:39:39 +0000100 fVertices = NULL;
101 fMaxVertices = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000102 fDrawTarget = fContext->getTextTarget(fPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000103}
104
105GrTextContext::~GrTextContext() {
106 this->flushGlyphs();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000107 fContext->setMatrix(fOrigViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000108}
109
110void GrTextContext::flush() {
111 this->flushGlyphs();
112}
113
114static inline void setRectFan(GrGpuTextVertex v[4], int l, int t, int r, int b,
115 int stride) {
116 v[0 * stride].setI(l, t);
117 v[1 * stride].setI(l, b);
118 v[2 * stride].setI(r, b);
119 v[3 * stride].setI(r, t);
120}
121
122void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
123 GrFixed vx, GrFixed vy,
124 GrFontScaler* scaler) {
125 if (NULL == fStrike) {
126 fStrike = fContext->getFontCache()->getStrike(scaler);
127 }
128
129 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
130 if (NULL == glyph || glyph->fBounds.isEmpty()) {
131 return;
132 }
133
134 vx += GrIntToFixed(glyph->fBounds.fLeft);
135 vy += GrIntToFixed(glyph->fBounds.fTop);
136
137 // keep them as ints until we've done the clip-test
138 GrFixed width = glyph->fBounds.width();
139 GrFixed height = glyph->fBounds.height();
140
141 // check if we clipped out
142 if (true || NULL == glyph->fAtlas) {
143 int x = vx >> 16;
144 int y = vy >> 16;
145 if (fClipRect.quickReject(x, y, x + width, y + height)) {
146// Gr_clz(3); // so we can set a break-point in the debugger
147 return;
148 }
149 }
150
151 if (NULL == glyph->fAtlas) {
152 if (fStrike->getGlyphAtlas(glyph, scaler)) {
153 goto HAS_ATLAS;
154 }
reed@google.com313e4032010-12-22 22:16:59 +0000155 // must do this to flush inorder buffering before we purge
156 fContext->flushText();
157
reed@google.comac10a2d2010-12-22 21:39:39 +0000158 // try to purge
159 fContext->getFontCache()->purgeExceptFor(fStrike);
160 if (fStrike->getGlyphAtlas(glyph, scaler)) {
161 goto HAS_ATLAS;
162 }
163
164 // Draw as a path, so we flush any accumulated glyphs first
165 this->flushGlyphs();
166
167 if (NULL == glyph->fPath) {
168
169 GrPath* path = new GrPath;
170 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
171 // flag the glyph as being dead?
172 delete path;
173 return;
174 }
175 glyph->fPath = path;
176 }
177 GrPath::Iter iter(*glyph->fPath);
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 GrPoint translate;
179 translate.set(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
180 GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000181 fContext->drawPath(fPaint, &iter, GrContext::kWinding_PathFill,
182 &translate);
reed@google.comac10a2d2010-12-22 21:39:39 +0000183 return;
184 }
185
186HAS_ATLAS:
187 GrAssert(glyph->fAtlas);
188
189 // now promote them to fixed
190 width = GrIntToFixed(width);
191 height = GrIntToFixed(height);
192
193 GrTexture* texture = glyph->fAtlas->texture();
194 GrAssert(texture);
195
196 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
197 this->flushGlyphs();
198 fCurrTexture = texture;
199 fCurrTexture->ref();
200 }
201
202 if (NULL == fVertices) {
203 // If we need to reserve vertices allow the draw target to suggest
204 // a number of verts to reserve and whether to perform a flush.
205 fMaxVertices = kMinRequestedVerts;
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000206 bool flush = fDrawTarget->geometryHints(fVertexLayout,
reed@google.comac10a2d2010-12-22 21:39:39 +0000207 &fMaxVertices,
208 NULL);
209 if (flush) {
210 this->flushGlyphs();
211 fContext->flushText();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000212 fDrawTarget = fContext->getTextTarget(fPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 fMaxVertices = kDefaultRequestedVerts;
214 // ignore return, no point in flushing again.
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000215 fDrawTarget->geometryHints(fVertexLayout,
reed@google.comac10a2d2010-12-22 21:39:39 +0000216 &fMaxVertices,
217 NULL);
218 }
219
220 if (fMaxVertices < kMinRequestedVerts) {
221 fMaxVertices = kDefaultRequestedVerts;
222 } else if (fMaxVertices > (fContext->maxQuadsInIndexBuffer() * 4)) {
223 // don't exceed the limit of the index buffer
224 fMaxVertices = (fContext->maxQuadsInIndexBuffer() * 4);
225 }
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000226 bool success = fDrawTarget->reserveAndLockGeometry(fVertexLayout,
reed@google.comac10a2d2010-12-22 21:39:39 +0000227 fMaxVertices, 0,
reed@google.com1fcd51e2011-01-05 15:50:27 +0000228 GrTCast<void**>(&fVertices),
reed@google.comac10a2d2010-12-22 21:39:39 +0000229 NULL);
230 GrAlwaysAssert(success);
231 }
232
233 GrFixed tx = GrIntToFixed(glyph->fAtlasLocation.fX);
234 GrFixed ty = GrIntToFixed(glyph->fAtlasLocation.fY);
235
236#if GR_GL_TEXT_TEXTURE_NORMALIZED
237 int x = vx >> 16;
238 int y = vy >> 16;
239 int w = width >> 16;
240 int h = height >> 16;
241
242 setRectFan(&fVertices[2*fCurrVertex], x, y, x + w, y + h, 2);
243 setRectFan(&fVertices[2*fCurrVertex+1],
244 texture->normalizeFixedX(tx),
245 texture->normalizeFixedY(ty),
246 texture->normalizeFixedX(tx + width),
247 texture->normalizeFixedY(ty + height),
248 2);
249#else
250 fVertices[2*fCurrVertex].setXRectFan(vx, vy, vx + width, vy + height,
251 2 * sizeof(GrGpuTextVertex));
252 fVertices[2*fCurrVertex+1].setXRectFan(texture->normalizeFixedX(tx),
253 texture->normalizeFixedY(ty),
254 texture->normalizeFixedX(tx + width),
255 texture->normalizeFixedY(ty + height),
256 2 * sizeof(GrGpuTextVertex));
257#endif
258 fCurrVertex += 4;
259}
260
261