| 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()) { |
| 122 return beforeWidth; | 121 // Glyphs are shaped & stored in RTL advance order - reverse them for LT
R drawing. |
| 122 shaper.advance(runInfo.run.length()); |
| 123 glyphBuffer.reverseForSimpleRTL(width, shaper.runWidthSoFar()); |
| 124 } |
| 123 | 125 |
| 124 // RTL | 126 return width; |
| 125 float afterWidth = shaper.runWidthSoFar(); | |
| 126 shaper.advance(runInfo.run.length()); | |
| 127 glyphBuffer.reverse(); | |
| 128 | |
| 129 return shaper.runWidthSoFar() - afterWidth; | |
| 130 } | 127 } |
| 131 | 128 |
| 132 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, | 129 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, |
| 133 const FloatPoint& point) const | 130 const FloatPoint& point) const |
| 134 { | 131 { |
| 135 // Don't draw anything while we are using custom fonts that are in the proce
ss of loading. | 132 // Don't draw anything while we are using custom fonts that are in the proce
ss of loading. |
| 136 if (shouldSkipDrawing()) | 133 if (shouldSkipDrawing()) |
| 137 return; | 134 return; |
| 138 | 135 |
| 139 TextDrawingModeFlags textMode = context->textDrawingMode(); | 136 TextDrawingModeFlags textMode = context->textDrawingMode(); |
| 140 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context->
hasStroke())) | 137 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context->
hasStroke())) |
| 141 return; | 138 return; |
| 142 | 139 |
| 143 if (runInfo.cachedTextBlob && runInfo.cachedTextBlob->get()) { | 140 if (runInfo.cachedTextBlob && runInfo.cachedTextBlob->get()) { |
| 144 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); | 141 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 145 // we have a pre-cached blob -- happy joy! | 142 // we have a pre-cached blob -- happy joy! |
| 146 drawTextBlob(context, runInfo.cachedTextBlob->get(), point.data()); | 143 drawTextBlob(context, runInfo.cachedTextBlob->get(), point.data()); |
| 147 return; | 144 return; |
| 148 } | 145 } |
| 149 | 146 |
| 150 GlyphBuffer glyphBuffer; | 147 GlyphBuffer glyphBuffer; |
| 151 float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer); | 148 buildGlyphBuffer(runInfo, glyphBuffer); |
| 152 | 149 |
| 153 if (glyphBuffer.isEmpty()) | 150 if (glyphBuffer.isEmpty()) |
| 154 return; | 151 return; |
| 155 | 152 |
| 156 if (RuntimeEnabledFeatures::textBlobEnabled()) { | 153 if (RuntimeEnabledFeatures::textBlobEnabled()) { |
| 157 // Enabling text-blobs forces the blob rendering path even for uncacheab
le blobs. | 154 // Enabling text-blobs forces the blob rendering path even for uncacheab
le blobs. |
| 158 TextBlobPtr uncacheableTextBlob; | 155 TextBlobPtr uncacheableTextBlob; |
| 159 TextBlobPtr& textBlob = runInfo.cachedTextBlob ? *runInfo.cachedTextBlob
: uncacheableTextBlob; | 156 TextBlobPtr& textBlob = runInfo.cachedTextBlob ? *runInfo.cachedTextBlob
: uncacheableTextBlob; |
| 160 FloatRect blobBounds = runInfo.bounds; | 157 FloatRect blobBounds = runInfo.bounds; |
| 161 blobBounds.moveBy(-point); | 158 blobBounds.moveBy(-point); |
| 162 | 159 |
| 163 textBlob = buildTextBlob(glyphBuffer, initialAdvance, blobBounds, contex
t->couldUseLCDRenderedText()); | 160 textBlob = buildTextBlob(glyphBuffer, blobBounds, context->couldUseLCDRe
nderedText()); |
| 164 if (textBlob) { | 161 if (textBlob) { |
| 165 drawTextBlob(context, textBlob.get(), point.data()); | 162 drawTextBlob(context, textBlob.get(), point.data()); |
| 166 return; | 163 return; |
| 167 } | 164 } |
| 168 } | 165 } |
| 169 | 166 |
| 170 drawGlyphBuffer(context, runInfo, glyphBuffer, FloatPoint(point.x() + initia
lAdvance, point.y())); | 167 drawGlyphBuffer(context, runInfo, glyphBuffer, point); |
| 171 } | 168 } |
| 172 | 169 |
| 173 float Font::drawUncachedText(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, | 170 float Font::drawUncachedText(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, |
| 174 const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction)
const | 171 const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction)
const |
| 175 { | 172 { |
| 176 // Don't draw anything while we are using custom fonts that are in the proce
ss of loading, | 173 // 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 | 174 // except if the 'force' argument is set to true (in which case it will use
a fallback |
| 178 // font). | 175 // font). |
| 179 if (shouldSkipDrawing() && customFontNotReadyAction == DoNotPaintIfFontNotRe
ady) | 176 if (shouldSkipDrawing() && customFontNotReadyAction == DoNotPaintIfFontNotRe
ady) |
| 180 return 0; | 177 return 0; |
| 181 | 178 |
| 182 TextDrawingModeFlags textMode = context->textDrawingMode(); | 179 TextDrawingModeFlags textMode = context->textDrawingMode(); |
| 183 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context->
hasStroke())) | 180 if (!(textMode & TextModeFill) && !((textMode & TextModeStroke) && context->
hasStroke())) |
| 184 return 0; | 181 return 0; |
| 185 | 182 |
| 186 GlyphBuffer glyphBuffer; | 183 GlyphBuffer glyphBuffer; |
| 187 float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer); | 184 float totalAdvance = buildGlyphBuffer(runInfo, glyphBuffer); |
| 188 | 185 |
| 189 if (glyphBuffer.isEmpty()) | 186 if (glyphBuffer.isEmpty()) |
| 190 return 0; | 187 return 0; |
| 191 | 188 |
| 192 return drawGlyphBuffer(context, runInfo, glyphBuffer, FloatPoint(point.x() +
initialAdvance, point.y())); | 189 drawGlyphBuffer(context, runInfo, glyphBuffer, point); |
| 190 |
| 191 return totalAdvance; |
| 193 } | 192 } |
| 194 | 193 |
| 195 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, const AtomicString& mark, const FloatPoint& point) const | 194 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, const AtomicString& mark, const FloatPoint& point) const |
| 196 { | 195 { |
| 197 if (shouldSkipDrawing()) | 196 if (shouldSkipDrawing()) |
| 198 return; | 197 return; |
| 199 | 198 |
| 200 GlyphBuffer glyphBuffer; | 199 GlyphBuffer glyphBuffer; |
| 201 float initialAdvance = buildGlyphBuffer(runInfo, glyphBuffer, ForTextEmphasi
s); | 200 buildGlyphBuffer(runInfo, glyphBuffer, ForTextEmphasis); |
| 202 | 201 |
| 203 if (glyphBuffer.isEmpty()) | 202 if (glyphBuffer.isEmpty()) |
| 204 return; | 203 return; |
| 205 | 204 |
| 206 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x()
+ initialAdvance, point.y())); | 205 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, point); |
| 207 } | 206 } |
| 208 | 207 |
| 209 static inline void updateGlyphOverflowFromBounds(const IntRectExtent& glyphBound
s, | 208 static inline void updateGlyphOverflowFromBounds(const IntRectExtent& glyphBound
s, |
| 210 const FontMetrics& fontMetrics, GlyphOverflow* glyphOverflow) | 209 const FontMetrics& fontMetrics, GlyphOverflow* glyphOverflow) |
| 211 { | 210 { |
| 212 glyphOverflow->top = std::max<int>(glyphOverflow->top, | 211 glyphOverflow->top = std::max<int>(glyphOverflow->top, |
| 213 glyphBounds.top() - (glyphOverflow->computeBounds ? 0 : fontMetrics.asce
nt())); | 212 glyphBounds.top() - (glyphOverflow->computeBounds ? 0 : fontMetrics.asce
nt())); |
| 214 glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, | 213 glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, |
| 215 glyphBounds.bottom() - (glyphOverflow->computeBounds ? 0 : fontMetrics.d
escent())); | 214 glyphBounds.bottom() - (glyphOverflow->computeBounds ? 0 : fontMetrics.d
escent())); |
| 216 glyphOverflow->left = glyphBounds.left(); | 215 glyphOverflow->left = glyphBounds.left(); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) { | 251 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) { |
| 253 cacheEntry->glyphBounds = glyphBounds; | 252 cacheEntry->glyphBounds = glyphBounds; |
| 254 cacheEntry->width = result; | 253 cacheEntry->width = result; |
| 255 } | 254 } |
| 256 | 255 |
| 257 if (glyphOverflow) | 256 if (glyphOverflow) |
| 258 updateGlyphOverflowFromBounds(glyphBounds, fontMetrics(), glyphOverflow)
; | 257 updateGlyphOverflowFromBounds(glyphBounds, fontMetrics(), glyphOverflow)
; |
| 259 return result; | 258 return result; |
| 260 } | 259 } |
| 261 | 260 |
| 262 namespace { | 261 PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, const FloatR
ect& bounds, |
| 262 bool couldUseLCD) const |
| 263 { |
| 264 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 263 | 265 |
| 264 template <bool hasOffsets> | 266 SkTextBlobBuilder builder; |
| 265 bool buildTextBlobInternal(const GlyphBuffer& glyphBuffer, SkScalar initialAdvan
ce, | 267 SkRect skBounds = bounds; |
| 266 const SkRect* bounds, bool couldUseLCD, SkTextBlobBuilder& builder) | 268 bool hasVerticalOffsets = glyphBuffer.hasVerticalOffsets(); |
| 267 { | 269 |
| 268 SkScalar x = initialAdvance; | |
| 269 unsigned i = 0; | 270 unsigned i = 0; |
| 270 while (i < glyphBuffer.size()) { | 271 while (i < glyphBuffer.size()) { |
| 271 const SimpleFontData* fontData = glyphBuffer.fontDataAt(i); | 272 const SimpleFontData* fontData = glyphBuffer.fontDataAt(i); |
| 272 | 273 |
| 273 // FIXME: Handle vertical text. | 274 // FIXME: Handle vertical text. |
| 274 if (fontData->platformData().orientation() == Vertical) | 275 if (fontData->platformData().orientation() == Vertical) |
| 275 return false; | 276 return nullptr; |
| 276 | 277 |
| 277 // FIXME: FontPlatformData makes some decisions on the device scale | 278 // FIXME: FontPlatformData makes some decisions on the device scale |
| 278 // factor, which is found via the GraphicsContext. This should be fixed | 279 // factor, which is found via the GraphicsContext. This should be fixed |
| 279 // to avoid correctness problems here. | 280 // to avoid correctness problems here. |
| 280 SkPaint paint; | 281 SkPaint paint; |
| 281 fontData->platformData().setupPaint(&paint); | 282 fontData->platformData().setupPaint(&paint); |
| 282 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 283 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 283 | 284 |
| 284 // FIXME: this should go away after the big LCD cleanup. | 285 // FIXME: this should go away after the big LCD cleanup. |
| 285 paint.setLCDRenderText(paint.isLCDRenderText() && couldUseLCD); | 286 paint.setLCDRenderText(paint.isLCDRenderText() && couldUseLCD); |
| 286 | 287 |
| 287 unsigned start = i++; | 288 unsigned start = i++; |
| 288 while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData) | 289 while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData) |
| 289 i++; | 290 i++; |
| 290 unsigned count = i - start; | 291 unsigned count = i - start; |
| 291 | 292 |
| 292 const SkTextBlobBuilder::RunBuffer& buffer = hasOffsets ? | 293 const SkTextBlobBuilder::RunBuffer& buffer = hasVerticalOffsets |
| 293 builder.allocRunPos(paint, count, bounds) : | 294 ? builder.allocRunPos(paint, count, &skBounds) |
| 294 builder.allocRunPosH(paint, count, 0, bounds); | 295 : builder.allocRunPosH(paint, count, 0, &skBounds); |
| 295 | 296 |
| 296 const uint16_t* glyphs = glyphBuffer.glyphs(start); | 297 const uint16_t* glyphs = glyphBuffer.glyphs(start); |
| 298 const float* offsets = glyphBuffer.offsets(start); |
| 297 std::copy(glyphs, glyphs + count, buffer.glyphs); | 299 std::copy(glyphs, glyphs + count, buffer.glyphs); |
| 300 std::copy(offsets, offsets + (hasVerticalOffsets ? 2 * count : count), b
uffer.pos); |
| 301 } |
| 298 | 302 |
| 299 const float* advances = glyphBuffer.advances(start); | 303 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 } | 304 } |
| 331 | 305 |
| 332 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) | 306 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) |
| 333 { | 307 { |
| 334 // Using roundf() rather than ceilf() for the right edge as a compromise to | 308 // Using roundf() rather than ceilf() for the right edge as a compromise to |
| 335 // ensure correct caret positioning. | 309 // ensure correct caret positioning. |
| 336 float roundedX = roundf(rect.x()); | 310 float roundedX = roundf(rect.x()); |
| 337 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), rect.he
ight()); | 311 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), rect.he
ight()); |
| 338 } | 312 } |
| 339 | 313 |
| (...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 SkPaint paint = textFillPaint(gc, font); | 781 SkPaint paint = textFillPaint(gc, font); |
| 808 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe
ct, paint); | 782 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe
ct, paint); |
| 809 } | 783 } |
| 810 | 784 |
| 811 if ((textMode & TextModeStroke) && gc->hasStroke()) { | 785 if ((textMode & TextModeStroke) && gc->hasStroke()) { |
| 812 SkPaint paint = textStrokePaint(gc, font, textMode & TextModeFill); | 786 SkPaint paint = textStrokePaint(gc, font, textMode & TextModeFill); |
| 813 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe
ct, paint); | 787 gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRe
ct, paint); |
| 814 } | 788 } |
| 815 } | 789 } |
| 816 | 790 |
| 791 static void drawVerticalGlyphs(GraphicsContext* gc, const SimpleFontData* font, |
| 792 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const Flo
atPoint& point, |
| 793 const FloatRect& textRect) |
| 794 { |
| 795 const OpenTypeVerticalData* verticalData = font->verticalData(); |
| 796 |
| 797 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); |
| 798 SkPoint* pos = storage.get(); |
| 799 |
| 800 // Bend over backwards to preserve legacy rounding. |
| 801 float initialAdvance = glyphBuffer.xOffsetAt(from); |
| 802 FloatPoint adjustedPoint(point.x() + initialAdvance, point.y()); |
| 803 |
| 804 AffineTransform savedMatrix = gc->getCTM(); |
| 805 gc->concatCTM(AffineTransform(0, -1, 1, 0, adjustedPoint.x(), adjustedPoint.
y())); |
| 806 gc->concatCTM(AffineTransform(1, 0, 0, 1, -adjustedPoint.x(), -adjustedPoint
.y())); |
| 807 |
| 808 const unsigned kMaxBufferLength = 256; |
| 809 Vector<FloatPoint, kMaxBufferLength> translations; |
| 810 |
| 811 const FontMetrics& metrics = font->fontMetrics(); |
| 812 float verticalOriginX = adjustedPoint.x() + metrics.floatAscent() - metrics.
floatAscent(IdeographicBaseline); |
| 813 |
| 814 unsigned glyphIndex = 0; |
| 815 while (glyphIndex < numGlyphs) { |
| 816 unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphIndex
); |
| 817 |
| 818 const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); |
| 819 |
| 820 translations.resize(chunkLength); |
| 821 verticalData->getVerticalTranslationsForGlyphs(font, glyphs, chunkLength
, |
| 822 reinterpret_cast<float*>(&translations[0])); |
| 823 |
| 824 for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { |
| 825 SkScalar x = verticalOriginX + lroundf(translations[i].x()); |
| 826 SkScalar y = adjustedPoint.y() - SkIntToScalar( |
| 827 -lroundf(glyphBuffer.xOffsetAt(from + glyphIndex) - initialAdvan
ce - translations[i].y())); |
| 828 pos[i].set(x, y); |
| 829 } |
| 830 paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); |
| 831 } |
| 832 |
| 833 gc->setCTM(savedMatrix); |
| 834 } |
| 835 |
| 817 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, | 836 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, |
| 818 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, | 837 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, |
| 819 const FloatPoint& point, const FloatRect& textRect) const | 838 const FloatPoint& point, const FloatRect& textRect) const |
| 820 { | 839 { |
| 821 SkScalar x = SkFloatToScalar(point.x()); | 840 ASSERT(glyphBuffer.size() >= from + numGlyphs); |
| 822 SkScalar y = SkFloatToScalar(point.y()); | |
| 823 | 841 |
| 824 const OpenTypeVerticalData* verticalData = font->verticalData(); | 842 if (font->platformData().orientation() == Vertical && font->verticalData())
{ |
| 825 if (font->platformData().orientation() == Vertical && verticalData) { | 843 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; | 844 return; |
| 864 } | 845 } |
| 865 | 846 |
| 866 if (!glyphBuffer.hasOffsets()) { | 847 if (!glyphBuffer.hasVerticalOffsets()) { |
| 867 SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); | 848 SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); |
| 868 SkScalar* xpos = storage.get(); | 849 SkScalar* xpos = storage.get(); |
| 869 const float* adv = glyphBuffer.advances(from); | 850 for (unsigned i = 0; i < numGlyphs; i++) |
| 870 for (unsigned i = 0; i < numGlyphs; i++) { | 851 xpos[i] = SkFloatToScalar(point.x() + glyphBuffer.xOffsetAt(from + i
)); |
| 871 xpos[i] = x; | 852 |
| 872 x += SkFloatToScalar(adv[i]); | 853 paintGlyphsHorizontal(gc, font, glyphBuffer.glyphs(from), numGlyphs, xpo
s, |
| 873 } | 854 SkFloatToScalar(point.y()), textRect); |
| 874 const Glyph* glyphs = glyphBuffer.glyphs(from); | |
| 875 paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar
(y), textRect); | |
| 876 return; | 855 return; |
| 877 } | 856 } |
| 878 | 857 |
| 879 ASSERT(glyphBuffer.hasOffsets()); | 858 ASSERT(glyphBuffer.hasVerticalOffsets()); |
| 880 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); | 859 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); |
| 881 SkPoint* pos = storage.get(); | 860 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++) { | 861 for (unsigned i = 0; i < numGlyphs; i++) { |
| 886 pos[i].set( | 862 pos[i].set( |
| 887 x + SkFloatToScalar(offsets[i].width()) + advanceSoFar, | 863 SkFloatToScalar(point.x() + glyphBuffer.xOffsetAt(from + i)), |
| 888 y + SkFloatToScalar(offsets[i].height())); | 864 SkFloatToScalar(point.y() + glyphBuffer.yOffsetAt(from + i))); |
| 889 advanceSoFar += SkFloatToScalar(advances[i]); | |
| 890 } | 865 } |
| 891 | 866 |
| 892 const Glyph* glyphs = glyphBuffer.glyphs(from); | 867 paintGlyphs(gc, font, glyphBuffer.glyphs(from), numGlyphs, pos, textRect); |
| 893 paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); | |
| 894 } | 868 } |
| 895 | 869 |
| 896 void Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoi
nt& origin) const | 870 void Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoi
nt& origin) const |
| 897 { | 871 { |
| 898 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); | 872 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 899 | 873 |
| 900 TextDrawingModeFlags textMode = gc->textDrawingMode(); | 874 TextDrawingModeFlags textMode = gc->textDrawingMode(); |
| 901 if (textMode & TextModeFill) | 875 if (textMode & TextModeFill) |
| 902 gc->drawTextBlob(blob, origin, gc->fillPaint()); | 876 gc->drawTextBlob(blob, origin, gc->fillPaint()); |
| 903 | 877 |
| (...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. | 910 // Return the rectangle for selecting the given range of code-points in the Text
Run. |
| 937 FloatRect Font::selectionRectForComplexText(const TextRun& run, | 911 FloatRect Font::selectionRectForComplexText(const TextRun& run, |
| 938 const FloatPoint& point, int height, int from, int to) const | 912 const FloatPoint& point, int height, int from, int to) const |
| 939 { | 913 { |
| 940 HarfBuzzShaper shaper(this, run); | 914 HarfBuzzShaper shaper(this, run); |
| 941 if (!shaper.shape()) | 915 if (!shaper.shape()) |
| 942 return FloatRect(); | 916 return FloatRect(); |
| 943 return shaper.selectionRect(point, height, from, to); | 917 return shaper.selectionRect(point, height, from, to); |
| 944 } | 918 } |
| 945 | 919 |
| 946 float Font::drawGlyphBuffer(GraphicsContext* context, | 920 void Font::drawGlyphBuffer(GraphicsContext* context, |
| 947 const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, | 921 const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, |
| 948 const FloatPoint& point) const | 922 const FloatPoint& point) const |
| 949 { | 923 { |
| 950 // Draw each contiguous run of glyphs that use the same font data. | 924 // Draw each contiguous run of glyphs that use the same font data. |
| 951 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); | 925 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); |
| 952 FloatPoint startPoint(point); | |
| 953 float advanceSoFar = 0; | |
| 954 unsigned lastFrom = 0; | 926 unsigned lastFrom = 0; |
| 955 unsigned nextGlyph = 0; | 927 unsigned nextGlyph; |
| 956 | 928 |
| 957 while (nextGlyph < glyphBuffer.size()) { | 929 for (nextGlyph = 0; nextGlyph < glyphBuffer.size(); ++nextGlyph) { |
| 958 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); | 930 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); |
| 959 | 931 |
| 960 if (nextFontData != fontData) { | 932 if (nextFontData != fontData) { |
| 961 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - las
tFrom, startPoint, runInfo.bounds); | 933 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - las
tFrom, point, |
| 934 runInfo.bounds); |
| 962 | 935 |
| 963 lastFrom = nextGlyph; | 936 lastFrom = nextGlyph; |
| 964 fontData = nextFontData; | 937 fontData = nextFontData; |
| 965 startPoint += FloatSize(advanceSoFar, 0); | |
| 966 advanceSoFar = 0; | |
| 967 } | 938 } |
| 968 advanceSoFar += glyphBuffer.advanceAt(nextGlyph); | |
| 969 nextGlyph++; | |
| 970 } | 939 } |
| 971 | 940 |
| 972 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, s
tartPoint, runInfo.bounds); | 941 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, p
oint, |
| 973 startPoint += FloatSize(advanceSoFar, 0); | 942 runInfo.bounds); |
| 974 return startPoint.x() - point.x(); | |
| 975 } | 943 } |
| 976 | 944 |
| 977 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph
glyph) | 945 inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph
glyph) |
| 978 { | 946 { |
| 979 if (fontData->platformData().orientation() == Horizontal) { | 947 if (fontData->platformData().orientation() == Horizontal) { |
| 980 FloatRect bounds = fontData->boundsForGlyph(glyph); | 948 FloatRect bounds = fontData->boundsForGlyph(glyph); |
| 981 return bounds.x() + bounds.width() / 2; | 949 return bounds.x() + bounds.width() / 2; |
| 982 } | 950 } |
| 983 // FIXME: Use glyph bounds once they make sense for vertical fonts. | 951 // FIXME: Use glyph bounds once they make sense for vertical fonts. |
| 984 return fontData->widthForGlyph(glyph) / 2; | 952 return fontData->widthForGlyph(glyph) / 2; |
| 985 } | 953 } |
| 986 | 954 |
| 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 | 955 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoi
nt& point) const |
| 993 { | 956 { |
| 994 FontCachePurgePreventer purgePreventer; | 957 FontCachePurgePreventer purgePreventer; |
| 995 | 958 |
| 996 GlyphData markGlyphData; | 959 GlyphData markGlyphData; |
| 997 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) | 960 if (!getEmphasisMarkGlyphData(mark, markGlyphData)) |
| 998 return; | 961 return; |
| 999 | 962 |
| 1000 const SimpleFontData* markFontData = markGlyphData.fontData; | 963 const SimpleFontData* markFontData = markGlyphData.fontData; |
| 1001 ASSERT(markFontData); | 964 ASSERT(markFontData); |
| 1002 if (!markFontData) | 965 if (!markFontData) |
| 1003 return; | 966 return; |
| 1004 | 967 |
| 1005 Glyph markGlyph = markGlyphData.glyph; | 968 GlyphBuffer markBuffer; |
| 1006 Glyph spaceGlyph = markFontData->spaceGlyph(); | 969 float midMarkOffset = offsetToMiddleOfGlyph(markFontData, markGlyphData.glyp
h); |
| 970 for (unsigned i = 0; i < glyphBuffer.size(); ++i) { |
| 971 // Skip marks for suppressed glyphs. |
| 972 if (!glyphBuffer.glyphAt(i)) |
| 973 continue; |
| 1007 | 974 |
| 1008 float middleOfLastGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, 0); | 975 // We want the middle of the emphasis mark aligned with the middle of th
e glyph. |
| 1009 FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(
markFontData, markGlyph), point.y()); | 976 // The input offsets are already adjusted to point to the middle of the
glyph, so all |
| 977 // is left to do is adjust for 1/2 mark width. |
| 978 // FIXME: we could avoid this by passing some additional info to the sha
per, |
| 979 // and perform all adjustments at buffer build time. |
| 980 markBuffer.add(markGlyphData.glyph, markFontData, glyphBuffer.xOffsetAt(
i) - midMarkOffset); |
| 981 } |
| 1010 | 982 |
| 1011 GlyphBuffer markBuffer; | 983 drawGlyphBuffer(context, runInfo, markBuffer, point); |
| 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 } | 984 } |
| 1022 | 985 |
| 1023 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFont
Data*>* fallbackFonts, IntRectExtent* glyphBounds) const | 986 float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFont
Data*>* fallbackFonts, IntRectExtent* glyphBounds) const |
| 1024 { | 987 { |
| 1025 SimpleShaper::GlyphBounds bounds; | 988 SimpleShaper::GlyphBounds bounds; |
| 1026 SimpleShaper shaper(this, run, fallbackFonts, glyphBounds ? &bounds : 0); | 989 SimpleShaper shaper(this, run, fallbackFonts, glyphBounds ? &bounds : 0); |
| 1027 shaper.advance(run.length()); | 990 shaper.advance(run.length()); |
| 1028 | 991 |
| 1029 if (glyphBounds) { | 992 if (glyphBounds) { |
| 1030 glyphBounds->setTop(floorf(-bounds.minGlyphBoundingBoxY)); | 993 glyphBounds->setTop(floorf(-bounds.minGlyphBoundingBoxY)); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 if (delta <= 0) | 1059 if (delta <= 0) |
| 1097 break; | 1060 break; |
| 1098 } | 1061 } |
| 1099 } | 1062 } |
| 1100 } | 1063 } |
| 1101 | 1064 |
| 1102 return offset; | 1065 return offset; |
| 1103 } | 1066 } |
| 1104 | 1067 |
| 1105 } // namespace blink | 1068 } // namespace blink |
| OLD | NEW |