Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "GrAtlasTextContext.h" | 7 #include "GrAtlasTextContext.h" |
| 8 | 8 |
| 9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
| 10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 } | 84 } |
| 85 | 85 |
| 86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, | 86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, |
| 87 const GrClip&, | 87 const GrClip&, |
| 88 const GrPaint&, | 88 const GrPaint&, |
| 89 const SkPaint& skPaint, | 89 const SkPaint& skPaint, |
| 90 const SkMatrix& viewMatrix) { | 90 const SkMatrix& viewMatrix) { |
| 91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
| 92 } | 92 } |
| 93 | 93 |
| 94 bool GrAtlasTextContext::MustRegenerateBlob(const BitmapTextBlob& blob, const Sk Paint& paint, | 94 bool GrAtlasTextContext::MustRegenerateBlob(SkScalar* outTransX, SkScalar* outTr ansY, |
| 95 const BitmapTextBlob& blob, const Sk Paint& paint, | |
| 95 const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { | 96 const SkMatrix& viewMatrix, SkScalar x, SkScalar y) { |
| 96 // We always regenerate blobs with patheffects or mask filters we could cach e these | 97 // Color can affect the mask |
| 97 // TODO find some way to cache the maskfilter / patheffects on the textblob | 98 // TODO we can adjust the color within specific gamma slots |
| 98 return !blob.fViewMatrix.cheapEqualTo(viewMatrix) || blob.fX != x || blob.fY != y || | 99 if (blob.fColor != paint.getColor()) { |
| 99 paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() ! = blob.fStyle; | 100 return true; |
| 101 } | |
| 102 | |
| 103 if (blob.fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) { | |
| 104 return true; | |
| 105 } | |
| 106 | |
| 107 if (blob.fViewMatrix.hasPerspective() && !blob.fViewMatrix.cheapEqualTo(view Matrix)) { | |
| 108 return true; | |
| 109 } | |
| 110 | |
| 111 if (blob.fViewMatrix.getScaleX() != viewMatrix.getScaleX() || | |
| 112 blob.fViewMatrix.getScaleY() != viewMatrix.getScaleY() || | |
| 113 blob.fViewMatrix.getSkewX() != viewMatrix.getSkewX() || | |
| 114 blob.fViewMatrix.getSkewY() != viewMatrix.getSkewY()) { | |
| 115 return true; | |
| 116 } | |
| 117 | |
| 118 // We can update the positions in the cachedtextblobs without regenerating t he whole blob, but | |
| 119 // only for integer translations. | |
| 120 // This cool bit of math will determine the necessary translation to apply t o the already | |
| 121 // generated vertex coordinates to move them to the correct position | |
| 122 static const SkScalar kMinDiscernableTranslation = 0.0625; | |
| 123 SkScalar transX = viewMatrix.getTranslateX() + | |
| 124 viewMatrix.getScaleX() * (x - blob.fX) + | |
| 125 viewMatrix.getSkewX() * (y - blob.fY) - | |
| 126 blob.fViewMatrix.getTranslateX(); | |
| 127 SkScalar transY = viewMatrix.getTranslateY() + | |
| 128 viewMatrix.getSkewY() * (x - blob.fX) + | |
| 129 viewMatrix.getScaleY() * (y - blob.fY) - | |
| 130 blob.fViewMatrix.getTranslateY(); | |
| 131 if (SkScalarFraction(transX) > kMinDiscernableTranslation || | |
| 132 SkScalarFraction(transY) > kMinDiscernableTranslation) { | |
| 133 return true; | |
| 134 } | |
| 135 | |
| 136 #ifdef SK_DEBUG | |
|
jvanverth1
2015/04/10 15:46:31
A comment on what this all means would be useful (
| |
| 137 blob.fTotalXError += SkScalarAbs(SkScalarFraction(transX) - kMinDiscernableT ranslation); | |
| 138 blob.fTotalYError += SkScalarAbs(SkScalarFraction(transY) - kMinDiscernableT ranslation); | |
| 139 if (blob.fTotalXError > kMinDiscernableTranslation || | |
| 140 blob.fTotalYError > kMinDiscernableTranslation) { | |
| 141 SkDebugf("Exceeding error threshold for bitmap text translation"); | |
| 142 } | |
| 143 #endif | |
| 144 (*outTransX) = transX; | |
| 145 (*outTransY) = transY; | |
| 146 return false; | |
| 100 } | 147 } |
| 101 | 148 |
| 102 | 149 |
| 103 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, | 150 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, |
| 104 const SkPaint& skPaint, | 151 const SkPaint& skPaint, |
| 105 const SkMatrix& viewMatrix) { | 152 const SkMatrix& viewMatrix) { |
| 106 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v iewMatrix, false); | 153 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v iewMatrix, false); |
| 107 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); | 154 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); |
| 108 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()) ; | 155 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()) ; |
| 109 } | 156 } |
| 110 | 157 |
| 111 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, | 158 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, |
| 112 const SkPaint& skPaint, const SkMatrix& vi ewMatrix, | 159 const SkPaint& skPaint, const SkMatrix& vi ewMatrix, |
| 113 const SkTextBlob* blob, SkScalar x, SkScal ar y, | 160 const SkTextBlob* blob, SkScalar x, SkScal ar y, |
| 114 SkDrawFilter* drawFilter, const SkIRect& c lipBounds) { | 161 SkDrawFilter* drawFilter, const SkIRect& c lipBounds) { |
| 115 uint32_t uniqueID = blob->uniqueID(); | 162 uint32_t uniqueID = blob->uniqueID(); |
| 116 BitmapTextBlob* cacheBlob = fCache->find(uniqueID); | 163 SkAutoTUnref<BitmapTextBlob> cacheBlob; |
| 164 // TODO start caching these, mix bits into the key | |
| 165 bool canCache = !(skPaint.getPathEffect() || | |
| 166 skPaint.getMaskFilter() || | |
| 167 skPaint.getColorFilter() || | |
| 168 skPaint.getStyle() != SkPaint::kFill_Style || | |
| 169 drawFilter); | |
| 170 | |
| 171 if (canCache) { | |
| 172 cacheBlob.reset(SkSafeRef(fCache->find(uniqueID))); | |
| 173 } | |
| 174 | |
| 117 SkIRect clipRect; | 175 SkIRect clipRect; |
| 118 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | 176 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
| 119 | 177 |
| 178 SkScalar transX = 0.f; | |
| 179 SkScalar transY = 0.f; | |
| 180 | |
| 120 if (cacheBlob) { | 181 if (cacheBlob) { |
| 121 if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) { | 182 if (MustRegenerateBlob(&transX, &transY, *cacheBlob, skPaint, viewMatrix , x, y)) { |
| 122 // We have to remake the blob because changes may invalidate our mas ks. | 183 // We have to remake the blob because changes may invalidate our mas ks. |
| 123 // TODO we could probably get away reuse most of the time if the poi nter is unique, | 184 // TODO we could probably get away reuse most of the time if the poi nter is unique, |
| 124 // but we'd have to clear the subrun information | 185 // but we'd have to clear the subrun information |
| 125 fCache->remove(cacheBlob); | 186 fCache->remove(cacheBlob); |
| 126 cacheBlob = fCache->createCachedBlob(blob, kGrayTextVASize); | 187 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize ))); |
| 127 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, | 188 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, |
| 128 clipRect); | 189 clipRect); |
| 129 } else { | 190 } else { |
| 191 // If we can reuse the blob, then make sure we update the blob's vie wmatrix and x/y | |
| 192 // offsets to reflect the results of any translations we may apply i n generateGeometry | |
| 193 cacheBlob->fViewMatrix = viewMatrix; | |
| 194 cacheBlob->fX = x; | |
| 195 cacheBlob->fY = y; | |
| 130 fCache->makeMRU(cacheBlob); | 196 fCache->makeMRU(cacheBlob); |
| 131 } | 197 } |
| 132 } else { | 198 } else { |
| 133 cacheBlob = fCache->createCachedBlob(blob, kGrayTextVASize); | 199 if (canCache) { |
| 200 cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, kGrayTextVASize ))); | |
| 201 } else { | |
| 202 cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); | |
| 203 } | |
| 134 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra wFilter, clipRect); | 204 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra wFilter, clipRect); |
| 135 } | 205 } |
| 136 | 206 |
| 137 // Though for the time being runs in the textblob can override the paint, th ey only touch font | 207 // Though for the time being runs in the textblob can override the paint, th ey only touch font |
| 138 // info. | 208 // info. |
| 139 GrPaint grPaint; | 209 GrPaint grPaint; |
| 140 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); | 210 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint); |
| 141 | 211 |
| 142 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter, | 212 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter, |
| 143 clip, viewMatrix, clipBounds, x, y); | 213 clip, viewMatrix, clipBounds, x, y, transX, transY); |
| 144 } | 214 } |
| 145 | 215 |
| 146 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, | 216 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, |
| 147 const SkPaint& skPaint, const SkMatr ix& viewMatrix, | 217 const SkPaint& skPaint, const SkMatr ix& viewMatrix, |
| 148 const SkTextBlob* blob, SkScalar x, SkScalar y, | 218 const SkTextBlob* blob, SkScalar x, SkScalar y, |
| 149 SkDrawFilter* drawFilter, const SkIR ect& clipRect) { | 219 SkDrawFilter* drawFilter, const SkIR ect& clipRect) { |
| 150 cacheBlob->fViewMatrix = viewMatrix; | 220 cacheBlob->fViewMatrix = viewMatrix; |
| 151 cacheBlob->fX = x; | 221 cacheBlob->fX = x; |
| 152 cacheBlob->fY = y; | 222 cacheBlob->fY = y; |
| 223 cacheBlob->fColor = skPaint.getColor(); | |
| 153 cacheBlob->fStyle = skPaint.getStyle(); | 224 cacheBlob->fStyle = skPaint.getStyle(); |
| 154 | 225 |
| 155 // Regenerate textblob | 226 // Regenerate textblob |
| 156 SkPaint runPaint = skPaint; | 227 SkPaint runPaint = skPaint; |
| 157 SkTextBlob::RunIterator it(blob); | 228 SkTextBlob::RunIterator it(blob); |
| 158 for (int run = 0; !it.done(); it.next(), run++) { | 229 for (int run = 0; !it.done(); it.next(), run++) { |
| 159 int glyphCount = it.glyphCount(); | 230 int glyphCount = it.glyphCount(); |
| 160 size_t textLen = glyphCount * sizeof(uint16_t); | 231 size_t textLen = glyphCount * sizeof(uint16_t); |
| 161 const SkPoint& offset = it.offset(); | 232 const SkPoint& offset = it.offset(); |
| 162 // applyFontToPaint() always overwrites the exact same attributes, | 233 // applyFontToPaint() always overwrites the exact same attributes, |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 178 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); | 249 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); |
| 179 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( ); | 250 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( ); |
| 180 | 251 |
| 181 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; | 252 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; |
| 182 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; | 253 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; |
| 183 | 254 |
| 184 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; | 255 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; |
| 185 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; | 256 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; |
| 186 } | 257 } |
| 187 | 258 |
| 188 if (SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix)) { | 259 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { |
| 189 cacheBlob->fRuns[run].fDrawAsPaths = true; | 260 cacheBlob->fRuns[run].fDrawAsPaths = true; |
| 190 continue; | 261 continue; |
| 191 } | 262 } |
| 192 cacheBlob->fRuns[run].fDrawAsPaths = false; | 263 cacheBlob->fRuns[run].fDrawAsPaths = false; |
| 193 | 264 |
| 194 switch (it.positioning()) { | 265 switch (it.positioning()) { |
| 195 case SkTextBlob::kDefault_Positioning: | 266 case SkTextBlob::kDefault_Positioning: |
| 196 this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatr ix, | 267 this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatr ix, |
| 197 (const char *)it.glyphs(), textLen, | 268 (const char *)it.glyphs(), textLen, |
| 198 x + offset.x(), y + offset.y(), clipRect) ; | 269 x + offset.x(), y + offset.y(), clipRect) ; |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 return; | 600 return; |
| 530 } | 601 } |
| 531 | 602 |
| 532 int x = vx + glyph->fBounds.fLeft; | 603 int x = vx + glyph->fBounds.fLeft; |
| 533 int y = vy + glyph->fBounds.fTop; | 604 int y = vy + glyph->fBounds.fTop; |
| 534 | 605 |
| 535 // keep them as ints until we've done the clip-test | 606 // keep them as ints until we've done the clip-test |
| 536 int width = glyph->fBounds.width(); | 607 int width = glyph->fBounds.width(); |
| 537 int height = glyph->fBounds.height(); | 608 int height = glyph->fBounds.height(); |
| 538 | 609 |
| 539 // check if we clipped out | |
|
jvanverth1
2015/04/10 15:46:31
I recall a discussion about removing this, but upo
| |
| 540 if (clipRect.quickReject(x, y, x + width, y + height)) { | |
| 541 return; | |
| 542 } | |
| 543 | |
| 544 // If the glyph is too large we fall back to paths | 610 // If the glyph is too large we fall back to paths |
| 545 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { | 611 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { |
| 546 if (NULL == glyph->fPath) { | 612 if (NULL == glyph->fPath) { |
| 547 SkPath* path = SkNEW(SkPath); | 613 SkPath* path = SkNEW(SkPath); |
| 548 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { | 614 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { |
| 549 // flag the glyph as being dead? | 615 // flag the glyph as being dead? |
| 550 SkDELETE(path); | 616 SkDELETE(path); |
| 551 return; | 617 return; |
| 552 } | 618 } |
| 553 glyph->fPath = path; | 619 glyph->fPath = path; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 591 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex); | 657 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex); |
| 592 | 658 |
| 593 // V0 | 659 // V0 |
| 594 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); | 660 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); |
| 595 position->set(r.fLeft, r.fTop); | 661 position->set(r.fLeft, r.fTop); |
| 596 if (kA8_GrMaskFormat == format) { | 662 if (kA8_GrMaskFormat == format) { |
| 597 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; | 663 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; |
| 598 *colorPtr = color; | 664 *colorPtr = color; |
| 599 } | 665 } |
| 600 vertex += vertexStride; | 666 vertex += vertexStride; |
| 601 | |
| 602 // V1 | 667 // V1 |
| 603 position = reinterpret_cast<SkPoint*>(vertex); | 668 position = reinterpret_cast<SkPoint*>(vertex); |
| 604 position->set(r.fLeft, r.fBottom); | 669 position->set(r.fLeft, r.fBottom); |
| 605 if (kA8_GrMaskFormat == format) { | 670 if (kA8_GrMaskFormat == format) { |
| 606 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; | 671 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; |
| 607 *colorPtr = color; | 672 *colorPtr = color; |
| 608 } | 673 } |
| 609 vertex += vertexStride; | 674 vertex += vertexStride; |
| 610 | 675 |
| 611 // V2 | 676 // V2 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 633 public: | 698 public: |
| 634 typedef GrAtlasTextContext::BitmapTextBlob Blob; | 699 typedef GrAtlasTextContext::BitmapTextBlob Blob; |
| 635 typedef Blob::Run Run; | 700 typedef Blob::Run Run; |
| 636 typedef Run::SubRunInfo TextInfo; | 701 typedef Run::SubRunInfo TextInfo; |
| 637 struct Geometry { | 702 struct Geometry { |
| 638 Geometry() {} | 703 Geometry() {} |
| 639 Geometry(const Geometry& geometry) | 704 Geometry(const Geometry& geometry) |
| 640 : fBlob(SkRef(geometry.fBlob.get())) | 705 : fBlob(SkRef(geometry.fBlob.get())) |
| 641 , fRun(geometry.fRun) | 706 , fRun(geometry.fRun) |
| 642 , fSubRun(geometry.fSubRun) | 707 , fSubRun(geometry.fSubRun) |
| 643 , fColor(geometry.fColor) {} | 708 , fColor(geometry.fColor) |
| 709 , fTransX(geometry.fTransX) | |
| 710 , fTransY(geometry.fTransY) {} | |
| 644 SkAutoTUnref<Blob> fBlob; | 711 SkAutoTUnref<Blob> fBlob; |
| 645 int fRun; | 712 int fRun; |
| 646 int fSubRun; | 713 int fSubRun; |
| 647 GrColor fColor; | 714 GrColor fColor; |
| 715 SkScalar fTransX; | |
| 716 SkScalar fTransY; | |
| 648 }; | 717 }; |
| 649 | 718 |
| 650 static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat, | 719 static GrBatch* Create(const Geometry& geometry, GrMaskFormat maskFormat, |
| 651 int glyphCount, GrBatchFontCache* fontCache) { | 720 int glyphCount, GrBatchFontCache* fontCache) { |
| 652 return SkNEW_ARGS(BitmapTextBatch, (geometry, maskFormat, glyphCount, fo ntCache)); | 721 return SkNEW_ARGS(BitmapTextBatch, (geometry, maskFormat, glyphCount, fo ntCache)); |
| 653 } | 722 } |
| 654 | 723 |
| 655 const char* name() const override { return "BitmapTextBatch"; } | 724 const char* name() const override { return "BitmapTextBatch"; } |
| 656 | 725 |
| 657 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | 726 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 757 int instancesToFlush = 0; | 826 int instancesToFlush = 0; |
| 758 for (int i = 0; i < instanceCount; i++) { | 827 for (int i = 0; i < instanceCount; i++) { |
| 759 Geometry& args = fGeoData[i]; | 828 Geometry& args = fGeoData[i]; |
| 760 Blob* blob = args.fBlob; | 829 Blob* blob = args.fBlob; |
| 761 Run& run = blob->fRuns[args.fRun]; | 830 Run& run = blob->fRuns[args.fRun]; |
| 762 TextInfo& info = run.fSubRunInfo[args.fSubRun]; | 831 TextInfo& info = run.fSubRunInfo[args.fSubRun]; |
| 763 | 832 |
| 764 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); | 833 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); |
| 765 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen; | 834 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen; |
| 766 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor; | 835 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor; |
| 836 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f; | |
| 767 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 837 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
| 768 | 838 |
| 769 // We regenerate both texture coords and colors in the blob itself, and update the | 839 // We regenerate both texture coords and colors in the blob itself, and update the |
| 770 // atlas generation. If we don't end up purging any unused plots, w e can avoid | 840 // atlas generation. If we don't end up purging any unused plots, w e can avoid |
| 771 // regenerating the coords. We could take a finer grained approach to updating texture | 841 // regenerating the coords. We could take a finer grained approach to updating texture |
| 772 // coords but its not clear if the extra bookkeeping would offset an y gains. | 842 // coords but its not clear if the extra bookkeeping would offset an y gains. |
| 773 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color | 843 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color |
| 774 // or coords as needed. One final note, if we have to break a run f or an atlas eviction | 844 // or coords as needed. One final note, if we have to break a run f or an atlas eviction |
| 775 // then we can't really trust the atlas has all of the correct data. Atlas evictions | 845 // then we can't really trust the atlas has all of the correct data. Atlas evictions |
| 776 // should be pretty rare, so we just always regenerate in those case s | 846 // should be pretty rare, so we just always regenerate in those case s |
| 777 if (regenerateTextureCoords || regenerateColors) { | 847 if (regenerateTextureCoords || regenerateColors || regeneratePositio ns) { |
| 778 // first regenerate texture coordinates / colors if need be | 848 // first regenerate texture coordinates / colors if need be |
| 779 const SkDescriptor* desc = NULL; | 849 const SkDescriptor* desc = NULL; |
| 780 SkGlyphCache* cache = NULL; | 850 SkGlyphCache* cache = NULL; |
| 781 GrFontScaler* scaler = NULL; | 851 GrFontScaler* scaler = NULL; |
| 782 GrBatchTextStrike* strike = NULL; | 852 GrBatchTextStrike* strike = NULL; |
| 783 bool brokenRun = false; | 853 bool brokenRun = false; |
| 784 if (regenerateTextureCoords) { | 854 if (regenerateTextureCoords) { |
| 785 info.fBulkUseToken.reset(); | 855 info.fBulkUseToken.reset(); |
| 786 desc = run.fDescriptor.getDesc(); | 856 desc = run.fDescriptor.getDesc(); |
| 787 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); | 857 cache = SkGlyphCache::DetachCache(run.fTypeface, desc); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 821 this->regenerateTextureCoords(glyph, vertex, vertexStrid e); | 891 this->regenerateTextureCoords(glyph, vertex, vertexStrid e); |
| 822 } | 892 } |
| 823 | 893 |
| 824 if (regenerateColors) { | 894 if (regenerateColors) { |
| 825 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices); | 895 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices); |
| 826 vertex += info.fVertexStartIndex; | 896 vertex += info.fVertexStartIndex; |
| 827 vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint); | 897 vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint); |
| 828 this->regenerateColors(vertex, vertexStride, args.fColor ); | 898 this->regenerateColors(vertex, vertexStride, args.fColor ); |
| 829 } | 899 } |
| 830 | 900 |
| 901 if (regeneratePositions) { | |
| 902 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices); | |
| 903 vertex += info.fVertexStartIndex; | |
| 904 vertex += vertexStride * glyphIdx * kVerticesPerGlyph; | |
| 905 SkScalar transX = args.fTransX; | |
| 906 SkScalar transY = args.fTransY; | |
| 907 this->regeneratePositions(vertex, vertexStride, transX, transY); | |
| 908 } | |
| 831 instancesToFlush++; | 909 instancesToFlush++; |
| 832 } | 910 } |
| 833 | 911 |
| 912 // We my have changed the color so update it here | |
| 913 run.fColor = args.fColor; | |
| 834 if (regenerateTextureCoords) { | 914 if (regenerateTextureCoords) { |
| 835 SkGlyphCache::AttachCache(cache); | 915 SkGlyphCache::AttachCache(cache); |
| 836 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt lasGeneration : | 916 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt lasGeneration : |
| 837 fFontCache->atlasGenerat ion(fMaskFormat); | 917 fFontCache->atlasGenerat ion(fMaskFormat); |
| 838 } | 918 } |
| 839 } else { | 919 } else { |
| 840 instancesToFlush += glyphCount; | 920 instancesToFlush += glyphCount; |
| 841 | 921 |
| 842 // set use tokens for all of the glyphs in our subrun. This is only valid if we | 922 // set use tokens for all of the glyphs in our subrun. This is only valid if we |
| 843 // have a valid atlas generation | 923 // have a valid atlas generation |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 903 } | 983 } |
| 904 | 984 |
| 905 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { | 985 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { |
| 906 for (int i = 0; i < kVerticesPerGlyph; i++) { | 986 for (int i = 0; i < kVerticesPerGlyph; i++) { |
| 907 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); | 987 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); |
| 908 *vcolor = color; | 988 *vcolor = color; |
| 909 vertex += vertexStride; | 989 vertex += vertexStride; |
| 910 } | 990 } |
| 911 } | 991 } |
| 912 | 992 |
| 993 void regeneratePositions(intptr_t vertex, size_t vertexStride, SkScalar tran sX, | |
| 994 SkScalar transY) { | |
| 995 for (int i = 0; i < kVerticesPerGlyph; i++) { | |
| 996 SkPoint* point = reinterpret_cast<SkPoint*>(vertex); | |
| 997 point->fX += transX; | |
| 998 point->fY += transY; | |
| 999 vertex += vertexStride; | |
| 1000 } | |
| 1001 } | |
| 1002 | |
| 913 void initDraw(GrBatchTarget* batchTarget, | 1003 void initDraw(GrBatchTarget* batchTarget, |
| 914 const GrGeometryProcessor* gp, | 1004 const GrGeometryProcessor* gp, |
| 915 const GrPipeline* pipeline) { | 1005 const GrPipeline* pipeline) { |
| 916 batchTarget->initDraw(gp, pipeline); | 1006 batchTarget->initDraw(gp, pipeline); |
| 917 | 1007 |
| 918 // TODO remove this when batch is everywhere | 1008 // TODO remove this when batch is everywhere |
| 919 GrPipelineInfo init; | 1009 GrPipelineInfo init; |
| 920 init.fColorIgnored = fBatch.fColorIgnored; | 1010 init.fColorIgnored = fBatch.fColorIgnored; |
| 921 init.fOverrideColor = GrColor_ILLEGAL; | 1011 init.fOverrideColor = GrColor_ILLEGAL; |
| 922 init.fCoverageIgnored = fBatch.fCoverageIgnored; | 1012 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1009 break; | 1099 break; |
| 1010 case SkTextBlob::kFull_Positioning: | 1100 case SkTextBlob::kFull_Positioning: |
| 1011 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (), | 1101 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (), |
| 1012 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds); | 1102 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds); |
| 1013 break; | 1103 break; |
| 1014 } | 1104 } |
| 1015 } | 1105 } |
| 1016 | 1106 |
| 1017 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder, | 1107 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder, |
| 1018 BitmapTextBlob* cacheBlob, int run, GrC olor color, | 1108 BitmapTextBlob* cacheBlob, int run, GrC olor color, |
| 1019 uint8_t paintAlpha) { | 1109 uint8_t paintAlpha, SkScalar transX, Sk Scalar transY) { |
| 1020 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) { | 1110 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) { |
| 1021 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; | 1111 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; |
| 1022 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 1112 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
| 1023 if (0 == glyphCount) { | 1113 if (0 == glyphCount) { |
| 1024 continue; | 1114 continue; |
| 1025 } | 1115 } |
| 1026 | 1116 |
| 1027 GrMaskFormat format = info.fMaskFormat; | 1117 GrMaskFormat format = info.fMaskFormat; |
| 1028 GrColor subRunColor = kARGB_GrMaskFormat == format ? | 1118 GrColor subRunColor = kARGB_GrMaskFormat == format ? |
| 1029 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : | 1119 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : |
| 1030 color; | 1120 color; |
| 1031 | 1121 |
| 1032 BitmapTextBatch::Geometry geometry; | 1122 BitmapTextBatch::Geometry geometry; |
| 1033 geometry.fBlob.reset(SkRef(cacheBlob)); | 1123 geometry.fBlob.reset(SkRef(cacheBlob)); |
| 1034 geometry.fRun = run; | 1124 geometry.fRun = run; |
| 1035 geometry.fSubRun = subRun; | 1125 geometry.fSubRun = subRun; |
| 1036 geometry.fColor = subRunColor; | 1126 geometry.fColor = subRunColor; |
| 1127 geometry.fTransX = transX; | |
| 1128 geometry.fTransY = transY; | |
| 1037 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, gl yphCount, | 1129 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, format, gl yphCount, |
| 1038 fContext->getBatchFo ntCache())); | 1130 fContext->getBatchFo ntCache())); |
| 1039 | 1131 |
| 1040 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds); | 1132 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds); |
| 1041 } | 1133 } |
| 1042 } | 1134 } |
| 1043 | 1135 |
| 1044 inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend erTarget* rt, | 1136 inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend erTarget* rt, |
| 1045 const GrPaint& grPaint, const GrC lip& clip) { | 1137 const GrPaint& grPaint, const GrC lip& clip, |
| 1138 SkScalar transX, SkScalar transY) { | |
| 1046 for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { | 1139 for (int i = 0; i < cacheBlob->fBigGlyphs.count(); i++) { |
| 1047 const BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; | 1140 BitmapTextBlob::BigGlyph& bigGlyph = cacheBlob->fBigGlyphs[i]; |
| 1141 bigGlyph.fVx += transX; | |
| 1142 bigGlyph.fVy += transY; | |
| 1048 SkMatrix translate; | 1143 SkMatrix translate; |
| 1049 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGly ph.fVy)); | 1144 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), |
| 1145 SkIntToScalar(bigGlyph.fVy)); | |
| 1050 SkPath tmpPath(bigGlyph.fPath); | 1146 SkPath tmpPath(bigGlyph.fPath); |
| 1051 tmpPath.transform(translate); | 1147 tmpPath.transform(translate); |
| 1052 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); | 1148 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle); |
| 1053 fContext->drawPath(rt, clip, grPaint, SkMatrix::I(), tmpPath, strokeInfo ); | 1149 fContext->drawPath(rt, clip, grPaint, SkMatrix::I(), tmpPath, strokeInfo ); |
| 1054 } | 1150 } |
| 1055 } | 1151 } |
| 1056 | 1152 |
| 1057 void GrAtlasTextContext::flush(GrDrawTarget* target, | 1153 void GrAtlasTextContext::flush(GrDrawTarget* target, |
| 1058 const SkTextBlob* blob, | 1154 const SkTextBlob* blob, |
| 1059 BitmapTextBlob* cacheBlob, | 1155 BitmapTextBlob* cacheBlob, |
| 1060 GrRenderTarget* rt, | 1156 GrRenderTarget* rt, |
| 1061 const SkPaint& skPaint, | 1157 const SkPaint& skPaint, |
| 1062 const GrPaint& grPaint, | 1158 const GrPaint& grPaint, |
| 1063 SkDrawFilter* drawFilter, | 1159 SkDrawFilter* drawFilter, |
| 1064 const GrClip& clip, | 1160 const GrClip& clip, |
| 1065 const SkMatrix& viewMatrix, | 1161 const SkMatrix& viewMatrix, |
| 1066 const SkIRect& clipBounds, | 1162 const SkIRect& clipBounds, |
| 1067 SkScalar x, | 1163 SkScalar x, SkScalar y, |
| 1068 SkScalar y) { | 1164 SkScalar transX, SkScalar transY) { |
| 1069 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush | 1165 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush |
| 1070 // it as paths | 1166 // it as paths |
| 1071 GrPipelineBuilder pipelineBuilder; | 1167 GrPipelineBuilder pipelineBuilder; |
| 1072 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 1168 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
| 1073 | 1169 |
| 1074 GrColor color = grPaint.getColor(); | 1170 GrColor color = grPaint.getColor(); |
| 1075 uint8_t paintAlpha = skPaint.getAlpha(); | 1171 uint8_t paintAlpha = skPaint.getAlpha(); |
| 1076 | 1172 |
| 1077 SkTextBlob::RunIterator it(blob); | 1173 SkTextBlob::RunIterator it(blob); |
| 1078 for (int run = 0; !it.done(); it.next(), run++) { | 1174 for (int run = 0; !it.done(); it.next(), run++) { |
| 1079 if (cacheBlob->fRuns[run].fDrawAsPaths) { | 1175 if (cacheBlob->fRuns[run].fDrawAsPaths) { |
| 1080 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y); | 1176 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y); |
| 1081 continue; | 1177 continue; |
| 1082 } | 1178 } |
| 1083 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha); | 1179 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); |
| 1180 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, transX, transY); | |
| 1084 } | 1181 } |
| 1085 | 1182 |
| 1086 // Now flush big glyphs | 1183 // Now flush big glyphs |
| 1087 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip); | 1184 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); |
| 1088 } | 1185 } |
| 1089 | 1186 |
| 1090 void GrAtlasTextContext::flush(GrDrawTarget* target, | 1187 void GrAtlasTextContext::flush(GrDrawTarget* target, |
| 1091 BitmapTextBlob* cacheBlob, | 1188 BitmapTextBlob* cacheBlob, |
| 1092 GrRenderTarget* rt, | 1189 GrRenderTarget* rt, |
| 1093 const SkPaint& skPaint, | 1190 const SkPaint& skPaint, |
| 1094 const GrPaint& grPaint, | 1191 const GrPaint& grPaint, |
| 1095 const GrClip& clip, | 1192 const GrClip& clip, |
| 1096 const SkMatrix& viewMatrix) { | 1193 const SkMatrix& viewMatrix) { |
| 1097 GrPipelineBuilder pipelineBuilder; | 1194 GrPipelineBuilder pipelineBuilder; |
| 1098 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 1195 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
| 1099 | 1196 |
| 1100 GrColor color = grPaint.getColor(); | 1197 GrColor color = grPaint.getColor(); |
| 1101 uint8_t paintAlpha = skPaint.getAlpha(); | 1198 uint8_t paintAlpha = skPaint.getAlpha(); |
| 1102 for (int run = 0; run < cacheBlob->fRunCount; run++) { | 1199 for (int run = 0; run < cacheBlob->fRunCount; run++) { |
| 1103 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha); | 1200 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, 0, 0); |
| 1104 } | 1201 } |
| 1105 | 1202 |
| 1106 // Now flush big glyphs | 1203 // Now flush big glyphs |
| 1107 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip); | 1204 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); |
| 1108 } | 1205 } |
| OLD | NEW |