blob: 6819bde4c3af142d8afc5c517cb32bfbe0c74598 [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
reed@google.comac10a2d2010-12-22 21:39:39 +000018#include "GrTextContext.h"
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000019#include "GrAtlas.h"
20#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000021#include "GrTextStrike.h"
22#include "GrTextStrike_impl.h"
23#include "GrFontScaler.h"
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000024#include "GrIndexBuffer.h"
25#include "GrGpuVertex.h"
bsalomon@google.comffca4002011-02-22 20:34:01 +000026#include "GrDrawTarget.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000027
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000028static const int TEXT_STAGE = 1;
29
30static const GrVertexLayout BASE_VLAYOUT =
31 GrDrawTarget::kTextFormat_VertexLayoutBit |
32 GrDrawTarget::StageTexCoordVertexLayoutBit(TEXT_STAGE,0);
reed@google.comac10a2d2010-12-22 21:39:39 +000033
34void GrTextContext::flushGlyphs() {
35 if (fCurrVertex > 0) {
36 GrDrawTarget::AutoStateRestore asr(fDrawTarget);
37
38 // setup our sampler state for our text texture/atlas
39
40 GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode,
41 GrSamplerState::kRepeat_WrapMode,
reed@google.comac10a2d2010-12-22 21:39:39 +000042 !fExtMatrix.isIdentity());
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000043 fDrawTarget->setSamplerState(TEXT_STAGE, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +000044
45 GrAssert(GrIsALIGN4(fCurrVertex));
46 int nIndices = fCurrVertex + (fCurrVertex >> 1);
47 GrAssert(fCurrTexture);
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000048 fDrawTarget->setTexture(TEXT_STAGE, fCurrTexture);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000049 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
reed@google.comac10a2d2010-12-22 21:39:39 +000050
bsalomon@google.comffca4002011-02-22 20:34:01 +000051 fDrawTarget->drawIndexed(kTriangles_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +000052 0, 0, fCurrVertex, nIndices);
reed@google.comac10a2d2010-12-22 21:39:39 +000053 fDrawTarget->releaseReservedGeometry();
54 fVertices = NULL;
55 fMaxVertices = 0;
56 fCurrVertex = 0;
57 fCurrTexture->unref();
58 fCurrTexture = NULL;
59 }
60}
61
bsalomon@google.com5782d712011-01-21 21:03:59 +000062GrTextContext::GrTextContext(GrContext* context,
63 const GrPaint& paint,
64 const GrMatrix* extMatrix) : fPaint(paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +000065 fContext = context;
66 fStrike = NULL;
67
68 fCurrTexture = NULL;
69 fCurrVertex = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +000070
71 if (NULL != extMatrix) {
72 fExtMatrix = *extMatrix;
73 } else {
74 fExtMatrix = GrMatrix::I();
75 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +000076 if (context->getClip().hasConservativeBounds()) {
bsalomon@google.comd302f142011-03-03 13:54:13 +000077 if (!fExtMatrix.isIdentity()) {
78 GrMatrix inverse;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +000079 GrRect r = context->getClip().getConservativeBounds();
bsalomon@google.comd302f142011-03-03 13:54:13 +000080 if (fExtMatrix.invert(&inverse)) {
81 inverse.mapRect(&r);
82 r.roundOut(&fClipRect);
83 }
84 } else {
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +000085 context->getClip().getConservativeBounds().roundOut(&fClipRect);
reed@google.comac10a2d2010-12-22 21:39:39 +000086 }
bsalomon@google.comd302f142011-03-03 13:54:13 +000087 } else {
88 fClipRect.setLargest();
reed@google.comac10a2d2010-12-22 21:39:39 +000089 }
90
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000091 // save the context's original matrix off and restore in destructor
92 // this must be done before getTextTarget.
bsalomon@google.com5782d712011-01-21 21:03:59 +000093 fOrigViewMatrix = fContext->getMatrix();
94 fContext->setMatrix(fExtMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +000095
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +000096 fVertexLayout = BASE_VLAYOUT;
97 if (NULL != paint.getTexture()) {
98 fVertexLayout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
99 GrMatrix inverseViewMatrix;
100 if (fOrigViewMatrix.invert(&inverseViewMatrix)) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000101 fPaint.fSampler.preConcatMatrix(inverseViewMatrix);
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000102 }
103 }
104
reed@google.comac10a2d2010-12-22 21:39:39 +0000105 fVertices = NULL;
106 fMaxVertices = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000107 fDrawTarget = fContext->getTextTarget(fPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000108}
109
110GrTextContext::~GrTextContext() {
111 this->flushGlyphs();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000112 fContext->setMatrix(fOrigViewMatrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000113}
114
115void GrTextContext::flush() {
116 this->flushGlyphs();
117}
118
119static inline void setRectFan(GrGpuTextVertex v[4], int l, int t, int r, int b,
120 int stride) {
121 v[0 * stride].setI(l, t);
122 v[1 * stride].setI(l, b);
123 v[2 * stride].setI(r, b);
124 v[3 * stride].setI(r, t);
125}
126
127void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
128 GrFixed vx, GrFixed vy,
129 GrFontScaler* scaler) {
130 if (NULL == fStrike) {
131 fStrike = fContext->getFontCache()->getStrike(scaler);
132 }
133
134 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
135 if (NULL == glyph || glyph->fBounds.isEmpty()) {
136 return;
137 }
138
139 vx += GrIntToFixed(glyph->fBounds.fLeft);
140 vy += GrIntToFixed(glyph->fBounds.fTop);
141
142 // keep them as ints until we've done the clip-test
143 GrFixed width = glyph->fBounds.width();
144 GrFixed height = glyph->fBounds.height();
145
146 // check if we clipped out
147 if (true || NULL == glyph->fAtlas) {
148 int x = vx >> 16;
149 int y = vy >> 16;
150 if (fClipRect.quickReject(x, y, x + width, y + height)) {
151// Gr_clz(3); // so we can set a break-point in the debugger
152 return;
153 }
154 }
155
156 if (NULL == glyph->fAtlas) {
157 if (fStrike->getGlyphAtlas(glyph, scaler)) {
158 goto HAS_ATLAS;
159 }
reed@google.com313e4032010-12-22 22:16:59 +0000160 // must do this to flush inorder buffering before we purge
161 fContext->flushText();
162
reed@google.comac10a2d2010-12-22 21:39:39 +0000163 // try to purge
164 fContext->getFontCache()->purgeExceptFor(fStrike);
165 if (fStrike->getGlyphAtlas(glyph, scaler)) {
166 goto HAS_ATLAS;
167 }
168
169 // Draw as a path, so we flush any accumulated glyphs first
170 this->flushGlyphs();
171
172 if (NULL == glyph->fPath) {
173
174 GrPath* path = new GrPath;
175 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
176 // flag the glyph as being dead?
177 delete path;
178 return;
179 }
180 glyph->fPath = path;
181 }
182 GrPath::Iter iter(*glyph->fPath);
reed@google.comac10a2d2010-12-22 21:39:39 +0000183 GrPoint translate;
184 translate.set(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
185 GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
bsalomon@google.comffca4002011-02-22 20:34:01 +0000186 fContext->drawPath(fPaint, &iter, kWinding_PathFill,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000187 &translate);
reed@google.comac10a2d2010-12-22 21:39:39 +0000188 return;
189 }
190
191HAS_ATLAS:
192 GrAssert(glyph->fAtlas);
193
194 // now promote them to fixed
195 width = GrIntToFixed(width);
196 height = GrIntToFixed(height);
197
198 GrTexture* texture = glyph->fAtlas->texture();
199 GrAssert(texture);
200
201 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
202 this->flushGlyphs();
203 fCurrTexture = texture;
204 fCurrTexture->ref();
205 }
206
207 if (NULL == fVertices) {
208 // If we need to reserve vertices allow the draw target to suggest
209 // a number of verts to reserve and whether to perform a flush.
210 fMaxVertices = kMinRequestedVerts;
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000211 bool flush = fDrawTarget->geometryHints(fVertexLayout,
reed@google.comac10a2d2010-12-22 21:39:39 +0000212 &fMaxVertices,
213 NULL);
214 if (flush) {
215 this->flushGlyphs();
216 fContext->flushText();
bsalomon@google.com5782d712011-01-21 21:03:59 +0000217 fDrawTarget = fContext->getTextTarget(fPaint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000218 fMaxVertices = kDefaultRequestedVerts;
219 // ignore return, no point in flushing again.
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000220 fDrawTarget->geometryHints(fVertexLayout,
reed@google.comac10a2d2010-12-22 21:39:39 +0000221 &fMaxVertices,
222 NULL);
223 }
224
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000225 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->size() / (6 * sizeof(uint16_t));
reed@google.comac10a2d2010-12-22 21:39:39 +0000226 if (fMaxVertices < kMinRequestedVerts) {
227 fMaxVertices = kDefaultRequestedVerts;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000228 } else if (fMaxVertices > maxQuadVertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000229 // don't exceed the limit of the index buffer
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000230 fMaxVertices = maxQuadVertices;
reed@google.comac10a2d2010-12-22 21:39:39 +0000231 }
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000232 bool success = fDrawTarget->reserveAndLockGeometry(fVertexLayout,
reed@google.comac10a2d2010-12-22 21:39:39 +0000233 fMaxVertices, 0,
reed@google.com1fcd51e2011-01-05 15:50:27 +0000234 GrTCast<void**>(&fVertices),
reed@google.comac10a2d2010-12-22 21:39:39 +0000235 NULL);
236 GrAlwaysAssert(success);
237 }
238
239 GrFixed tx = GrIntToFixed(glyph->fAtlasLocation.fX);
240 GrFixed ty = GrIntToFixed(glyph->fAtlasLocation.fY);
241
242#if GR_GL_TEXT_TEXTURE_NORMALIZED
243 int x = vx >> 16;
244 int y = vy >> 16;
245 int w = width >> 16;
246 int h = height >> 16;
247
248 setRectFan(&fVertices[2*fCurrVertex], x, y, x + w, y + h, 2);
249 setRectFan(&fVertices[2*fCurrVertex+1],
250 texture->normalizeFixedX(tx),
251 texture->normalizeFixedY(ty),
252 texture->normalizeFixedX(tx + width),
253 texture->normalizeFixedY(ty + height),
254 2);
255#else
256 fVertices[2*fCurrVertex].setXRectFan(vx, vy, vx + width, vy + height,
257 2 * sizeof(GrGpuTextVertex));
258 fVertices[2*fCurrVertex+1].setXRectFan(texture->normalizeFixedX(tx),
259 texture->normalizeFixedY(ty),
260 texture->normalizeFixedX(tx + width),
261 texture->normalizeFixedY(ty + height),
262 2 * sizeof(GrGpuTextVertex));
263#endif
264 fCurrVertex += 4;
265}
266
267