Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2000 Dirk Mueller (mueller@kde.org) | 4 * (C) 2000 Dirk Mueller (mueller@kde.org) |
| 5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. | 5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. |
| 6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. | 6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 } | 101 } |
| 102 | 102 |
| 103 float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, GlyphBuffer& glyph Buffer, | 103 float Font::buildGlyphBuffer(const TextRunPaintInfo& runInfo, GlyphBuffer& glyph Buffer, |
| 104 ForTextEmphasisOrNot forTextEmphasis) const | 104 ForTextEmphasisOrNot forTextEmphasis) const |
| 105 { | 105 { |
| 106 if (codePath(runInfo) == ComplexPath) { | 106 if (codePath(runInfo) == ComplexPath) { |
| 107 HarfBuzzShaper shaper(this, runInfo.run, (forTextEmphasis == ForTextEmph asis) | 107 HarfBuzzShaper shaper(this, runInfo.run, (forTextEmphasis == ForTextEmph asis) |
| 108 ? HarfBuzzShaper::ForTextEmphasis : HarfBuzzShaper::NotForTextEmphas is); | 108 ? HarfBuzzShaper::ForTextEmphasis : HarfBuzzShaper::NotForTextEmphas is); |
| 109 shaper.setDrawRange(runInfo.from, runInfo.to); | 109 shaper.setDrawRange(runInfo.from, runInfo.to); |
| 110 shaper.shape(&glyphBuffer); | 110 shaper.shape(&glyphBuffer); |
| 111 | 111 return shaper.totalWidth(); |
| 112 return 0; | |
| 113 } | 112 } |
| 114 | 113 |
| 115 SimpleShaper shaper(this, runInfo.run, nullptr /* fallbackFonts */, | 114 SimpleShaper shaper(this, runInfo.run, nullptr /* fallbackFonts */, |
| 116 nullptr /* GlyphBounds */, forTextEmphasis); | 115 nullptr /* GlyphBounds */, forTextEmphasis); |
| 117 shaper.advance(runInfo.from); | 116 shaper.advance(runInfo.from); |
| 118 float beforeWidth = shaper.runWidthSoFar(); | |
| 119 shaper.advance(runInfo.to, &glyphBuffer); | 117 shaper.advance(runInfo.to, &glyphBuffer); |
| 118 float width = shaper.runWidthSoFar(); | |
| 120 | 119 |
| 121 if (runInfo.run.ltr()) | 120 if (runInfo.run.rtl()) { |
|
jbroman
2014/10/29 15:06:07
Can you add a comment clarifying how this RTL code
f(malita)
2014/10/29 16:48:29
Added a comment + more comprehensive explanation i
| |
| 122 return beforeWidth; | 121 shaper.advance(runInfo.run.length()); |
| 122 glyphBuffer.reverse(width, shaper.runWidthSoFar()); | |
| 123 } | |
| 123 | 124 |
| 124 // RTL | 125 return width; |
| 125 float afterWidth = shaper.runWidthSoFar(); | |
| 126 shaper.advance(runInfo.run.length()); | |
| 127 glyphBuffer.reverse(); | |
| 128 | |
| 129 return shaper.runWidthSoFar() - afterWidth; | |
| 130 } | 126 } |
| 131 | 127 |
| 132 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, | 128 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, |
| 133 const FloatPoint& point) const | 129 const FloatPoint& point) const |
| 134 { | 130 { |
| 135 // Don't draw anything while we are using custom fonts that are in the proce ss of loading. | 131 // Don't draw anything while we are using custom fonts that are in the proce ss of loading. |
| 136 if (shouldSkipDrawing()) | 132 if (shouldSkipDrawing()) |
| 137 return; | 133 return; |
| 138 | 134 |
| 139 TextDrawingModeFlags textMode = context->textDrawingMode(); | 135 TextDrawingModeFlags textMode = context->textDrawingMode(); |
| 140 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context-> hasStroke())) | 136 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context-> hasStroke())) |
| 141 return; | 137 return; |
| 142 | 138 |
| 143 if (runInfo.cachedTextBlob && runInfo.cachedTextBlob->get()) { | 139 if (runInfo.cachedTextBlob && runInfo.cachedTextBlob->get()) { |
| 144 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); | 140 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 145 // we have a pre-cached blob -- happy joy! | 141 // we have a pre-cached blob -- happy joy! |
| 146 drawTextBlob(context, runInfo.cachedTextBlob->get(), point.data()); | 142 drawTextBlob(context, runInfo.cachedTextBlob->get(), point.data()); |
| 147 return; | 143 return; |
| 148 } | 144 } |
| 149 | 145 |
| 150 GlyphBuffer glyphBuffer; | 146 GlyphBuffer glyphBuffer; |
| 151 float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer); | 147 buildGlyphBuffer(runInfo, glyphBuffer); |
| 152 | 148 |
| 153 if (glyphBuffer.isEmpty()) | 149 if (glyphBuffer.isEmpty()) |
| 154 return; | 150 return; |
| 155 | 151 |
| 156 if (RuntimeEnabledFeatures::textBlobEnabled()) { | 152 if (RuntimeEnabledFeatures::textBlobEnabled()) { |
| 157 // Enabling text-blobs forces the blob rendering path even for uncacheab le blobs. | 153 // Enabling text-blobs forces the blob rendering path even for uncacheab le blobs. |
| 158 TextBlobPtr uncacheableTextBlob; | 154 TextBlobPtr uncacheableTextBlob; |
| 159 TextBlobPtr& textBlob = runInfo.cachedTextBlob ? *runInfo.cachedTextBlob : uncacheableTextBlob; | 155 TextBlobPtr& textBlob = runInfo.cachedTextBlob ? *runInfo.cachedTextBlob : uncacheableTextBlob; |
| 160 FloatRect blobBounds = runInfo.bounds; | 156 FloatRect blobBounds = runInfo.bounds; |
| 161 blobBounds.moveBy(-point); | 157 blobBounds.moveBy(-point); |
| 162 | 158 |
| 163 textBlob = buildTextBlob(glyphBuffer, initialAdvance, blobBounds, contex t->couldUseLCDRenderedText()); | 159 textBlob = buildTextBlob(glyphBuffer, blobBounds, context->couldUseLCDRe nderedText()); |
| 164 if (textBlob) { | 160 if (textBlob) { |
| 165 drawTextBlob(context, textBlob.get(), point.data()); | 161 drawTextBlob(context, textBlob.get(), point.data()); |
| 166 return; | 162 return; |
| 167 } | 163 } |
| 168 } | 164 } |
| 169 | 165 |
| 170 drawGlyphBuffer(context, runInfo, glyphBuffer, FloatPoint(point.x() + initia lAdvance, point.y())); | 166 drawGlyphBuffer(context, runInfo, glyphBuffer, point); |
| 171 } | 167 } |
| 172 | 168 |
| 173 float Font::drawUncachedText(GraphicsContext* context, const TextRunPaintInfo& r unInfo, | 169 float Font::drawUncachedText(GraphicsContext* context, const TextRunPaintInfo& r unInfo, |
| 174 const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const | 170 const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const |
| 175 { | 171 { |
| 176 // Don't draw anything while we are using custom fonts that are in the proce ss of loading, | 172 // Don't draw anything while we are using custom fonts that are in the proce ss of loading, |
| 177 // except if the 'force' argument is set to true (in which case it will use a fallback | 173 // except if the 'force' argument is set to true (in which case it will use a fallback |
| 178 // font). | 174 // font). |
| 179 if (shouldSkipDrawing() && customFontNotReadyAction == DoNotPaintIfFontNotRe ady) | 175 if (shouldSkipDrawing() && customFontNotReadyAction == DoNotPaintIfFontNotRe ady) |
| 180 return 0; | 176 return 0; |
| 181 | 177 |
| 182 TextDrawingModeFlags textMode = context->textDrawingMode(); | 178 TextDrawingModeFlags textMode = context->textDrawingMode(); |
| 183 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context-> hasStroke())) | 179 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context-> hasStroke())) |
| 184 return 0; | 180 return 0; |
| 185 | 181 |
| 186 GlyphBuffer glyphBuffer; | 182 GlyphBuffer glyphBuffer; |
| 187 float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer); | 183 float totalAdvance = buildGlyphBuffer(runInfo, glyphBuffer); |
| 188 | 184 |
| 189 if (glyphBuffer.isEmpty()) | 185 if (glyphBuffer.isEmpty()) |
| 190 return 0; | 186 return 0; |
| 191 | 187 |
| 192 return drawGlyphBuffer(context, runInfo, glyphBuffer, FloatPoint(point.x() + initialAdvance, point.y())); | 188 drawGlyphBuffer(context, runInfo, glyphBuffer, point); |
| 189 | |
| 190 return totalAdvance; | |
| 193 } | 191 } |
| 194 | 192 |
| 195 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r unInfo, const AtomicString& mark, const FloatPoint& point) const | 193 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r unInfo, const AtomicString& mark, const FloatPoint& point) const |
| 196 { | 194 { |
| 197 if (shouldSkipDrawing()) | 195 if (shouldSkipDrawing()) |
| 198 return; | 196 return; |
| 199 | 197 |
| 200 GlyphBuffer glyphBuffer; | 198 GlyphBuffer glyphBuffer; |
| 201 float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer, ForTextEmphasi s); | 199 buildGlyphBuffer(runInfo, glyphBuffer, ForTextEmphasis); |
| 202 | 200 |
| 203 if (glyphBuffer.isEmpty()) | 201 if (glyphBuffer.isEmpty()) |
| 204 return; | 202 return; |
| 205 | 203 |
| 206 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); | 204 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, point); |
| 207 } | 205 } |
| 208 | 206 |
| 209 static inline void updateGlyphOverflowFromBounds(const IntRectExtent& glyphBound s, | 207 static inline void updateGlyphOverflowFromBounds(const IntRectExtent& glyphBound s, |
| 210 const FontMetrics& fontMetrics, GlyphOverflow* glyphOverflow) | 208 const FontMetrics& fontMetrics, GlyphOverflow* glyphOverflow) |
| 211 { | 209 { |
| 212 glyphOverflow->top = std::max<int>(glyphOverflow->top, | 210 glyphOverflow->top = std::max<int>(glyphOverflow->top, |
| 213 glyphBounds.top() - (glyphOverflow->computeBounds ? 0 : fontMetrics.asce nt())); | 211 glyphBounds.top() - (glyphOverflow->computeBounds ? 0 : fontMetrics.asce nt())); |
| 214 glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, | 212 glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, |
| 215 glyphBounds.bottom() - (glyphOverflow->computeBounds ? 0 : fontMetrics.d escent())); | 213 glyphBounds.bottom() - (glyphOverflow->computeBounds ? 0 : fontMetrics.d escent())); |
| 216 glyphOverflow->left = glyphBounds.left(); | 214 glyphOverflow->left = glyphBounds.left(); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) { | 250 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) { |
| 253 cacheEntry->glyphBounds = glyphBounds; | 251 cacheEntry->glyphBounds = glyphBounds; |
| 254 cacheEntry->width = result; | 252 cacheEntry->width = result; |
| 255 } | 253 } |
| 256 | 254 |
| 257 if (glyphOverflow) | 255 if (glyphOverflow) |
| 258 updateGlyphOverflowFromBounds(glyphBounds, fontMetrics(), glyphOverflow) ; | 256 updateGlyphOverflowFromBounds(glyphBounds, fontMetrics(), glyphOverflow) ; |
| 259 return result; | 257 return result; |
| 260 } | 258 } |
| 261 | 259 |
| 262 namespace { | 260 PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, const FloatR ect& bounds, |
| 261 bool couldUseLCD) const | |
| 262 { | |
| 263 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); | |
| 263 | 264 |
| 264 template <bool hasOffsets> | 265 SkTextBlobBuilder builder; |
| 265 bool buildTextBlobInternal(const GlyphBuffer& glyphBuffer, SkScalar initialAdvan ce, | 266 SkRect skBounds = bounds; |
| 266 const SkRect* bounds, bool couldUseLCD, SkTextBlobBuilder& builder) | 267 bool hasVerticalOffsets = glyphBuffer.hasVerticalOffsets(); |
| 267 { | 268 |
| 268 SkScalar x = initialAdvance; | |
| 269 unsigned i = 0; | 269 unsigned i = 0; |
| 270 while (i < glyphBuffer.size()) { | 270 while (i < glyphBuffer.size()) { |
| 271 const SimpleFontData* fontData = glyphBuffer.fontDataAt(i); | 271 const SimpleFontData* fontData = glyphBuffer.fontDataAt(i); |
| 272 | 272 |
| 273 // FIXME: Handle vertical text. | 273 // FIXME: Handle vertical text. |
| 274 if (fontData->platformData().orientation() == Vertical) | 274 if (fontData->platformData().orientation() == Vertical) |
| 275 return false; | 275 return nullptr; |
| 276 | 276 |
| 277 // FIXME: FontPlatformData makes some decisions on the device scale | 277 // FIXME: FontPlatformData makes some decisions on the device scale |
| 278 // factor, which is found via the GraphicsContext. This should be fixed | 278 // factor, which is found via the GraphicsContext. This should be fixed |
| 279 // to avoid correctness problems here. | 279 // to avoid correctness problems here. |
| 280 SkPaint paint; | 280 SkPaint paint; |
| 281 fontData->platformData().setupPaint(&paint); | 281 fontData->platformData().setupPaint(&paint); |
| 282 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 282 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 283 | 283 |
| 284 // FIXME: this should go away after the big LCD cleanup. | 284 // FIXME: this should go away after the big LCD cleanup. |
| 285 paint.setLCDRenderText(paint.isLCDRenderText() && couldUseLCD); | 285 paint.setLCDRenderText(paint.isLCDRenderText() && couldUseLCD); |
| 286 | 286 |
| 287 unsigned start = i++; | 287 unsigned start = i++; |
| 288 while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData) | 288 while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData) |
| 289 i++; | 289 i++; |
| 290 unsigned count = i - start; | 290 unsigned count = i - start; |
| 291 | 291 |
| 292 const SkTextBlobBuilder::RunBuffer& buffer = hasOffsets ? | 292 const SkTextBlobBuilder::RunBuffer& buffer = hasVerticalOffsets |
| 293 builder.allocRunPos(paint, count, bounds) : | 293 ? builder.allocRunPos(paint, count, &skBounds) |
| 294 builder.allocRunPosH(paint, count, 0, bounds); | 294 : builder.allocRunPosH(paint, count, 0, &skBounds); |
| 295 | 295 |
| 296 const uint16_t* glyphs = glyphBuffer.glyphs(start); | 296 const uint16_t* glyphs = glyphBuffer.glyphs(start); |
| 297 const float* offsets = glyphBuffer.offsets(start); | |
| 297 std::copy(glyphs, glyphs + count, buffer.glyphs); | 298 std::copy(glyphs, glyphs + count, buffer.glyphs); |
| 299 std::copy(offsets, offsets + (hasVerticalOffsets ? 2 * count : count), b uffer.pos); | |
| 300 } | |
| 298 | 301 |
| 299 const float* advances = glyphBuffer.advances(start); | 302 return adoptRef(builder.build()); |
| 300 const FloatSize* offsets = glyphBuffer.offsets(start); | |
| 301 for (unsigned j = 0; j < count; j++) { | |
| 302 if (hasOffsets) { | |
| 303 const FloatSize& offset = offsets[j]; | |
| 304 buffer.pos[2 * j] = x + offset.width(); | |
| 305 buffer.pos[2 * j + 1] = offset.height(); | |
| 306 } else { | |
| 307 buffer.pos[j] = x; | |
| 308 } | |
| 309 x += SkFloatToScalar(advances[j]); | |
| 310 } | |
| 311 } | |
| 312 return true; | |
| 313 } | |
| 314 | |
| 315 } // namespace | |
| 316 | |
| 317 PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, float initia lAdvance, | |
| 318 const FloatRect& bounds, bool couldUseLCD) const | |
| 319 { | |
| 320 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); | |
| 321 | |
| 322 SkTextBlobBuilder builder; | |
| 323 SkScalar advance = SkFloatToScalar(initialAdvance); | |
| 324 SkRect skBounds = bounds; | |
| 325 | |
| 326 bool success = glyphBuffer.hasOffsets() ? | |
| 327 buildTextBlobInternal<true>(glyphBuffer, advance, &skBounds, couldUseLCD , builder) : | |
| 328 buildTextBlobInternal<false>(glyphBuffer, advance, &skBounds, couldUseLC D, builder); | |
| 329 return success ? adoptRef(builder.build()) : nullptr; | |
| 330 } | 303 } |
| 331 | 304 |
| 332 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) | 305 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) |
| 333 { | 306 { |
| 334 // Using roundf() rather than ceilf() for the right edge as a compromise to | 307 // Using roundf() rather than ceilf() for the right edge as a compromise to |
| 335 // ensure correct caret positioning. | 308 // ensure correct caret positioning. |
| 336 float roundedX = roundf(rect.x()); | 309 float roundedX = roundf(rect.x()); |
| 337 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), rect.he ight()); | 310 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), rect.he ight()); |
| 338 } | 311 } |
| 339 | 312 |
| (...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 807 SkPaint paint = textFillPaint(gc, font); | 780 SkPaint paint = textFillPaint(gc, font); |
| 808 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe ct, paint); | 781 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe ct, paint); |
| 809 } | 782 } |
| 810 | 783 |
| 811 if ((textMode & TextModeStroke) && gc->hasStroke()) { | 784 if ((textMode & TextModeStroke) && gc->hasStroke()) { |
| 812 SkPaint paint = textStrokePaint(gc, font, textMode & TextModeFill); | 785 SkPaint paint = textStrokePaint(gc, font, textMode & TextModeFill); |
| 813 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe ct, paint); | 786 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe ct, paint); |
| 814 } | 787 } |
| 815 } | 788 } |
| 816 | 789 |
| 790 static void drawVerticalGlyphs(GraphicsContext* gc, const SimpleFontData* font, | |
| 791 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const Flo atPoint& point, | |
| 792 const FloatRect& textRect) | |
| 793 { | |
| 794 const OpenTypeVerticalData* verticalData = font->verticalData(); | |
| 795 | |
| 796 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); | |
| 797 SkPoint* pos = storage.get(); | |
| 798 | |
| 799 // Bend over backwards to preserve legacy rounding. | |
| 800 float initialAdvance = glyphBuffer.xOffsetAt(from); | |
| 801 FloatPoint adjustedPoint(point.x() + initialAdvance, point.y()); | |
| 802 | |
| 803 AffineTransform savedMatrix = gc->getCTM(); | |
| 804 gc->concatCTM(AffineTransform(0, -1, 1, 0, adjustedPoint.x(), adjustedPoint. y())); | |
| 805 gc->concatCTM(AffineTransform(1, 0, 0, 1, -adjustedPoint.x(), -adjustedPoint .y())); | |
| 806 | |
| 807 const unsigned kMaxBufferLength = 256; | |
| 808 Vector<FloatPoint, kMaxBufferLength> translations; | |
| 809 | |
| 810 const FontMetrics& metrics = font->fontMetrics(); | |
| 811 float verticalOriginX = adjustedPoint.x() + metrics.floatAscent() - metrics. floatAscent(IdeographicBaseline); | |
| 812 | |
| 813 unsigned glyphIndex = 0; | |
| 814 while (glyphIndex < numGlyphs) { | |
| 815 unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphIndex ); | |
| 816 | |
| 817 const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); | |
| 818 | |
| 819 translations.resize(chunkLength); | |
| 820 verticalData->getVerticalTranslationsForGlyphs(font, glyphs, chunkLength , | |
| 821 reinterpret_cast<float*>(&translations[0])); | |
| 822 | |
| 823 for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { | |
| 824 SkScalar x = verticalOriginX + lroundf(translations[i].x()); | |
| 825 SkScalar y = adjustedPoint.y() - SkIntToScalar( | |
| 826 -lroundf(glyphBuffer.xOffsetAt(from + glyphIndex) - initialAdvan ce - translations[i].y())); | |
| 827 pos[i].set(x, y); | |
| 828 } | |
| 829 paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); | |
| 830 } | |
| 831 | |
| 832 gc->setCTM(savedMatrix); | |
| 833 } | |
| 834 | |
| 817 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, | 835 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, |
| 818 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, | 836 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, |
| 819 const FloatPoint& point, const FloatRect& textRect) const | 837 const FloatPoint& point, const FloatRect& textRect) const |
| 820 { | 838 { |
| 821 SkScalar x = SkFloatToScalar(point.x()); | 839 ASSERT(glyphBuffer.size() >= from + numGlyphs); |
| 822 SkScalar y = SkFloatToScalar(point.y()); | |
| 823 | 840 |
| 824 const OpenTypeVerticalData* verticalData = font->verticalData(); | 841 if (font->platformData().orientation() == Vertical && font->verticalData()) { |
| 825 if (font->platformData().orientation() == Vertical && verticalData) { | 842 drawVerticalGlyphs(gc, font, glyphBuffer, from, numGlyphs, point, textRe ct); |
| 826 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); | |
| 827 SkPoint* pos = storage.get(); | |
| 828 | |
| 829 AffineTransform savedMatrix = gc->getCTM(); | |
| 830 gc->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y())); | |
| 831 gc->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y())); | |
| 832 | |
| 833 const unsigned kMaxBufferLength = 256; | |
| 834 Vector<FloatPoint, kMaxBufferLength> translations; | |
| 835 | |
| 836 const FontMetrics& metrics = font->fontMetrics(); | |
| 837 SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAsce nt() - metrics.floatAscent(IdeographicBaseline)); | |
| 838 float horizontalOffset = point.x(); | |
| 839 | |
| 840 unsigned glyphIndex = 0; | |
| 841 while (glyphIndex < numGlyphs) { | |
| 842 unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphI ndex); | |
| 843 | |
| 844 const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); | |
| 845 translations.resize(chunkLength); | |
| 846 verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chu nkLength, reinterpret_cast<float*>(&translations[0])); | |
| 847 | |
| 848 x = verticalOriginX; | |
| 849 y = SkFloatToScalar(point.y() + horizontalOffset - point.x()); | |
| 850 | |
| 851 float currentWidth = 0; | |
| 852 for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { | |
| 853 pos[i].set( | |
| 854 x + SkIntToScalar(lroundf(translations[i].x())), | |
| 855 y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y ()))); | |
| 856 currentWidth += glyphBuffer.advanceAt(from + glyphIndex); | |
| 857 } | |
| 858 horizontalOffset += currentWidth; | |
| 859 paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); | |
| 860 } | |
| 861 | |
| 862 gc->setCTM(savedMatrix); | |
| 863 return; | 843 return; |
| 864 } | 844 } |
| 865 | 845 |
| 866 if (!glyphBuffer.hasOffsets()) { | 846 if (!glyphBuffer.hasVerticalOffsets()) { |
| 867 SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); | 847 SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); |
| 868 SkScalar* xpos = storage.get(); | 848 SkScalar* xpos = storage.get(); |
| 869 const float* adv = glyphBuffer.advances(from); | 849 for (unsigned i = 0; i < numGlyphs; i++) |
| 870 for (unsigned i = 0; i < numGlyphs; i++) { | 850 xpos[i] = SkFloatToScalar(point.x() + glyphBuffer.xOffsetAt(from + i )); |
| 871 xpos[i] = x; | 851 |
| 872 x += SkFloatToScalar(adv[i]); | 852 paintGlyphsHorizontal(gc, font, glyphBuffer.glyphs(from), numGlyphs, xpo s, |
| 873 } | 853 SkFloatToScalar(point.y()), textRect); |
| 874 const Glyph* glyphs = glyphBuffer.glyphs(from); | |
| 875 paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar (y), textRect); | |
| 876 return; | 854 return; |
| 877 } | 855 } |
| 878 | 856 |
| 879 ASSERT(glyphBuffer.hasOffsets()); | 857 ASSERT(glyphBuffer.hasVerticalOffsets()); |
| 880 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); | 858 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); |
| 881 SkPoint* pos = storage.get(); | 859 SkPoint* pos = storage.get(); |
| 882 const FloatSize* offsets = glyphBuffer.offsets(from); | |
| 883 const float* advances = glyphBuffer.advances(from); | |
| 884 SkScalar advanceSoFar = SkFloatToScalar(0); | |
| 885 for (unsigned i = 0; i < numGlyphs; i++) { | 860 for (unsigned i = 0; i < numGlyphs; i++) { |
| 886 pos[i].set( | 861 pos[i].set( |
| 887 x + SkFloatToScalar(offsets[i].width()) + advanceSoFar, | 862 SkFloatToScalar(point.x() + glyphBuffer.xOffsetAt(from + i)), |
| 888 y + SkFloatToScalar(offsets[i].height())); | 863 SkFloatToScalar(point.y() + glyphBuffer.yOffsetAt(from + i))); |
| 889 advanceSoFar += SkFloatToScalar(advances[i]); | |
| 890 } | 864 } |
| 891 | 865 |
| 892 const Glyph* glyphs = glyphBuffer.glyphs(from); | 866 paintGlyphs(gc, font, glyphBuffer.glyphs(from), numGlyphs, pos, textRect); |
| 893 paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); | |
| 894 } | 867 } |
| 895 | 868 |
| 896 void Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoi nt& origin) const | 869 void Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoi nt& origin) const |
| 897 { | 870 { |
| 898 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); | 871 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 899 | 872 |
| 900 TextDrawingModeFlags textMode = gc->textDrawingMode(); | 873 TextDrawingModeFlags textMode = gc->textDrawingMode(); |
| 901 if (textMode & TextModeFill) | 874 if (textMode & TextModeFill) |
| 902 gc->drawTextBlob(blob, origin, gc->fillPaint()); | 875 gc->drawTextBlob(blob, origin, gc->fillPaint()); |
| 903 | 876 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 936 // Return the rectangle for selecting the given range of code-points in the Text Run. | 909 // Return the rectangle for selecting the given range of code-points in the Text Run. |
| 937 FloatRect Font::selectionRectForComplexText(const TextRun& run, | 910 FloatRect Font::selectionRectForComplexText(const TextRun& run, |
| 938 const FloatPoint& point, int height, int from, int to) const | 911 const FloatPoint& point, int height, int from, int to) const |
| 939 { | 912 { |
| 940 HarfBuzzShaper shaper(this, run); | 913 HarfBuzzShaper shaper(this, run); |
| 941 if (!shaper.shape()) | 914 if (!shaper.shape()) |
| 942 return FloatRect(); | 915 return FloatRect(); |
| 943 return shaper.selectionRect(point, height, from, to); | 916 return shaper.selectionRect(point, height, from, to); |
| 944 } | 917 } |
| 945 | 918 |
| 946 float Font::drawGlyphBuffer(GraphicsContext* context, | 919 void Font::drawGlyphBuffer(GraphicsContext* context, |
| 947 const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, | 920 const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, |
| 948 const FloatPoint& point) const | 921 const FloatPoint& point) const |
| 949 { | 922 { |
| 950 // Draw each contiguous run of glyphs that use the same font data. | 923 // Draw each contiguous run of glyphs that use the same font data. |
| 951 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); | 924 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); |
| 952 FloatPoint startPoint(point); | |
| 953 float advanceSoFar = 0; | |
| 954 unsigned lastFrom = 0; | 925 unsigned lastFrom = 0; |
| 955 unsigned nextGlyph = 0; | 926 unsigned nextGlyph; |
| 956 | 927 |
| 957 while (nextGlyph < glyphBuffer.size()) { | 928 for (nextGlyph = 0; nextGlyph < glyphBuffer.size(); ++nextGlyph) { |
| 958 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); | 929 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); |
| 959 | 930 |
| 960 if (nextFontData != fontData) { | 931 if (nextFontData != fontData) { |
| 961 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - las tFrom, startPoint, runInfo.bounds); | 932 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - las tFrom, point, |
| 933 runInfo.bounds); | |
| 962 | 934 |
| 963 lastFrom = nextGlyph; | 935 lastFrom = nextGlyph; |
| 964 fontData = nextFontData; | 936 fontData = nextFontData; |
| 965 startPoint += FloatSize(advanceSoFar, 0); | |
| 966 advanceSoFar = 0; | |
| 967 } | 937 } |
| 968 advanceSoFar += glyphBuffer.advanceAt(nextGlyph); | |
| 969 nextGlyph++; | |
| 970 } | 938 } |
| 971 | 939 |
| 972 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, s tartPoint, runInfo.bounds); | 940 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, p oint, |
| 973 startPoint += FloatSize(advanceSoFar, 0); | 941 runInfo.bounds); |
| 974 return startPoint.x() - point.x(); | |
| 975 } | 942 } |
| 976 | 943 |
| 977 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) | 944 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) |
| 978 { | 945 { |
| 979 if (fontData->platformData().orientation() == Horizontal) { | 946 if (fontData->platformData().orientation() == Horizontal) { |
| 980 FloatRect bounds = fontData->boundsForGlyph(glyph); | 947 FloatRect bounds = fontData->boundsForGlyph(glyph); |
| 981 return bounds.x() + bounds.width() / 2; | 948 return bounds.x() + bounds.width() / 2; |
| 982 } | 949 } |
| 983 // FIXME: Use glyph bounds once they make sense for vertical fonts. | 950 // FIXME: Use glyph bounds once they make sense for vertical fonts. |
| 984 return fontData->widthForGlyph(glyph) / 2; | 951 return fontData->widthForGlyph(glyph) / 2; |
| 985 } | 952 } |
| 986 | 953 |
| 987 inline static float offsetToMiddleOfAdvanceAtIndex(const GlyphBuffer& glyphBuffe r, size_t i) | |
| 988 { | |
| 989 return glyphBuffer.advanceAt(i) / 2; | |
| 990 } | |
| 991 | |
| 992 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r unInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoi nt& point) const | 954 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r unInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoi nt& point) const |
| 993 { | 955 { |
| 994 FontCachePurgePreventer purgePreventer; | 956 FontCachePurgePreventer purgePreventer; |
| 995 | 957 |
| 996 GlyphData markGlyphData; | 958 GlyphData markGlyphData; |
| 997 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) | 959 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) |
| 998 return; | 960 return; |
| 999 | 961 |
| 1000 const SimpleFontData* markFontData = markGlyphData.fontData; | 962 const SimpleFontData* markFontData = markGlyphData.fontData; |
| 1001 ASSERT(markFontData); | 963 ASSERT(markFontData); |
| 1002 if (!markFontData) | 964 if (!markFontData) |
| 1003 return; | 965 return; |
| 1004 | 966 |
| 1005 Glyph markGlyph = markGlyphData.glyph; | 967 GlyphBuffer markBuffer; |
| 1006 Glyph spaceGlyph = markFontData->spaceGlyph(); | 968 float midMarkOffset = offsetToMiddleOfGlyph(markFontData, markGlyphData.glyp h); |
|
jbroman
2014/10/29 15:06:07
Can you clarify why we're subtracting midMarkOffse
f(malita)
2014/10/29 16:48:29
Added some comments (we are essentially aligning t
| |
| 969 for (unsigned i = 0; i < glyphBuffer.size(); ++i) { | |
| 970 // Offsets point to glyphs midpoint. | |
| 971 if (glyphBuffer.glyphAt(i)) | |
| 972 markBuffer.add(markGlyphData.glyph, markFontData, glyphBuffer.xOffse tAt(i) - midMarkOffset); | |
| 973 } | |
| 1007 | 974 |
| 1008 float middleOfLastGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, 0); | 975 drawGlyphBuffer(context, runInfo, markBuffer, point); |
| 1009 FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph( markFontData, markGlyph), point.y()); | |
| 1010 | |
| 1011 GlyphBuffer markBuffer; | |
| 1012 for (unsigned i = 0; i + 1 < glyphBuffer.size(); ++i) { | |
| 1013 float middleOfNextGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, i + 1); | |
| 1014 float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfN extGlyph; | |
| 1015 markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFont Data, advance); | |
| 1016 middleOfLastGlyph = middleOfNextGlyph; | |
| 1017 } | |
| 1018 markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spa ceGlyph, markFontData, 0); | |
| 1019 | |
| 1020 drawGlyphBuffer(context, runInfo, markBuffer, startPoint); | |
| 1021 } | 976 } |
| 1022 | 977 |
| 1023 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFont Data*>* fallbackFonts, IntRectExtent* glyphBounds) const | 978 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFont Data*>* fallbackFonts, IntRectExtent* glyphBounds) const |
| 1024 { | 979 { |
| 1025 SimpleShaper::GlyphBounds bounds; | 980 SimpleShaper::GlyphBounds bounds; |
| 1026 SimpleShaper shaper(this, run, fallbackFonts, glyphBounds ? &bounds : 0); | 981 SimpleShaper shaper(this, run, fallbackFonts, glyphBounds ? &bounds : 0); |
| 1027 shaper.advance(run.length()); | 982 shaper.advance(run.length()); |
| 1028 | 983 |
| 1029 if (glyphBounds) { | 984 if (glyphBounds) { |
| 1030 glyphBounds->setTop(floorf(-bounds.minGlyphBoundingBoxY)); | 985 glyphBounds->setTop(floorf(-bounds.minGlyphBoundingBoxY)); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1096 if (delta <= 0) | 1051 if (delta <= 0) |
| 1097 break; | 1052 break; |
| 1098 } | 1053 } |
| 1099 } | 1054 } |
| 1100 } | 1055 } |
| 1101 | 1056 |
| 1102 return offset; | 1057 return offset; |
| 1103 } | 1058 } |
| 1104 | 1059 |
| 1105 } // namespace blink | 1060 } // namespace blink |
| OLD | NEW |