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 "core/platform/graphics/Font.h" 33 34 #include "core/platform/NotImplemented.h" 35 #include "core/platform/graphics/FloatRect.h" 36 #include "core/platform/graphics/GlyphBuffer.h" 37 #include "core/platform/graphics/GraphicsContext.h" 38 #include "core/platform/graphics/SimpleFontData.h" 39 #include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h" 40 41 #include "SkPaint.h" 42 #include "SkTemplates.h" 43 44 #include "wtf/unicode/Unicode.h" 45 46 namespace WebCore { 47 48 bool Font::canReturnFallbackFontsForComplexText() 49 { 50 return false; 51 } 52 53 bool Font::canExpandAroundIdeographsInComplexText() 54 { 55 return false; 56 } 57 58 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, 59 const GlyphBuffer& glyphBuffer, int from, int numGlyphs, 60 const FloatPoint& point, const FloatRect& textRect) const { 61 SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert 62 63 const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); 64 SkScalar x = SkFloatToScalar(point.x()); 65 SkScalar y = SkFloatToScalar(point.y()); 66 67 // FIXME: text rendering speed: 68 // Android has code in their WebCore fork to special case when the 69 // GlyphBuffer has no advances other than the defaults. In that case the 70 // text drawing can proceed faster. However, it's unclear when those 71 // patches may be upstreamed to WebKit so we always use the slower path 72 // here. 73 const GlyphBufferAdvance* adv = glyphBuffer.advances(from); 74 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs); 75 SkPoint* pos = storage.get(); 76 SkPoint* vPosBegin = storage2.get(); 77 SkPoint* vPosEnd = storage3.get(); 78 79 bool isVertical = font->platformData().orientation() == Vertical; 80 SkScalar verticalPosCompensation = isVertical ? SkFloatToScalar((font->fontMetrics().floatHeight() - font->fontMetrics().floatAscent()) / 2) : 0; 81 for (int i = 0; i < numGlyphs; i++) { 82 SkScalar myWidth = SkFloatToScalar(adv[i].width()); 83 pos[i].set(x, y); 84 if (isVertical) { 85 // In vertical mode, we need to align the left of ideographics to the vertical baseline. 86 // (Note vertical/horizontal are in absolute orientation, that is, here x is vertical.) 87 // However, when the glyph is drawn in drawTextOnPath(), the baseline is the horizontal path, 88 // so the ideographics will look shifted to the bottom-right direction because the ascent is 89 // applied vertically. Compensate the position so that ascent will look like to be applied 90 // horizontally. 91 SkScalar bottom = x + myWidth - verticalPosCompensation; 92 SkScalar left = y + verticalPosCompensation; 93 vPosBegin[i].set(bottom, left); 94 vPosEnd[i].set(bottom, left - myWidth); 95 } 96 x += myWidth; 97 y += SkFloatToScalar(adv[i].height()); 98 } 99 100 TextDrawingModeFlags textMode = gc->textDrawingMode(); 101 102 // We draw text up to two times (once for fill, once for stroke). 103 if (textMode & TextModeFill) { 104 SkPaint paint; 105 gc->setupPaintForFilling(&paint); 106 font->platformData().setupPaint(&paint); 107 gc->adjustTextRenderMode(&paint); 108 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 109 110 if (isVertical) { 111 SkPath path; 112 for (int i = 0; i < numGlyphs; ++i) { 113 path.reset(); 114 path.moveTo(vPosBegin[i]); 115 path.lineTo(vPosEnd[i]); 116 gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint); 117 } 118 } else 119 gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint); 120 } 121 122 if ((textMode & TextModeStroke) 123 && gc->strokeStyle() != NoStroke 124 && gc->strokeThickness() > 0) { 125 126 SkPaint paint; 127 gc->setupPaintForStroking(&paint); 128 font->platformData().setupPaint(&paint); 129 gc->adjustTextRenderMode(&paint); 130 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 131 132 if (textMode & TextModeFill) { 133 // If we also filled, we don't want to draw shadows twice. 134 // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. 135 // Since we use the looper for shadows, we remove it (if any) now. 136 paint.setLooper(0); 137 } 138 139 if (isVertical) { 140 SkPath path; 141 for (int i = 0; i < numGlyphs; ++i) { 142 path.reset(); 143 path.moveTo(vPosBegin[i]); 144 path.lineTo(vPosEnd[i]); 145 gc->drawTextOnPath(glyphs + i, 2, path, textRect, 0, paint); 146 } 147 } else 148 gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint); 149 } 150 } 151 152 static void setupForTextPainting(SkPaint* paint, SkColor color) 153 { 154 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 155 paint->setColor(color); 156 } 157 158 void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const 159 { 160 if (!runInfo.run.length()) 161 return; 162 163 TextDrawingModeFlags textMode = gc->textDrawingMode(); 164 bool fill = textMode & TextModeFill; 165 bool stroke = (textMode & TextModeStroke) 166 && gc->strokeStyle() != NoStroke 167 && gc->strokeThickness() > 0; 168 169 if (!fill && !stroke) 170 return; 171 172 SkPaint strokePaint, fillPaint; 173 if (fill) { 174 gc->setupPaintForFilling(&fillPaint); 175 setupForTextPainting(&fillPaint, gc->fillColor().rgb()); 176 } 177 if (stroke) { 178 gc->setupPaintForStroking(&strokePaint); 179 setupForTextPainting(&strokePaint, gc->strokeColor().rgb()); 180 } 181 182 GlyphBuffer glyphBuffer; 183 HarfBuzzShaper shaper(this, runInfo.run); 184 shaper.setDrawRange(runInfo.from, runInfo.to); 185 if (!shaper.shape(&glyphBuffer)) 186 return; 187 FloatPoint adjustedPoint = shaper.adjustStartPoint(point); 188 drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint); 189 } 190 191 void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRunPaintInfo& /* runInfo */, const AtomicString& /* mark */, const FloatPoint& /* point */) const 192 { 193 notImplemented(); 194 } 195 196 float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const 197 { 198 HarfBuzzShaper shaper(this, run); 199 if (!shaper.shape()) 200 return 0; 201 return shaper.totalWidth(); 202 } 203 204 // Return the code point index for the given |x| offset into the text run. 205 int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, 206 bool includePartialGlyphs) const 207 { 208 HarfBuzzShaper shaper(this, run); 209 if (!shaper.shape()) 210 return 0; 211 return shaper.offsetForPosition(xFloat); 212 } 213 214 // Return the rectangle for selecting the given range of code-points in the TextRun. 215 FloatRect Font::selectionRectForComplexText(const TextRun& run, 216 const FloatPoint& point, int height, 217 int from, int to) const 218 { 219 HarfBuzzShaper shaper(this, run); 220 if (!shaper.shape()) 221 return FloatRect(); 222 return shaper.selectionRect(point, height, from, to); 223 } 224 225 } // namespace WebCore 226