1 /* 2 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 29 */ 30 31 #include "config.h" 32 #include "platform/fonts/Font.h" 33 34 #include "platform/NotImplemented.h" 35 #include "platform/fonts/FontPlatformFeatures.h" 36 #include "platform/fonts/SimpleFontData.h" 37 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" 38 #include "platform/fonts/GlyphBuffer.h" 39 #include "platform/geometry/FloatRect.h" 40 #include "platform/graphics/GraphicsContext.h" 41 42 #include "SkPaint.h" 43 #include "SkTemplates.h" 44 45 #include "wtf/unicode/Unicode.h" 46 47 namespace WebCore { 48 49 bool FontPlatformFeatures::canReturnFallbackFontsForComplexText() 50 { 51 return false; 52 } 53 54 bool FontPlatformFeatures::canExpandAroundIdeographsInComplexText() 55 { 56 return false; 57 } 58 59 static void paintGlyphs(GraphicsContext* gc, const SimpleFontData* font, 60 const Glyph* glyphs, unsigned numGlyphs, 61 SkPoint* pos, const FloatRect& textRect) 62 { 63 TextDrawingModeFlags textMode = gc->textDrawingMode(); 64 65 // We draw text up to two times (once for fill, once for stroke). 66 if (textMode & TextModeFill) { 67 SkPaint paint = gc->fillPaint(); 68 font->platformData().setupPaint(&paint, gc); 69 gc->adjustTextRenderMode(&paint); 70 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 71 72 gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); 73 } 74 75 if ((textMode & TextModeStroke) 76 && gc->strokeStyle() != NoStroke 77 && gc->strokeThickness() > 0) { 78 79 SkPaint paint = gc->strokePaint(); 80 font->platformData().setupPaint(&paint, gc); 81 gc->adjustTextRenderMode(&paint); 82 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 83 84 if (textMode & TextModeFill) { 85 // If there is a shadow and we filled above, there will already be 86 // a shadow. We don't want to draw it again or it will be too dark 87 // and it will go on top of the fill. 88 // 89 // Note that this isn't strictly correct, since the stroke could be 90 // very thick and the shadow wouldn't account for this. The "right" 91 // thing would be to draw to a new layer and then draw that layer 92 // with a shadow. But this is a lot of extra work for something 93 // that isn't normally an issue. 94 paint.setLooper(0); 95 } 96 97 gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); 98 } 99 } 100 101 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, 102 const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, 103 const FloatPoint& point, const FloatRect& textRect) const 104 { 105 SkScalar x = SkFloatToScalar(point.x()); 106 SkScalar y = SkFloatToScalar(point.y()); 107 108 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); 109 SkPoint* pos = storage.get(); 110 111 const OpenTypeVerticalData* verticalData = font->verticalData(); 112 if (font->platformData().orientation() == Vertical && verticalData) { 113 AffineTransform savedMatrix = gc->getCTM(); 114 gc->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y())); 115 gc->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y())); 116 117 const unsigned kMaxBufferLength = 256; 118 Vector<FloatPoint, kMaxBufferLength> translations; 119 120 const FontMetrics& metrics = font->fontMetrics(); 121 SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline)); 122 float horizontalOffset = point.x(); 123 124 unsigned glyphIndex = 0; 125 while (glyphIndex < numGlyphs) { 126 unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphIndex); 127 128 const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); 129 translations.resize(chunkLength); 130 verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chunkLength, reinterpret_cast<float*>(&translations[0])); 131 132 x = verticalOriginX; 133 y = SkFloatToScalar(point.y() + horizontalOffset - point.x()); 134 135 float currentWidth = 0; 136 for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { 137 pos[i].set( 138 x + SkIntToScalar(lroundf(translations[i].x())), 139 y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y()))); 140 currentWidth += glyphBuffer.advanceAt(from + glyphIndex).width(); 141 } 142 horizontalOffset += currentWidth; 143 paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); 144 } 145 146 gc->setCTM(savedMatrix); 147 return; 148 } 149 150 // FIXME: text rendering speed: 151 // Android has code in their WebCore fork to special case when the 152 // GlyphBuffer has no advances other than the defaults. In that case the 153 // text drawing can proceed faster. However, it's unclear when those 154 // patches may be upstreamed to WebKit so we always use the slower path 155 // here. 156 const FloatSize* adv = glyphBuffer.advances(from); 157 for (unsigned i = 0; i < numGlyphs; i++) { 158 pos[i].set(x, y); 159 x += SkFloatToScalar(adv[i].width()); 160 y += SkFloatToScalar(adv[i].height()); 161 } 162 163 const Glyph* glyphs = glyphBuffer.glyphs(from); 164 paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); 165 } 166 167 void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const 168 { 169 if (!runInfo.run.length()) 170 return; 171 172 TextDrawingModeFlags textMode = gc->textDrawingMode(); 173 bool fill = textMode & TextModeFill; 174 bool stroke = (textMode & TextModeStroke) 175 && gc->strokeStyle() != NoStroke 176 && gc->strokeThickness() > 0; 177 178 if (!fill && !stroke) 179 return; 180 181 GlyphBuffer glyphBuffer; 182 HarfBuzzShaper shaper(this, runInfo.run); 183 shaper.setDrawRange(runInfo.from, runInfo.to); 184 if (!shaper.shape(&glyphBuffer) || glyphBuffer.isEmpty()) 185 return; 186 FloatPoint adjustedPoint = shaper.adjustStartPoint(point); 187 drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint); 188 } 189 190 void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const 191 { 192 GlyphBuffer glyphBuffer; 193 194 float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer, ForTextEmphasis); 195 196 if (glyphBuffer.isEmpty()) 197 return; 198 199 drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); 200 } 201 202 float Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const 203 { 204 HarfBuzzShaper shaper(this, runInfo.run, HarfBuzzShaper::ForTextEmphasis); 205 shaper.setDrawRange(runInfo.from, runInfo.to); 206 shaper.shape(&glyphBuffer); 207 return 0; 208 } 209 210 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, IntRectExtent* glyphBounds) const 211 { 212 HarfBuzzShaper shaper(this, run); 213 if (!shaper.shape()) 214 return 0; 215 216 glyphBounds->setTop(floorf(-shaper.glyphBoundingBox().top())); 217 glyphBounds->setBottom(ceilf(shaper.glyphBoundingBox().bottom())); 218 glyphBounds->setLeft(std::max<int>(0, floorf(-shaper.glyphBoundingBox().left()))); 219 glyphBounds->setRight(std::max<int>(0, ceilf(shaper.glyphBoundingBox().right() - shaper.totalWidth()))); 220 221 return shaper.totalWidth(); 222 } 223 224 // Return the code point index for the given |x| offset into the text run. 225 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, 226 bool includePartialGlyphs) const 227 { 228 HarfBuzzShaper shaper(this, run); 229 if (!shaper.shape()) 230 return 0; 231 return shaper.offsetForPosition(xFloat); 232 } 233 234 // Return the rectangle for selecting the given range of code-points in the TextRun. 235 FloatRect Font::selectionRectForComplexText(const TextRun& run, 236 const FloatPoint& point, int height, 237 int from, int to) const 238 { 239 HarfBuzzShaper shaper(this, run); 240 if (!shaper.shape()) 241 return FloatRect(); 242 return shaper.selectionRect(point, height, from, to); 243 } 244 245 } // namespace WebCore 246