OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. | 2 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 13 matching lines...) Expand all Loading... |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "sky/engine/config.h" | 31 #include "sky/engine/config.h" |
32 #include "sky/engine/platform/fonts/Font.h" | 32 #include "sky/engine/platform/fonts/Font.h" |
33 | 33 |
34 #include "sky/engine/platform/NotImplemented.h" | 34 #include "gen/sky/platform/RuntimeEnabledFeatures.h" |
35 #include "sky/engine/platform/fonts/FontPlatformFeatures.h" | 35 #include "sky/engine/platform/fonts/FontPlatformFeatures.h" |
36 #include "sky/engine/platform/fonts/GlyphBuffer.h" | 36 #include "sky/engine/platform/fonts/GlyphBuffer.h" |
37 #include "sky/engine/platform/fonts/SimpleFontData.h" | 37 #include "sky/engine/platform/fonts/SimpleFontData.h" |
38 #include "sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.h" | 38 #include "sky/engine/platform/fonts/harfbuzz/HarfBuzzShaper.h" |
39 #include "sky/engine/platform/geometry/FloatRect.h" | 39 #include "sky/engine/platform/geometry/FloatRect.h" |
40 #include "sky/engine/platform/graphics/GraphicsContext.h" | 40 #include "sky/engine/platform/graphics/GraphicsContext.h" |
41 | 41 |
42 #include "third_party/skia/include/core/SkPaint.h" | 42 #include "third_party/skia/include/core/SkPaint.h" |
43 #include "third_party/skia/include/core/SkTemplates.h" | 43 #include "third_party/skia/include/core/SkTemplates.h" |
44 | 44 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chu
nkLength, reinterpret_cast<float*>(&translations[0])); | 150 verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chu
nkLength, reinterpret_cast<float*>(&translations[0])); |
151 | 151 |
152 x = verticalOriginX; | 152 x = verticalOriginX; |
153 y = SkFloatToScalar(point.y() + horizontalOffset - point.x()); | 153 y = SkFloatToScalar(point.y() + horizontalOffset - point.x()); |
154 | 154 |
155 float currentWidth = 0; | 155 float currentWidth = 0; |
156 for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { | 156 for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { |
157 pos[i].set( | 157 pos[i].set( |
158 x + SkIntToScalar(lroundf(translations[i].x())), | 158 x + SkIntToScalar(lroundf(translations[i].x())), |
159 y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y
()))); | 159 y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y
()))); |
160 currentWidth += glyphBuffer.advanceAt(from + glyphIndex).width()
; | 160 currentWidth += glyphBuffer.advanceAt(from + glyphIndex); |
161 } | 161 } |
162 horizontalOffset += currentWidth; | 162 horizontalOffset += currentWidth; |
163 paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); | 163 paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); |
164 } | 164 } |
165 | 165 |
166 gc->setCTM(savedMatrix); | 166 gc->setCTM(savedMatrix); |
167 return; | 167 return; |
168 } | 168 } |
169 | 169 |
170 if (!glyphBuffer.hasVerticalAdvances()) { | 170 if (!glyphBuffer.hasOffsets()) { |
171 SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); | 171 SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); |
172 SkScalar* xpos = storage.get(); | 172 SkScalar* xpos = storage.get(); |
173 const FloatSize* adv = glyphBuffer.advances(from); | 173 const float* adv = glyphBuffer.advances(from); |
174 for (unsigned i = 0; i < numGlyphs; i++) { | 174 for (unsigned i = 0; i < numGlyphs; i++) { |
175 xpos[i] = x; | 175 xpos[i] = x; |
176 x += SkFloatToScalar(adv[i].width()); | 176 x += SkFloatToScalar(adv[i]); |
177 } | 177 } |
178 const Glyph* glyphs = glyphBuffer.glyphs(from); | 178 const Glyph* glyphs = glyphBuffer.glyphs(from); |
179 paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar
(y), textRect); | 179 paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar
(y), textRect); |
180 return; | 180 return; |
181 } | 181 } |
182 | 182 |
183 // FIXME: text rendering speed: | 183 // FIXME: text rendering speed: |
184 // Android has code in their WebCore fork to special case when the | 184 // Android has code in their WebCore fork to special case when the |
185 // GlyphBuffer has no advances other than the defaults. In that case the | 185 // GlyphBuffer has no advances other than the defaults. In that case the |
186 // text drawing can proceed faster. However, it's unclear when those | 186 // text drawing can proceed faster. However, it's unclear when those |
187 // patches may be upstreamed to WebKit so we always use the slower path | 187 // patches may be upstreamed to WebKit so we always use the slower path |
188 // here. | 188 // here. |
189 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); | 189 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); |
190 SkPoint* pos = storage.get(); | 190 SkPoint* pos = storage.get(); |
191 const FloatSize* adv = glyphBuffer.advances(from); | 191 const FloatSize* offsets = glyphBuffer.offsets(from); |
| 192 const float* advances = glyphBuffer.advances(from); |
| 193 SkScalar advanceSoFar = SkFloatToScalar(0); |
192 for (unsigned i = 0; i < numGlyphs; i++) { | 194 for (unsigned i = 0; i < numGlyphs; i++) { |
193 pos[i].set(x, y); | 195 pos[i].set( |
194 x += SkFloatToScalar(adv[i].width()); | 196 x + SkFloatToScalar(offsets[i].width()) + advanceSoFar, |
195 y += SkFloatToScalar(adv[i].height()); | 197 y + SkFloatToScalar(offsets[i].height())); |
| 198 advanceSoFar += SkFloatToScalar(advances[i]); |
196 } | 199 } |
197 | 200 |
198 const Glyph* glyphs = glyphBuffer.glyphs(from); | 201 const Glyph* glyphs = glyphBuffer.glyphs(from); |
199 paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); | 202 paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); |
200 } | 203 } |
201 | 204 |
202 void Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoi
nt& origin) const | 205 void Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoi
nt& origin) const |
203 { | 206 { |
| 207 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 208 |
204 // FIXME: It would be good to move this to Font.cpp, if we're sure that none | 209 // FIXME: It would be good to move this to Font.cpp, if we're sure that none |
205 // of the things in FontMac's setupPaint need to apply here. | 210 // of the things in FontMac's setupPaint need to apply here. |
206 // See also paintGlyphs. | 211 // See also paintGlyphs. |
207 TextDrawingModeFlags textMode = gc->textDrawingMode(); | 212 TextDrawingModeFlags textMode = gc->textDrawingMode(); |
208 | 213 |
209 if (textMode & TextModeFill) { | 214 if (textMode & TextModeFill) |
210 SkPaint paint = gc->fillPaint(); | 215 gc->drawTextBlob(blob, origin, gc->fillPaint()); |
211 gc->adjustTextRenderMode(&paint); | |
212 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
213 gc->drawTextBlob(blob, origin, paint); | |
214 } | |
215 | 216 |
216 if ((textMode & TextModeStroke) && gc->hasStroke()) { | 217 if ((textMode & TextModeStroke) && gc->hasStroke()) { |
217 SkPaint paint = gc->strokePaint(); | 218 SkPaint paint = gc->strokePaint(); |
218 gc->adjustTextRenderMode(&paint); | |
219 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
220 if (textMode & TextModeFill) | 219 if (textMode & TextModeFill) |
221 paint.setLooper(0); | 220 paint.setLooper(0); |
222 gc->drawTextBlob(blob, origin, paint); | 221 gc->drawTextBlob(blob, origin, paint); |
223 } | 222 } |
224 } | 223 } |
225 | 224 |
226 void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo,
const FloatPoint& point) const | |
227 { | |
228 if (!runInfo.run.length()) | |
229 return; | |
230 | |
231 TextDrawingModeFlags textMode = gc->textDrawingMode(); | |
232 bool fill = textMode & TextModeFill; | |
233 bool stroke = (textMode & TextModeStroke) && gc->hasStroke(); | |
234 | |
235 if (!fill && !stroke) | |
236 return; | |
237 | |
238 GlyphBuffer glyphBuffer; | |
239 HarfBuzzShaper shaper(this, runInfo.run); | |
240 shaper.setDrawRange(runInfo.from, runInfo.to); | |
241 if (!shaper.shape(&glyphBuffer) || glyphBuffer.isEmpty()) | |
242 return; | |
243 FloatPoint adjustedPoint = shaper.adjustStartPoint(point); | |
244 drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint); | |
245 } | |
246 | |
247 void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextR
unPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const | |
248 { | |
249 GlyphBuffer glyphBuffer; | |
250 | |
251 float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuff
er, ForTextEmphasis); | |
252 | |
253 if (glyphBuffer.isEmpty()) | |
254 return; | |
255 | |
256 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x()
+ initialAdvance, point.y())); | |
257 } | |
258 | |
259 float Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo,
GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const | |
260 { | |
261 HarfBuzzShaper shaper(this, runInfo.run, HarfBuzzShaper::ForTextEmphasis); | |
262 shaper.setDrawRange(runInfo.from, runInfo.to); | |
263 shaper.shape(&glyphBuffer); | |
264 return 0; | |
265 } | |
266 | |
267 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon
tData*>* fallbackFonts, IntRectExtent* glyphBounds) const | 225 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon
tData*>* fallbackFonts, IntRectExtent* glyphBounds) const |
268 { | 226 { |
269 HarfBuzzShaper shaper(this, run, HarfBuzzShaper::NotForTextEmphasis, fallbac
kFonts); | 227 HarfBuzzShaper shaper(this, run, HarfBuzzShaper::NotForTextEmphasis, fallbac
kFonts); |
270 if (!shaper.shape()) | 228 if (!shaper.shape()) |
271 return 0; | 229 return 0; |
272 | 230 |
273 glyphBounds->setTop(floorf(-shaper.glyphBoundingBox().top())); | 231 glyphBounds->setTop(floorf(-shaper.glyphBoundingBox().top())); |
274 glyphBounds->setBottom(ceilf(shaper.glyphBoundingBox().bottom())); | 232 glyphBounds->setBottom(ceilf(shaper.glyphBoundingBox().bottom())); |
275 glyphBounds->setLeft(std::max<int>(0, floorf(-shaper.glyphBoundingBox().left
()))); | 233 glyphBounds->setLeft(std::max<int>(0, floorf(-shaper.glyphBoundingBox().left
()))); |
276 glyphBounds->setRight(std::max<int>(0, ceilf(shaper.glyphBoundingBox().right
() - shaper.totalWidth()))); | 234 glyphBounds->setRight(std::max<int>(0, ceilf(shaper.glyphBoundingBox().right
() - shaper.totalWidth()))); |
(...skipping 15 matching lines...) Expand all Loading... |
292 FloatRect Font::selectionRectForComplexText(const TextRun& run, | 250 FloatRect Font::selectionRectForComplexText(const TextRun& run, |
293 const FloatPoint& point, int height, | 251 const FloatPoint& point, int height, |
294 int from, int to) const | 252 int from, int to) const |
295 { | 253 { |
296 HarfBuzzShaper shaper(this, run); | 254 HarfBuzzShaper shaper(this, run); |
297 if (!shaper.shape()) | 255 if (!shaper.shape()) |
298 return FloatRect(); | 256 return FloatRect(); |
299 return shaper.selectionRect(point, height, from, to); | 257 return shaper.selectionRect(point, height, from, to); |
300 } | 258 } |
301 | 259 |
302 PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, float initia
lAdvance, const FloatRect& bounds) const | 260 namespace { |
| 261 |
| 262 template <bool hasOffsets> |
| 263 bool buildTextBlobInternal(const GlyphBuffer& glyphBuffer, SkScalar initialAdvan
ce, SkTextBlobBuilder& builder) |
303 { | 264 { |
304 // FIXME: Except for setupPaint, this is not specific to FontHarfBuzz. | 265 SkScalar x = initialAdvance; |
305 // FIXME: Also implement the more general full-positioning path. | |
306 ASSERT(!glyphBuffer.hasVerticalAdvances()); | |
307 | |
308 SkTextBlobBuilder builder; | |
309 SkScalar x = SkFloatToScalar(initialAdvance); | |
310 SkRect skBounds = bounds; | |
311 | |
312 unsigned i = 0; | 266 unsigned i = 0; |
313 while (i < glyphBuffer.size()) { | 267 while (i < glyphBuffer.size()) { |
314 const SimpleFontData* fontData = glyphBuffer.fontDataAt(i); | 268 const SimpleFontData* fontData = glyphBuffer.fontDataAt(i); |
315 | 269 |
316 // FIXME: Handle vertical text. | 270 // FIXME: Handle vertical text. |
317 if (fontData->platformData().orientation() == Vertical) | 271 if (fontData->platformData().orientation() == Vertical) |
318 return nullptr; | 272 return false; |
319 | 273 |
320 // FIXME: Handle SVG fonts. | 274 // FIXME: Handle SVG fonts. |
321 if (fontData->isSVGFont()) | 275 if (fontData->isSVGFont()) |
322 return nullptr; | 276 return false; |
323 | 277 |
324 // FIXME: FontPlatformData makes some decisions on the device scale | 278 // FIXME: FontPlatformData makes some decisions on the device scale |
325 // factor, which is found via the GraphicsContext. This should be fixed | 279 // factor, which is found via the GraphicsContext. This should be fixed |
326 // to avoid correctness problems here. | 280 // to avoid correctness problems here. |
327 SkPaint paint; | 281 SkPaint paint; |
328 fontData->platformData().setupPaint(&paint); | 282 fontData->platformData().setupPaint(&paint); |
329 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 283 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
330 | 284 |
331 unsigned start = i++; | 285 unsigned start = i++; |
332 while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData) | 286 while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData) |
333 i++; | 287 i++; |
334 unsigned count = i - start; | 288 unsigned count = i - start; |
335 | 289 |
336 const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPosH(paint,
count, 0, &skBounds); | 290 const SkTextBlobBuilder::RunBuffer& buffer = hasOffsets ? |
| 291 builder.allocRunPos(paint, count) : |
| 292 builder.allocRunPosH(paint, count, 0); |
337 | 293 |
338 const uint16_t* glyphs = glyphBuffer.glyphs(start); | 294 const uint16_t* glyphs = glyphBuffer.glyphs(start); |
339 std::copy(glyphs, glyphs + count, buffer.glyphs); | 295 std::copy(glyphs, glyphs + count, buffer.glyphs); |
340 | 296 |
341 const FloatSize* advances = glyphBuffer.advances(start); | 297 const float* advances = glyphBuffer.advances(start); |
| 298 const FloatSize* offsets = glyphBuffer.offsets(start); |
342 for (unsigned j = 0; j < count; j++) { | 299 for (unsigned j = 0; j < count; j++) { |
343 buffer.pos[j] = x; | 300 if (hasOffsets) { |
344 x += SkFloatToScalar(advances[j].width()); | 301 const FloatSize& offset = offsets[j]; |
| 302 buffer.pos[2 * j] = x + offset.width(); |
| 303 buffer.pos[2 * j + 1] = offset.height(); |
| 304 } else { |
| 305 buffer.pos[j] = x; |
| 306 } |
| 307 x += SkFloatToScalar(advances[j]); |
345 } | 308 } |
346 } | 309 } |
347 | 310 return true; |
348 return adoptRef(builder.build()); | |
349 } | 311 } |
350 | 312 |
| 313 } // namespace |
| 314 |
| 315 PassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, float initia
lAdvance, const FloatRect& bounds) const |
| 316 { |
| 317 ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); |
| 318 |
| 319 SkTextBlobBuilder builder; |
| 320 SkScalar advance = SkFloatToScalar(initialAdvance); |
| 321 |
| 322 bool success = glyphBuffer.hasOffsets() ? |
| 323 buildTextBlobInternal<true>(glyphBuffer, advance, builder) : |
| 324 buildTextBlobInternal<false>(glyphBuffer, advance, builder); |
| 325 return success ? adoptRef(builder.build()) : nullptr; |
| 326 } |
| 327 |
| 328 |
351 } // namespace blink | 329 } // namespace blink |
OLD | NEW |