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