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