blob: 0a777d6cd8a106bea3310288fdd3989161e8cd65 [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.com8531c1c2011-01-13 19:52:45 +000026static const GrVertexLayout VLAYOUT =
27 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
60GrTextContext::GrTextContext(GrContext* context, const GrMatrix* extMatrix) {
61 fContext = context;
62 fStrike = NULL;
63
64 fCurrTexture = NULL;
65 fCurrVertex = 0;
66 fClipRect = context->getClip().getBounds();
67
68 if (NULL != extMatrix) {
69 fExtMatrix = *extMatrix;
70 } else {
71 fExtMatrix = GrMatrix::I();
72 }
73 if (!fExtMatrix.isIdentity()) {
74 GrMatrix inverse;
75 GrRect r;
76 r.set(fClipRect);
77 if (fExtMatrix.invert(&inverse)) {
78 inverse.mapRect(&r);
79 r.roundOut(&fClipRect);
80 }
81 }
82
83 fContext->getViewMatrix(&fOrigViewMatrix);
84 fContext->setViewMatrix(fExtMatrix);
85
86 fVertices = NULL;
87 fMaxVertices = 0;
88 fDrawTarget = fContext->getTextTarget();
89}
90
91GrTextContext::~GrTextContext() {
92 this->flushGlyphs();
93 fContext->setViewMatrix(fOrigViewMatrix);
94}
95
96void GrTextContext::flush() {
97 this->flushGlyphs();
98}
99
100static inline void setRectFan(GrGpuTextVertex v[4], int l, int t, int r, int b,
101 int stride) {
102 v[0 * stride].setI(l, t);
103 v[1 * stride].setI(l, b);
104 v[2 * stride].setI(r, b);
105 v[3 * stride].setI(r, t);
106}
107
108void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
109 GrFixed vx, GrFixed vy,
110 GrFontScaler* scaler) {
111 if (NULL == fStrike) {
112 fStrike = fContext->getFontCache()->getStrike(scaler);
113 }
114
115 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
116 if (NULL == glyph || glyph->fBounds.isEmpty()) {
117 return;
118 }
119
120 vx += GrIntToFixed(glyph->fBounds.fLeft);
121 vy += GrIntToFixed(glyph->fBounds.fTop);
122
123 // keep them as ints until we've done the clip-test
124 GrFixed width = glyph->fBounds.width();
125 GrFixed height = glyph->fBounds.height();
126
127 // check if we clipped out
128 if (true || NULL == glyph->fAtlas) {
129 int x = vx >> 16;
130 int y = vy >> 16;
131 if (fClipRect.quickReject(x, y, x + width, y + height)) {
132// Gr_clz(3); // so we can set a break-point in the debugger
133 return;
134 }
135 }
136
137 if (NULL == glyph->fAtlas) {
138 if (fStrike->getGlyphAtlas(glyph, scaler)) {
139 goto HAS_ATLAS;
140 }
reed@google.com313e4032010-12-22 22:16:59 +0000141 // must do this to flush inorder buffering before we purge
142 fContext->flushText();
143
reed@google.comac10a2d2010-12-22 21:39:39 +0000144 // try to purge
145 fContext->getFontCache()->purgeExceptFor(fStrike);
146 if (fStrike->getGlyphAtlas(glyph, scaler)) {
147 goto HAS_ATLAS;
148 }
149
150 // Draw as a path, so we flush any accumulated glyphs first
151 this->flushGlyphs();
152
153 if (NULL == glyph->fPath) {
154
155 GrPath* path = new GrPath;
156 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
157 // flag the glyph as being dead?
158 delete path;
159 return;
160 }
161 glyph->fPath = path;
162 }
163 GrPath::Iter iter(*glyph->fPath);
164 bool useTexture = false;
165 GrPoint translate;
166 translate.set(GrFixedToScalar(vx - GrIntToFixed(glyph->fBounds.fLeft)),
167 GrFixedToScalar(vy - GrIntToFixed(glyph->fBounds.fTop)));
168 fContext->drawPath(&iter, GrContext::kWinding_PathFill,
169 useTexture, &translate);
170 return;
171 }
172
173HAS_ATLAS:
174 GrAssert(glyph->fAtlas);
175
176 // now promote them to fixed
177 width = GrIntToFixed(width);
178 height = GrIntToFixed(height);
179
180 GrTexture* texture = glyph->fAtlas->texture();
181 GrAssert(texture);
182
183 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
184 this->flushGlyphs();
185 fCurrTexture = texture;
186 fCurrTexture->ref();
187 }
188
189 if (NULL == fVertices) {
190 // If we need to reserve vertices allow the draw target to suggest
191 // a number of verts to reserve and whether to perform a flush.
192 fMaxVertices = kMinRequestedVerts;
193 bool flush = fDrawTarget->geometryHints(VLAYOUT,
194 &fMaxVertices,
195 NULL);
196 if (flush) {
197 this->flushGlyphs();
198 fContext->flushText();
199 fDrawTarget = fContext->getTextTarget();
200 fMaxVertices = kDefaultRequestedVerts;
201 // ignore return, no point in flushing again.
202 fDrawTarget->geometryHints(VLAYOUT,
203 &fMaxVertices,
204 NULL);
205 }
206
207 if (fMaxVertices < kMinRequestedVerts) {
208 fMaxVertices = kDefaultRequestedVerts;
209 } else if (fMaxVertices > (fContext->maxQuadsInIndexBuffer() * 4)) {
210 // don't exceed the limit of the index buffer
211 fMaxVertices = (fContext->maxQuadsInIndexBuffer() * 4);
212 }
213 bool success = fDrawTarget->reserveAndLockGeometry(VLAYOUT,
214 fMaxVertices, 0,
reed@google.com1fcd51e2011-01-05 15:50:27 +0000215 GrTCast<void**>(&fVertices),
reed@google.comac10a2d2010-12-22 21:39:39 +0000216 NULL);
217 GrAlwaysAssert(success);
218 }
219
220 GrFixed tx = GrIntToFixed(glyph->fAtlasLocation.fX);
221 GrFixed ty = GrIntToFixed(glyph->fAtlasLocation.fY);
222
223#if GR_GL_TEXT_TEXTURE_NORMALIZED
224 int x = vx >> 16;
225 int y = vy >> 16;
226 int w = width >> 16;
227 int h = height >> 16;
228
229 setRectFan(&fVertices[2*fCurrVertex], x, y, x + w, y + h, 2);
230 setRectFan(&fVertices[2*fCurrVertex+1],
231 texture->normalizeFixedX(tx),
232 texture->normalizeFixedY(ty),
233 texture->normalizeFixedX(tx + width),
234 texture->normalizeFixedY(ty + height),
235 2);
236#else
237 fVertices[2*fCurrVertex].setXRectFan(vx, vy, vx + width, vy + height,
238 2 * sizeof(GrGpuTextVertex));
239 fVertices[2*fCurrVertex+1].setXRectFan(texture->normalizeFixedX(tx),
240 texture->normalizeFixedY(ty),
241 texture->normalizeFixedX(tx + width),
242 texture->normalizeFixedY(ty + height),
243 2 * sizeof(GrGpuTextVertex));
244#endif
245 fCurrVertex += 4;
246}
247
248