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 |