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, | |
eae
2014/11/04 15:33:26
Dominik is working on changing our vertical text s
f(malita)
2014/11/04 21:52:22
Ack. IIUC, he's going to make this whole think go
| |
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 |