| 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 |