15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. 302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met: 702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Redistributions of source code must retain the above copyright 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Redistributions in binary form must reproduce the above 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution. 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Neither the name of Google Inc. nor the names of its 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission. 1702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 32a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/fonts/Font.h" 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "platform/RuntimeEnabledFeatures.h" 3509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#include "platform/fonts/FontPlatformFeatures.h" 36a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/fonts/SimpleFontData.h" 37a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/fonts/harfbuzz/HarfBuzzShaper.h" 3819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)#include "platform/fonts/GlyphBuffer.h" 391e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/geometry/FloatRect.h" 40a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/GraphicsContext.h" 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "SkPaint.h" 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "SkTemplates.h" 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/unicode/Unicode.h" 465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 477242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include <algorithm> 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccinamespace blink { 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool FontPlatformFeatures::canExpandAroundIdeographsInComplexText() 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 56197021e6b966cfb06891637935ef33fff06433d1Ben Murdochstatic SkPaint textFillPaint(GraphicsContext* gc, const SimpleFontData* font) 57197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{ 58197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPaint paint = gc->fillPaint(); 59197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch font->platformData().setupPaint(&paint, gc); 60197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch gc->adjustTextRenderMode(&paint); 61197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 62197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return paint; 63197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 64197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 65197021e6b966cfb06891637935ef33fff06433d1Ben Murdochstatic SkPaint textStrokePaint(GraphicsContext* gc, const SimpleFontData* font, bool isFilling) 66197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{ 67197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPaint paint = gc->strokePaint(); 68197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch font->platformData().setupPaint(&paint, gc); 69197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch gc->adjustTextRenderMode(&paint); 70197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 71197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (isFilling) { 72197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // If there is a shadow and we filled above, there will already be 73197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // a shadow. We don't want to draw it again or it will be too dark 74197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // and it will go on top of the fill. 75197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // 76197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // Note that this isn't strictly correct, since the stroke could be 77197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // very thick and the shadow wouldn't account for this. The "right" 78197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // thing would be to draw to a new layer and then draw that layer 79197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // with a shadow. But this is a lot of extra work for something 80197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch // that isn't normally an issue. 81197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch paint.setLooper(0); 82197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 83197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return paint; 84197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 85197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 8651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)static void paintGlyphs(GraphicsContext* gc, const SimpleFontData* font, 87197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch const Glyph glyphs[], unsigned numGlyphs, 88197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch const SkPoint pos[], const FloatRect& textRect) 8951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){ 90e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) TextDrawingModeFlags textMode = gc->textDrawingMode(); 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We draw text up to two times (once for fill, once for stroke). 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (textMode & TextModeFill) { 94197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPaint paint = textFillPaint(gc, font); 95197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); 96197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 98197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if ((textMode & TextModeStroke) && gc->hasStroke()) { 99197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPaint paint = textStrokePaint(gc, font, textMode & TextModeFill); 1005d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 102197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch} 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 104197021e6b966cfb06891637935ef33fff06433d1Ben Murdochstatic void paintGlyphsHorizontal(GraphicsContext* gc, const SimpleFontData* font, 105197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch const Glyph glyphs[], unsigned numGlyphs, 106197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch const SkScalar xpos[], SkScalar constY, const FloatRect& textRect) 107197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch{ 108197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch TextDrawingModeFlags textMode = gc->textDrawingMode(); 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 110197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (textMode & TextModeFill) { 111197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPaint paint = textFillPaint(gc, font); 112197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRect, paint); 113197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 114197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 115197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if ((textMode & TextModeStroke) && gc->hasStroke()) { 116197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPaint paint = textStrokePaint(gc, font, textMode & TextModeFill); 117197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch gc->drawPosTextH(glyphs, numGlyphs * sizeof(Glyph), xpos, constY, textRect, paint); 11851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) } 11951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)} 12051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 12151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, 12251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, 12351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) const FloatPoint& point, const FloatRect& textRect) const 12451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles){ 12551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) SkScalar x = SkFloatToScalar(point.x()); 12651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) SkScalar y = SkFloatToScalar(point.y()); 12751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 12851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) const OpenTypeVerticalData* verticalData = font->verticalData(); 12951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) if (font->platformData().orientation() == Vertical && verticalData) { 130197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); 131197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPoint* pos = storage.get(); 132197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 13351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) AffineTransform savedMatrix = gc->getCTM(); 13451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) gc->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y())); 13551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) gc->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y())); 13651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 13751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) const unsigned kMaxBufferLength = 256; 13851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) Vector<FloatPoint, kMaxBufferLength> translations; 13951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 14051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) const FontMetrics& metrics = font->fontMetrics(); 14151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline)); 14251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) float horizontalOffset = point.x(); 14351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 14451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) unsigned glyphIndex = 0; 14551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) while (glyphIndex < numGlyphs) { 14651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphIndex); 14751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 1485d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); 14951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) translations.resize(chunkLength); 15051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chunkLength, reinterpret_cast<float*>(&translations[0])); 15151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 15251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) x = verticalOriginX; 15351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) y = SkFloatToScalar(point.y() + horizontalOffset - point.x()); 15451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 15551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) float currentWidth = 0; 15651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) for (unsigned i = 0; i < chunkLength; ++i, ++glyphIndex) { 15751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) pos[i].set( 15851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) x + SkIntToScalar(lroundf(translations[i].x())), 15951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y()))); 160d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) currentWidth += glyphBuffer.advanceAt(from + glyphIndex).width(); 1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 16251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) horizontalOffset += currentWidth; 16351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); 16451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) } 16551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 16651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) gc->setCTM(savedMatrix); 16751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) return; 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 16951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 170197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch if (!glyphBuffer.hasVerticalAdvances()) { 171197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkAutoSTMalloc<64, SkScalar> storage(numGlyphs); 172197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkScalar* xpos = storage.get(); 173197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch const FloatSize* adv = glyphBuffer.advances(from); 174197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch for (unsigned i = 0; i < numGlyphs; i++) { 175197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch xpos[i] = x; 176197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch x += SkFloatToScalar(adv[i].width()); 177197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 178197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch const Glyph* glyphs = glyphBuffer.glyphs(from); 179197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch paintGlyphsHorizontal(gc, font, glyphs, numGlyphs, xpos, SkFloatToScalar(y), textRect); 180197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch return; 181197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 182197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 18351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) // FIXME: text rendering speed: 18451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) // Android has code in their WebCore fork to special case when the 18551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) // GlyphBuffer has no advances other than the defaults. In that case the 18651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) // text drawing can proceed faster. However, it's unclear when those 18751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) // patches may be upstreamed to WebKit so we always use the slower path 18851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) // here. 189197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); 190197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch SkPoint* pos = storage.get(); 1915d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) const FloatSize* adv = glyphBuffer.advances(from); 19251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) for (unsigned i = 0; i < numGlyphs; i++) { 19351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) pos[i].set(x, y); 19451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) x += SkFloatToScalar(adv[i].width()); 19551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) y += SkFloatToScalar(adv[i].height()); 19651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) } 19751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) 1985d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) const Glyph* glyphs = glyphBuffer.glyphs(from); 19951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); 2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2027242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccivoid Font::drawTextBlob(GraphicsContext* gc, const SkTextBlob* blob, const SkPoint& origin) const 2037242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{ 2047242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); 2057242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 2067242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // FIXME: It would be good to move this to Font.cpp, if we're sure that none 2077242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // of the things in FontMac's setupPaint need to apply here. 2087242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // See also paintGlyphs. 2097242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci TextDrawingModeFlags textMode = gc->textDrawingMode(); 2107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 2117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci if (textMode & TextModeFill) 2127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci gc->drawTextBlob(blob, origin, gc->fillPaint()); 2137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 2147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci if ((textMode & TextModeStroke) && gc->hasStroke()) { 2157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci SkPaint paint = gc->strokePaint(); 2167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci if (textMode & TextModeFill) 2177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci paint.setLooper(0); 2187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci gc->drawTextBlob(blob, origin, paint); 2197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci } 2207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci} 2217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 2227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccifloat Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, const FloatPoint& point) const 2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 22493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) if (!runInfo.run.length()) 2257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return 0; 2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 227e52495584422c5edb5b2944981473a2e208da323Torne (Richard Coles) TextDrawingModeFlags textMode = gc->textDrawingMode(); 2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool fill = textMode & TextModeFill; 229197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch bool stroke = (textMode & TextModeStroke) && gc->hasStroke(); 2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!fill && !stroke) 2327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return 0; 2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) GlyphBuffer glyphBuffer; 23593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) HarfBuzzShaper shaper(this, runInfo.run); 23693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) shaper.setDrawRange(runInfo.from, runInfo.to); 237a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch if (!shaper.shape(&glyphBuffer) || glyphBuffer.isEmpty()) 2387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return 0; 2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) FloatPoint adjustedPoint = shaper.adjustStartPoint(point); 2407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint); 2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 243d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const 2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 245d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) GlyphBuffer glyphBuffer; 246d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 247a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer, ForTextEmphasis); 248d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 249d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) if (glyphBuffer.isEmpty()) 250d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) return; 251d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 252d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); 253d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)} 254d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 255a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdochfloat Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const 256d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){ 257a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch HarfBuzzShaper shaper(this, runInfo.run, HarfBuzzShaper::ForTextEmphasis); 258a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch shaper.setDrawRange(runInfo.from, runInfo.to); 259d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) shaper.shape(&glyphBuffer); 260d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) return 0; 2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2637242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccifloat Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, IntRectExtent* glyphBounds) const 2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2657242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci HarfBuzzShaper shaper(this, run, HarfBuzzShaper::NotForTextEmphasis, fallbackFonts); 2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!shaper.shape()) 2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 26843e7502580f146aa5b3db8267ba6dbb5c733a489Torne (Richard Coles) 269d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) glyphBounds->setTop(floorf(-shaper.glyphBoundingBox().top())); 270d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) glyphBounds->setBottom(ceilf(shaper.glyphBoundingBox().bottom())); 271d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) glyphBounds->setLeft(std::max<int>(0, floorf(-shaper.glyphBoundingBox().left()))); 272d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) glyphBounds->setRight(std::max<int>(0, ceilf(shaper.glyphBoundingBox().right() - shaper.totalWidth()))); 273d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) 2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return shaper.totalWidth(); 2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Return the code point index for the given |x| offset into the text run. 2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, 2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool includePartialGlyphs) const 2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) HarfBuzzShaper shaper(this, run); 2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!shaper.shape()) 2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 284926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return shaper.offsetForPosition(xFloat); 2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Return the rectangle for selecting the given range of code-points in the TextRun. 2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FloatRect Font::selectionRectForComplexText(const TextRun& run, 2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const FloatPoint& point, int height, 2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int from, int to) const 2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) HarfBuzzShaper shaper(this, run); 2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!shaper.shape()) 2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return FloatRect(); 2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return shaper.selectionRect(point, height, from, to); 2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2987242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano TucciPassTextBlobPtr Font::buildTextBlob(const GlyphBuffer& glyphBuffer, float initialAdvance, 2997242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci const FloatRect& bounds, float& advance, bool couldUseLCD) const 3007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci{ 3017242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci ASSERT(RuntimeEnabledFeatures::textBlobEnabled()); 3027242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3037242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // FIXME: Except for setupPaint, this is not specific to FontHarfBuzz. 3047242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // FIXME: Also implement the more general full-positioning path. 3057242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci ASSERT(!glyphBuffer.hasVerticalAdvances()); 3067242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3077242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci SkTextBlobBuilder builder; 3087242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci SkScalar x = SkFloatToScalar(initialAdvance); 3097242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci SkRect skBounds = bounds; 3107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci unsigned i = 0; 3127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci while (i < glyphBuffer.size()) { 3137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci const SimpleFontData* fontData = glyphBuffer.fontDataAt(i); 3147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // FIXME: Handle vertical text. 3167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci if (fontData->platformData().orientation() == Vertical) 3177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return nullptr; 3187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // FIXME: Handle SVG fonts. 3207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci if (fontData->isSVGFont()) 3217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return nullptr; 3227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // FIXME: FontPlatformData makes some decisions on the device scale 3247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // factor, which is found via the GraphicsContext. This should be fixed 3257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // to avoid correctness problems here. 3267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci SkPaint paint; 3277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci fontData->platformData().setupPaint(&paint); 3287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 3297242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3307242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci // FIXME: this should go away after the big LCD cleanup. 3317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci paint.setLCDRenderText(paint.isLCDRenderText() && couldUseLCD); 3327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci unsigned start = i++; 3347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci while (i < glyphBuffer.size() && glyphBuffer.fontDataAt(i) == fontData) 3357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci i++; 3367242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci unsigned count = i - start; 3377242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPosH(paint, count, 0, &skBounds); 3397242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci const uint16_t* glyphs = glyphBuffer.glyphs(start); 3417242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci std::copy(glyphs, glyphs + count, buffer.glyphs); 3427242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3437242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci const FloatSize* advances = glyphBuffer.advances(start); 3447242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci for (unsigned j = 0; j < count; j++) { 3457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci buffer.pos[j] = x; 3467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci x += SkFloatToScalar(advances[j].width()); 3477242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci } 3487242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci } 3497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 3507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci advance = x; 3517242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return adoptRef(builder.build()); 3527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci} 3537242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 354c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink 355