Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: skia/sgl/SkScalerContext.cpp

Issue 113827: Remove the remainder of the skia source code from the Chromium repo.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « skia/sgl/SkRegion_path.cpp ('k') | skia/sgl/SkScan.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* libs/graphics/sgl/SkScalerContext.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkScalerContext.h"
19 #include "SkDescriptor.h"
20 #include "SkDraw.h"
21 #include "SkFontHost.h"
22 #include "SkMaskFilter.h"
23 #include "SkPathEffect.h"
24 #include "SkRasterizer.h"
25 #include "SkRegion.h"
26 #include "SkStroke.h"
27 #include "SkThread.h"
28
29 #ifdef SK_DEBUG
30 // #define TRACK_MISSING_CHARS
31 #endif
32
33 #define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3)
34
35 static const uint8_t* gBlackGammaTable;
36 static const uint8_t* gWhiteGammaTable;
37
38 void SkGlyph::toMask(SkMask* mask) const {
39 SkASSERT(mask);
40
41 mask->fImage = (uint8_t*)fImage;
42 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
43 mask->fRowBytes = this->rowBytes();
44 mask->fFormat = fMaskFormat;
45 }
46
47 size_t SkGlyph::computeImageSize() const {
48 size_t size = this->rowBytes() * fHeight;
49 if (fMaskFormat == SkMask::k3D_Format) {
50 size *= 3;
51 }
52 return size;
53 }
54
55 void SkGlyph::zeroMetrics() {
56 fAdvanceX = 0;
57 fAdvanceY = 0;
58 fWidth = 0;
59 fHeight = 0;
60 fTop = 0;
61 fLeft = 0;
62 fRsbDelta = 0;
63 fLsbDelta = 0;
64 }
65
66 #ifdef SK_DEBUG
67 #define DUMP_RECx
68 #endif
69
70 static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
71 SkFlattenable* obj = NULL;
72 uint32_t len;
73 const void* data = desc->findEntry(tag, &len);
74
75 if (data) {
76 SkFlattenableReadBuffer buffer(data, len);
77 obj = buffer.readFlattenable();
78 SkASSERT(buffer.offset() == buffer.size());
79 }
80 return obj;
81 }
82
83 SkScalerContext::SkScalerContext(const SkDescriptor* desc)
84 : fPathEffect(NULL), fMaskFilter(NULL)
85 {
86 static bool gHaveGammaTables;
87 if (!gHaveGammaTables) {
88 const uint8_t* tables[2];
89 SkFontHost::GetGammaTables(tables);
90 gBlackGammaTable = tables[0];
91 gWhiteGammaTable = tables[1];
92 gHaveGammaTables = true;
93 }
94
95 fBaseGlyphCount = 0;
96 fAuxScalerContext = NULL;
97
98 const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
99 SkASSERT(rec);
100
101 fRec = *rec;
102
103 #ifdef DUMP_REC
104 desc->assertChecksum();
105 SkDebugf("SkScalarContext checksum %x count %d length %d\n", desc->getChecks um(), desc->getCount(), desc->getLength());
106 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
107 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
108 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
109 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n",
110 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
111 rec->fMaskFormat, rec->fStrokeJoin);
112 SkDebugf(" pathEffect %x maskFilter %x\n", desc->findEntry(kPathEffect_SkDe scriptorTag, NULL),
113 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
114 #endif
115
116 fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptor Tag);
117 fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptor Tag);
118 fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptor Tag);
119 }
120
121 SkScalerContext::~SkScalerContext() {
122 fPathEffect->safeUnref();
123 fMaskFilter->safeUnref();
124 fRasterizer->safeUnref();
125
126 SkDELETE(fAuxScalerContext);
127 }
128
129 SkScalerContext* SkScalerContext::loadAuxContext() const {
130 if (NULL == fAuxScalerContext) {
131 fAuxScalerContext = SkFontHost::CreateFallbackScalerContext(fRec);
132 if (NULL != fAuxScalerContext) {
133 fAuxScalerContext->setBaseGlyphCount(this->getGlyphCount());
134 }
135 }
136 return fAuxScalerContext;
137 }
138
139 #ifdef TRACK_MISSING_CHARS
140 static uint8_t gMissingChars[1 << 13];
141 #endif
142
143 uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
144 unsigned glyphID = this->generateCharToGlyph(uni);
145
146 if (0 == glyphID) { // try auxcontext
147 SkScalerContext* ctx = this->loadAuxContext();
148 if (NULL != ctx) {
149 glyphID = ctx->generateCharToGlyph(uni);
150 if (0 != glyphID) { // only fiddle with it if its not missing
151 glyphID += this->getGlyphCount();
152 if (glyphID > 0xFFFF) {
153 glyphID = 0;
154 }
155 }
156 }
157 }
158 #ifdef TRACK_MISSING_CHARS
159 if (0 == glyphID) {
160 bool announce = false;
161 if (uni > 0xFFFF) { // we don't record these
162 announce = true;
163 } else {
164 unsigned index = uni >> 3;
165 unsigned mask = 1 << (uni & 7);
166 SkASSERT(index < SK_ARRAY_COUNT(gMissingChars));
167 if ((gMissingChars[index] & mask) == 0) {
168 gMissingChars[index] |= mask;
169 announce = true;
170 }
171 }
172 if (announce) {
173 printf(">>> MISSING CHAR <<< 0x%04X\n", uni);
174 }
175 }
176 #endif
177 return SkToU16(glyphID);
178 }
179
180 /* Internal routine to resolve auxContextID into a real context.
181 Only makes sense to call once the glyph has been given a
182 valid auxGlyphID.
183 */
184 SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) const {
185 SkScalerContext* ctx = const_cast<SkScalerContext*>(this);
186
187 if (glyph.getGlyphID() >= this->getGlyphCount()) {
188 ctx = this->loadAuxContext();
189 if (NULL == ctx) { // if no aux, just return us
190 ctx = const_cast<SkScalerContext*>(this);
191 }
192 }
193 return ctx;
194 }
195
196 static int plus_minus_pin(int value, int max) {
197 SkASSERT(max >= 0);
198
199 if (value > max) {
200 value = max;
201 } else if (value < -max) {
202 value = -max;
203 }
204 return value;
205 }
206
207 void SkScalerContext::getAdvance(SkGlyph* glyph) {
208 // mark us as just having a valid advance
209 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
210 // we mark the format before making the call, in case the impl
211 // internally ends up calling its generateMetrics, which is OK
212 // albeit slower than strictly necessary
213 this->getGlyphContext(*glyph)->generateAdvance(glyph);
214 }
215
216 void SkScalerContext::getMetrics(SkGlyph* glyph) {
217 this->getGlyphContext(*glyph)->generateMetrics(glyph);
218
219 // for now we have separate cache entries for devkerning on and off
220 // in the future we might share caches, but make our measure/draw
221 // code make the distinction. Thus we zap the values if the caller
222 // has not asked for them.
223 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
224 // no devkern, so zap the fields
225 glyph->fLsbDelta = glyph->fRsbDelta = 0;
226 }
227
228 // if either dimension is empty, zap the image bounds of the glyph
229 if (0 == glyph->fWidth || 0 == glyph->fHeight) {
230 glyph->fWidth = 0;
231 glyph->fHeight = 0;
232 glyph->fTop = 0;
233 glyph->fLeft = 0;
234 glyph->fMaskFormat = 0;
235 return;
236 }
237
238 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
239 SkPath devPath, fillPath;
240 SkMatrix fillToDevMatrix;
241
242 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
243
244 if (fRasterizer) {
245 SkMask mask;
246
247 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
248 fMaskFilter, &mask,
249 SkMask::kJustComputeBounds_CreateMode)) {
250 glyph->fLeft = mask.fBounds.fLeft;
251 glyph->fTop = mask.fBounds.fTop;
252 glyph->fWidth = SkToU16(mask.fBounds.width());
253 glyph->fHeight = SkToU16(mask.fBounds.height());
254 } else {
255 // draw nothing 'cause we failed
256 glyph->fLeft = 0;
257 glyph->fTop = 0;
258 glyph->fWidth = 0;
259 glyph->fHeight = 0;
260 return;
261 }
262 } else {
263 // just use devPath
264 SkRect r;
265 SkIRect ir;
266
267 devPath.computeBounds(&r, SkPath::kExact_BoundsType);
268 r.roundOut(&ir);
269
270 glyph->fLeft = ir.fLeft;
271 glyph->fTop = ir.fTop;
272 glyph->fWidth = SkToU16(ir.width());
273 glyph->fHeight = SkToU16(ir.height());
274 }
275 }
276
277 glyph->fMaskFormat = fRec.fMaskFormat;
278
279 if (fMaskFilter) {
280 SkMask src, dst;
281 SkMatrix matrix;
282
283 glyph->toMask(&src);
284 fRec.getMatrixFrom2x2(&matrix);
285
286 src.fImage = NULL; // only want the bounds from the filter
287 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
288 SkASSERT(dst.fImage == NULL);
289 glyph->fLeft = dst.fBounds.fLeft;
290 glyph->fTop = dst.fBounds.fTop;
291 glyph->fWidth = SkToU16(dst.fBounds.width());
292 glyph->fHeight = SkToU16(dst.fBounds.height());
293 glyph->fMaskFormat = dst.fFormat;
294 }
295 }
296 }
297
298 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
299 const SkGlyph* glyph = &origGlyph;
300 SkGlyph tmpGlyph;
301
302 if (fMaskFilter) { // restore the prefilter bounds
303 tmpGlyph.fID = origGlyph.fID;
304
305 // need the original bounds, sans our maskfilter
306 SkMaskFilter* mf = fMaskFilter;
307 fMaskFilter = NULL; // temp disable
308 this->getMetrics(&tmpGlyph);
309 fMaskFilter = mf; // restore
310
311 tmpGlyph.fImage = origGlyph.fImage;
312
313 // we need the prefilter bounds to be <= filter bounds
314 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
315 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
316 glyph = &tmpGlyph;
317 }
318
319 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
320 SkPath devPath, fillPath;
321 SkMatrix fillToDevMatrix;
322
323 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
324
325 if (fRasterizer) {
326 SkMask mask;
327
328 glyph->toMask(&mask);
329 mask.fFormat = SkMask::kA8_Format;
330 bzero(glyph->fImage, mask.computeImageSize());
331
332 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
333 fMaskFilter, &mask,
334 SkMask::kJustRenderImage_CreateMode)) {
335 return;
336 }
337 } else {
338 SkBitmap bm;
339 SkBitmap::Config config;
340 SkMatrix matrix;
341 SkRegion clip;
342 SkPaint paint;
343 SkDraw draw;
344
345 if (SkMask::kA8_Format == fRec.fMaskFormat) {
346 config = SkBitmap::kA8_Config;
347 paint.setAntiAlias(true);
348 } else {
349 SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
350 config = SkBitmap::kA1_Config;
351 paint.setAntiAlias(false);
352 }
353
354 clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
355 matrix.setTranslate(-SkIntToScalar(glyph->fLeft),
356 -SkIntToScalar(glyph->fTop));
357 bm.setConfig(config, glyph->fWidth, glyph->fHeight,
358 glyph->rowBytes());
359 bm.setPixels(glyph->fImage);
360 bzero(glyph->fImage, bm.height() * bm.rowBytes());
361
362 draw.fClip = &clip;
363 draw.fMatrix = &matrix;
364 draw.fBitmap = &bm;
365 draw.fBounder = NULL;
366 draw.drawPath(devPath, paint);
367 }
368 } else {
369 this->getGlyphContext(*glyph)->generateImage(*glyph);
370 }
371
372 if (fMaskFilter) {
373 SkMask srcM, dstM;
374 SkMatrix matrix;
375
376 // the src glyph image shouldn't be 3D
377 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
378 glyph->toMask(&srcM);
379 fRec.getMatrixFrom2x2(&matrix);
380
381 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
382 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
383 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
384 int dstRB = origGlyph.rowBytes();
385 int srcRB = dstM.fRowBytes;
386
387 const uint8_t* src = (const uint8_t*)dstM.fImage;
388 uint8_t* dst = (uint8_t*)origGlyph.fImage;
389
390 if (SkMask::k3D_Format == dstM.fFormat) {
391 // we have to copy 3 times as much
392 height *= 3;
393 }
394
395 // clean out our glyph, since it may be larger than dstM
396 //bzero(dst, height * dstRB);
397
398 while (--height >= 0) {
399 memcpy(dst, src, width);
400 src += srcRB;
401 dst += dstRB;
402 }
403 SkMask::FreeImage(dstM.fImage);
404 }
405 }
406
407 // check to see if we should filter the alpha channel
408
409 if (NULL == fMaskFilter &&
410 fRec.fMaskFormat != SkMask::kBW_Format &&
411 (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
412 {
413 const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGamma Table : gWhiteGammaTable;
414 if (NULL != table)
415 {
416 uint8_t* dst = (uint8_t*)origGlyph.fImage;
417 unsigned rowBytes = origGlyph.rowBytes();
418
419 for (int y = origGlyph.fHeight - 1; y >= 0; --y)
420 {
421 for (int x = origGlyph.fWidth - 1; x >= 0; --x)
422 dst[x] = table[dst[x]];
423 dst += rowBytes;
424 }
425 }
426 }
427 }
428
429 void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path)
430 {
431 this->internalGetPath(glyph, NULL, path, NULL);
432 }
433
434 void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetr ics* my)
435 {
436 this->generateFontMetrics(mx, my);
437 }
438
439 ///////////////////////////////////////////////////////////////////////
440
441 void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, Sk Path* devPath, SkMatrix* fillToDevMatrix)
442 {
443 SkPath path;
444
445 this->getGlyphContext(glyph)->generatePath(glyph, &path);
446
447 if (fRec.fFrameWidth > 0 || fPathEffect != NULL)
448 {
449 // need the path in user-space, with only the point-size applied
450 // so that our stroking and effects will operate the same way they
451 // would if the user had extracted the path themself, and then
452 // called drawPath
453 SkPath localPath;
454 SkMatrix matrix, inverse;
455
456 fRec.getMatrixFrom2x2(&matrix);
457 matrix.invert(&inverse);
458 path.transform(inverse, &localPath);
459 // now localPath is only affected by the paint settings, and not the can vas matrix
460
461 SkScalar width = fRec.fFrameWidth;
462
463 if (fPathEffect)
464 {
465 SkPath effectPath;
466
467 if (fPathEffect->filterPath(&effectPath, localPath, &width))
468 localPath.swap(effectPath);
469 }
470
471 if (width > 0)
472 {
473 SkStroke stroker;
474 SkPath outline;
475
476 stroker.setWidth(width);
477 stroker.setMiterLimit(fRec.fMiterLimit);
478 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
479 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
480 stroker.strokePath(localPath, &outline);
481 localPath.swap(outline);
482 }
483
484 // now return stuff to the caller
485 if (fillToDevMatrix)
486 *fillToDevMatrix = matrix;
487
488 if (devPath)
489 localPath.transform(matrix, devPath);
490
491 if (fillPath)
492 fillPath->swap(localPath);
493 }
494 else // nothing tricky to do
495 {
496 if (fillToDevMatrix)
497 fillToDevMatrix->reset();
498
499 if (devPath)
500 {
501 if (fillPath == NULL)
502 devPath->swap(path);
503 else
504 *devPath = path;
505 }
506
507 if (fillPath)
508 fillPath->swap(path);
509 }
510
511 if (devPath)
512 devPath->updateBoundsCache();
513 if (fillPath)
514 fillPath->updateBoundsCache();
515 }
516
517
518 void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const
519 {
520 dst->reset();
521 dst->setScaleX(fPost2x2[0][0]);
522 dst->setSkewX( fPost2x2[0][1]);
523 dst->setSkewY( fPost2x2[1][0]);
524 dst->setScaleY(fPost2x2[1][1]);
525 }
526
527 void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const
528 {
529 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
530 if (fPreSkewX)
531 m->postSkew(fPreSkewX, 0);
532 }
533
534 void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const
535 {
536 this->getLocalMatrix(m);
537
538 // now concat the device matrix
539 {
540 SkMatrix deviceMatrix;
541 this->getMatrixFrom2x2(&deviceMatrix);
542 m->postConcat(deviceMatrix);
543 }
544 }
545
546 #include "SkFontHost.h"
547
548 SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc)
549 {
550 return SkFontHost::CreateScalerContext(desc);
551 }
552
OLDNEW
« no previous file with comments | « skia/sgl/SkRegion_path.cpp ('k') | skia/sgl/SkScan.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698