1 /* 2 * Copyright (c) 2011 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/LayoutTestSupport.h" 35 #include "core/platform/graphics/FontSmoothingMode.h" 36 #include "core/platform/graphics/GlyphBuffer.h" 37 #include "core/platform/graphics/GraphicsContext.h" 38 #include "core/platform/graphics/SimpleFontData.h" 39 40 #include "third_party/skia/include/core/SkCanvas.h" 41 #include "third_party/skia/include/core/SkPaint.h" 42 #include "third_party/skia/include/core/SkTypeface.h" 43 #include "third_party/skia/include/ports/SkTypeface_mac.h" 44 45 namespace WebCore { 46 47 bool Font::canReturnFallbackFontsForComplexText() 48 { 49 return true; 50 } 51 52 bool Font::canExpandAroundIdeographsInComplexText() 53 { 54 return true; 55 } 56 57 static void setupPaint(SkPaint* paint, const SimpleFontData* fontData, const Font* font, bool shouldAntialias, bool shouldSmoothFonts) 58 { 59 const FontPlatformData& platformData = fontData->platformData(); 60 const float textSize = platformData.m_size >= 0 ? platformData.m_size : 12; 61 62 paint->setAntiAlias(shouldAntialias); 63 paint->setEmbeddedBitmapText(false); 64 paint->setTextSize(SkFloatToScalar(textSize)); 65 paint->setVerticalText(platformData.orientation() == Vertical); 66 SkTypeface* typeface = SkCreateTypefaceFromCTFont(platformData.ctFont()); 67 SkAutoUnref autoUnref(typeface); 68 paint->setTypeface(typeface); 69 paint->setFakeBoldText(platformData.m_syntheticBold); 70 paint->setTextSkewX(platformData.m_syntheticOblique ? -SK_Scalar1 / 4 : 0); 71 paint->setAutohinted(false); // freetype specific 72 paint->setLCDRenderText(shouldSmoothFonts); 73 paint->setSubpixelText(true); 74 75 #if OS(DARWIN) 76 // When using CoreGraphics, disable hinting when webkit-font-smoothing:antialiased is used. 77 // See crbug.com/152304 78 if (font->fontDescription().fontSmoothing() == Antialiased) 79 paint->setHinting(SkPaint::kNo_Hinting); 80 #endif 81 82 if (font->fontDescription().textRenderingMode() == GeometricPrecision) 83 paint->setHinting(SkPaint::kNo_Hinting); 84 } 85 86 // TODO: This needs to be split into helper functions to better scope the 87 // inputs/outputs, and reduce duplicate code. 88 // This issue is tracked in https://bugs.webkit.org/show_bug.cgi?id=62989 89 void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, 90 const GlyphBuffer& glyphBuffer, int from, int numGlyphs, 91 const FloatPoint& point, const FloatRect& textRect) const { 92 COMPILE_ASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t), GlyphBufferGlyphSize_equals_uint16_t); 93 94 bool shouldSmoothFonts = true; 95 bool shouldAntialias = true; 96 97 switch (fontDescription().fontSmoothing()) { 98 case Antialiased: 99 shouldSmoothFonts = false; 100 break; 101 case SubpixelAntialiased: 102 break; 103 case NoSmoothing: 104 shouldAntialias = false; 105 shouldSmoothFonts = false; 106 break; 107 case AutoSmoothing: 108 // For the AutoSmooth case, don't do anything! Keep the default settings. 109 break; 110 } 111 112 if (!shouldUseSmoothing() || isRunningLayoutTest()) { 113 shouldSmoothFonts = false; 114 shouldAntialias = false; 115 } 116 117 const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); 118 SkScalar x = SkFloatToScalar(point.x()); 119 SkScalar y = SkFloatToScalar(point.y()); 120 121 if (font->platformData().orientation() == Vertical) 122 y += SkFloatToScalar(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent()); 123 // FIXME: text rendering speed: 124 // Android has code in their WebCore fork to special case when the 125 // GlyphBuffer has no advances other than the defaults. In that case the 126 // text drawing can proceed faster. However, it's unclear when those 127 // patches may be upstreamed to WebKit so we always use the slower path 128 // here. 129 const GlyphBufferAdvance* adv = glyphBuffer.advances(from); 130 SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); 131 SkPoint* pos = storage.get(); 132 133 for (int i = 0; i < numGlyphs; i++) { 134 pos[i].set(x, y); 135 x += SkFloatToScalar(adv[i].width()); 136 y += SkFloatToScalar(adv[i].height()); 137 } 138 139 if (font->platformData().orientation() == Vertical) { 140 gc->save(); 141 gc->rotate(-0.5 * SK_ScalarPI); 142 SkMatrix rotator; 143 rotator.reset(); 144 rotator.setRotate(90); 145 rotator.mapPoints(pos, numGlyphs); 146 } 147 TextDrawingModeFlags textMode = gc->textDrawingMode(); 148 149 // We draw text up to two times (once for fill, once for stroke). 150 if (textMode & TextModeFill) { 151 SkPaint paint; 152 gc->setupPaintForFilling(&paint); 153 setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts); 154 gc->adjustTextRenderMode(&paint); 155 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 156 157 gc->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, textRect, paint); 158 } 159 160 if ((textMode & TextModeStroke) 161 && gc->strokeStyle() != NoStroke 162 && gc->strokeThickness() > 0) { 163 164 SkPaint paint; 165 gc->setupPaintForStroking(&paint); 166 setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts); 167 gc->adjustTextRenderMode(&paint); 168 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 169 170 if (textMode & TextModeFill) { 171 // If we also filled, we don't want to draw shadows twice. 172 // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. 173 paint.setLooper(0); 174 } 175 176 gc->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, textRect, paint); 177 } 178 if (font->platformData().orientation() == Vertical) 179 gc->restore(); 180 } 181 182 } // namespace WebCore 183