18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright 2009, The Android Open Source Project
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
8e03118fd5d9b776df29de3f96232ed6b5395c845Steve Block *  * Redistributions of source code must retain the above copyright
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
10e03118fd5d9b776df29de3f96232ed6b5395c845Steve Block *  * Redistributions in binary form must reproduce the above copyright
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
14e03118fd5d9b776df29de3f96232ed6b5395c845Steve Block * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17e03118fd5d9b776df29de3f96232ed6b5395c845Steve Block * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24e03118fd5d9b776df29de3f96232ed6b5395c845Steve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
29675402ef4358583f64a2476927a548db4841c856John Reck#define LOG_TAG "FontAndroid"
30675402ef4358583f64a2476927a548db4841c856John Reck
31675402ef4358583f64a2476927a548db4841c856John Reck#include "AndroidLog.h"
32a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project#include "EmojiFont.h"
3364e4b265f84573b97d408f7d3e5aa99a647be057Nicolas Roard#include "GraphicsOperation.h"
34a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project#include "Font.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FontData.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FontFallbackList.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GlyphBuffer.h"
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "IntRect.h"
40c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdoch#include "NotImplemented.h"
41a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project#include "PlatformGraphicsContext.h"
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SkCanvas.h"
43909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger#include "SkColorFilter.h"
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SkLayerDrawLooper.h"
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SkPaint.h"
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SkTemplates.h"
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SkTypeface.h"
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SkUtils.h"
4921e5a8c1ef0e857b93742093a0b034f9368cfe60Ben Murdoch#include "TextRun.h"
50e2b40beb65b8644a5c6d0332e5874d32fb3c470eBilly Hewlett#include "SkTypeface_android.h"
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
52c882e887207fecca865d26ab84fcc541c1b08fd9claireho#ifdef SUPPORT_COMPLEX_SCRIPTS
53c882e887207fecca865d26ab84fcc541c1b08fd9claireho#include "HarfbuzzSkia.h"
54c882e887207fecca865d26ab84fcc541c1b08fd9claireho#include <unicode/normlzr.h>
55c882e887207fecca865d26ab84fcc541c1b08fd9claireho#include <unicode/uchar.h>
56c882e887207fecca865d26ab84fcc541c1b08fd9claireho#include <wtf/OwnArrayPtr.h>
57c882e887207fecca865d26ab84fcc541c1b08fd9claireho#include <wtf/OwnPtr.h>
58a299dfda6bbcec93b532b7ad3d118a9609fa9b75Steve Block#include <wtf/PassOwnArrayPtr.h>
59a299dfda6bbcec93b532b7ad3d118a9609fa9b75Steve Block#include <wtf/PassOwnPtr.h>
60469c7a77ed7557a04a0797ff8ca3e4335a1c1be0Russell Brenner#include <wtf/unicode/CharacterNames.h>
61abb274d1eae5637eee465c5618aac1266d8ce695claireho#include <wtf/unicode/Unicode.h>
62c882e887207fecca865d26ab84fcc541c1b08fd9claireho#endif
63c882e887207fecca865d26ab84fcc541c1b08fd9claireho
64a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Projectusing namespace android;
65a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
682018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brennertypedef std::pair<int, float> FallbackFontKey;
692622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease
702018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brennertypedef HashMap<FallbackFontKey, FontPlatformData*> FallbackHash;
712018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void updateForFont(SkPaint* paint, const SimpleFontData* font) {
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    font->platformData().setupPaint(paint);
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
76611087b9e5016d419f347b32251f279b8853e69dclaireho
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc,
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                          const SimpleFontData* font) {
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    gc->setupFillPaint(paint);
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    updateForFont(paint, font);
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return paint;
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
83611087b9e5016d419f347b32251f279b8853e69dclaireho
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc,
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            const SimpleFontData* font) {
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    gc->setupStrokePaint(paint);
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    updateForFont(paint, font);
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return paint;
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
90611087b9e5016d419f347b32251f279b8853e69dclaireho
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool setupForText(SkPaint* paint, GraphicsContext* gc,
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                         const SimpleFontData* font) {
93b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch    int mode = gc->textDrawingMode() & (TextModeFill | TextModeStroke);
9472b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner    if (!mode)
9572b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner        return false;
9672b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner
97916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger    paint->setVerticalText(font->platformData().orientation() == Vertical);
98916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger
9972b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner    FloatSize shadowOffset;
10072b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner    float shadowBlur;
10172b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner    Color shadowColor;
102312a1f86fb2e3afb0948da0b2915fae853fbc54eBen Murdoch    ColorSpace shadowColorSpace;
1035ac7427c1558f018fbb6a5f8f9fcdba5d7bad6caBilly Hewlett
1045ac7427c1558f018fbb6a5f8f9fcdba5d7bad6caBilly Hewlett    if (RenderSkinAndroid::DrawableResolution() >= RenderSkinAndroid::HighRes)
1055ac7427c1558f018fbb6a5f8f9fcdba5d7bad6caBilly Hewlett        paint->setAutohinted(false);
1065ac7427c1558f018fbb6a5f8f9fcdba5d7bad6caBilly Hewlett
107312a1f86fb2e3afb0948da0b2915fae853fbc54eBen Murdoch    bool hasShadow = gc->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
108f27fab1a4a6a46039e79f96a6c5a85d8625d3fc5Teng-Hui Zhu    bool hasBothStrokeAndFill =
109b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch        (mode & (TextModeStroke | TextModeFill)) == (TextModeStroke | TextModeFill);
110f27fab1a4a6a46039e79f96a6c5a85d8625d3fc5Teng-Hui Zhu    if (hasShadow || hasBothStrokeAndFill) {
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        SkLayerDrawLooper* looper = new SkLayerDrawLooper;
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        paint->setLooper(looper)->unref();
113611087b9e5016d419f347b32251f279b8853e69dclaireho
11413d5898c0b431f802bb519a31ecd6b8ab2644143Derek Sollenberger        // The layerDrawLooper uses at the root paint to determine the text
11513d5898c0b431f802bb519a31ecd6b8ab2644143Derek Sollenberger        // encoding so we need to make sure it is properly configured.
11613d5898c0b431f802bb519a31ecd6b8ab2644143Derek Sollenberger        updateForFont(paint, font);
11713d5898c0b431f802bb519a31ecd6b8ab2644143Derek Sollenberger
118909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        // Specify the behavior of the looper
119909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        SkLayerDrawLooper::LayerInfo info;
120909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits;
121909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        info.fColorMode = SkXfermode::kSrc_Mode;
1224f35f0e844f7f679067223eaf7eb60cf4a350a05Derek Sollenberger        info.fFlagsMask = SkPaint::kAllFlags;
123909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger
124909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        // The paint is only valid until the looper receives another call to
125909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        // addLayer(). Therefore, we must cache certain state for later use.
126909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        bool hasFillPaint = false;
127909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        bool hasStrokePaint = false;
128909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger        SkScalar strokeWidth;
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
130b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch        if ((mode & TextModeStroke) && gc->willStroke()) {
131909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger            strokeWidth = setupStroke(looper->addLayer(info), gc, font)->getStrokeWidth();
132909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger            hasStrokePaint = true;
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
134b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch        if ((mode & TextModeFill) && gc->willFill()) {
135909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger            setupFill(looper->addLayer(info), gc, font);
136909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger            hasFillPaint = true;
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13972b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner        if (hasShadow) {
14072b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner            SkPaint shadowPaint;
14172b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner            SkPoint offset;
14272b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner            if (gc->setupShadowPaint(&shadowPaint, &offset)) {
143909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger
144909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                // add an offset to the looper when creating a shadow layer
145909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                info.fOffset.set(offset.fX, offset.fY);
146909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger
147909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                SkPaint* p = looper->addLayer(info);
14872b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner                *p = shadowPaint;
149909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger
150909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                // Currently, only GraphicsContexts associated with the
151909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                // HTMLCanvasElement have shadows ignore transforms set.  This
152909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                // allows us to distinguish between CSS and Canvas shadows which
153909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                // have different rendering specifications.
154909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                if (gc->shadowsIgnoreTransforms()) {
155909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                    SkColorFilter* cf = SkColorFilter::CreateModeFilter(p->getColor(),
156909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                            SkXfermode::kSrcIn_Mode);
157909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                    p->setColorFilter(cf)->unref();
158909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                } else { // in CSS
159909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                    p->setShader(NULL);
160909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                }
161909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger
162909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                if (hasStrokePaint && !hasFillPaint) {
16372b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner                    // stroke the shadow if we have stroke but no fill
16472b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner                    p->setStyle(SkPaint::kStroke_Style);
165909b5bb7002f48ae08c3c0157f5df3ee828e5d18Derek Sollenberger                    p->setStrokeWidth(strokeWidth);
16672b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner                }
16772b824a5bbed3afbd719564c8d603c8055ad3dfdRussell Brenner                updateForFont(p, font);
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
170b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch    } else if (mode & TextModeFill) {
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        (void)setupFill(paint, gc, font);
172b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch    } else if (mode & TextModeStroke) {
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        (void)setupStroke(paint, gc, font);
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
179a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project
1805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool Font::canReturnFallbackFontsForComplexText()
1815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return false;
1835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1854ca4fadf20df64973fab6d833db6d5dff4ef7e8fSteve Blockbool Font::canExpandAroundIdeographsInComplexText()
1864ca4fadf20df64973fab6d833db6d5dff4ef7e8fSteve Block{
1874ca4fadf20df64973fab6d833db6d5dff4ef7e8fSteve Block    return false;
1884ca4fadf20df64973fab6d833db6d5dff4ef7e8fSteve Block}
1894ca4fadf20df64973fab6d833db6d5dff4ef7e8fSteve Block
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                      const GlyphBuffer& glyphBuffer,  int from, int numGlyphs,
192a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                      const FloatPoint& point) const
193a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project{
194a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project    // compile-time assert
195a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project    SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t));
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
197675402ef4358583f64a2476927a548db4841c856John Reck    if (numGlyphs == 1 && glyphBuffer.glyphAt(from) == 0x3) {
198675402ef4358583f64a2476927a548db4841c856John Reck        // Webkit likes to draw end text control command for some reason
199675402ef4358583f64a2476927a548db4841c856John Reck        // Just ignore it
200675402ef4358583f64a2476927a548db4841c856John Reck        return;
201675402ef4358583f64a2476927a548db4841c856John Reck    }
202675402ef4358583f64a2476927a548db4841c856John Reck
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkPaint paint;
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!setupForText(&paint, gc, font)) {
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
207611087b9e5016d419f347b32251f279b8853e69dclaireho
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkScalar                    x = SkFloatToScalar(point.x());
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkScalar                    y = SkFloatToScalar(point.y());
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const GlyphBufferGlyph*     glyphs = glyphBuffer.glyphs(from);
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const GlyphBufferAdvance*   adv = glyphBuffer.advances(from);
212295fd960c28a38cfa7a28d4b8f68f474394f7fb0claireho    SkAutoSTMalloc<32, SkPoint> storage(numGlyphs), storage2(numGlyphs), storage3(numGlyphs);
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkPoint*                    pos = storage.get();
214611087b9e5016d419f347b32251f279b8853e69dclaireho
21564e4b265f84573b97d408f7d3e5aa99a647be057Nicolas Roard    SkCanvas* canvas = gc->platformContext()->recordingCanvas();
216a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /*  We need an array of [x,y,x,y,x,y,...], but webkit is giving us
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        point.xy + [width, height, width, height, ...], so we have to convert
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project     */
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
22185fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik    if (font->platformData().orientation() == Vertical) {
22285fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik        float yOffset = SkFloatToScalar(font->fontMetrics().floatAscent(IdeographicBaseline) - font->fontMetrics().floatAscent());
22385fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik        gc->platformContext()->setTextOffset(FloatSize(0.0f, -yOffset)); // compensate for offset in bounds calculation
22485fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik        y += yOffset;
22585fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik    }
226916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger
227a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project    if (EmojiFont::IsAvailable()) {
2280512d735497339600fc79c303870549dcdd965c7Mike Reed        // set filtering, to make scaled images look nice(r)
2290512d735497339600fc79c303870549dcdd965c7Mike Reed        paint.setFilterBitmap(true);
230611087b9e5016d419f347b32251f279b8853e69dclaireho
231398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma        SkMatrix rotator;
232398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma        rotator.reset();
233398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma        if (font->platformData().orientation() == Vertical) {
234398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma            canvas->save();
235398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma            canvas->rotate(-90);
236398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma            rotator.setRotate(90);
237398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma        }
238398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma
239a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project        int localIndex = 0;
240a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project        int localCount = 0;
241a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project        for (int i = 0; i < numGlyphs; i++) {
242a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project            if (EmojiFont::IsEmojiGlyph(glyphs[i])) {
243675402ef4358583f64a2476927a548db4841c856John Reck                if (localCount) {
244398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma                    rotator.mapPoints(&pos[localIndex], localCount);
245b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck                    canvas->drawPosText(&glyphs[localIndex],
246675402ef4358583f64a2476927a548db4841c856John Reck                                     localCount * sizeof(uint16_t),
247b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck                                     &pos[localIndex], paint);
248675402ef4358583f64a2476927a548db4841c856John Reck                }
2490512d735497339600fc79c303870549dcdd965c7Mike Reed                EmojiFont::Draw(canvas, glyphs[i], x, y, paint);
250a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                // reset local index/count track for "real" glyphs
251a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                localCount = 0;
252a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                localIndex = i + 1;
253a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project            } else {
254a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                pos[i].set(x, y);
255a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                localCount += 1;
256a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project            }
257a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project            x += SkFloatToScalar(adv[i].width());
258a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project            y += SkFloatToScalar(adv[i].height());
259a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project        }
260398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma
261a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project        // draw the last run of glyphs (if any)
262675402ef4358583f64a2476927a548db4841c856John Reck        if (localCount) {
263398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma            rotator.mapPoints(&pos[localIndex], localCount);
264b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck            canvas->drawPosText(&glyphs[localIndex],
265675402ef4358583f64a2476927a548db4841c856John Reck                             localCount * sizeof(uint16_t),
266b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck                             &pos[localIndex], paint);
267398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma
268675402ef4358583f64a2476927a548db4841c856John Reck        }
269398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma
270398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma        if (font->platformData().orientation() == Vertical)
271398703a12520dd1a7c2bdbd99d56fe024f761717Junichi Monma            canvas->restore();
272a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project    } else {
273a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project        for (int i = 0; i < numGlyphs; i++) {
274a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project            pos[i].set(x, y);
275a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project            y += SkFloatToScalar(adv[i].height());
276916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            x += SkFloatToScalar(adv[i].width());
277a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project        }
278916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger
279916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger        if (font->platformData().orientation() == Vertical) {
280916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            canvas->save();
281916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            canvas->rotate(-90);
282916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            SkMatrix rotator;
283916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            rotator.reset();
284916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            rotator.setRotate(90);
285916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            rotator.mapPoints(pos, numGlyphs);
286916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger        }
287b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck        canvas->drawPosText(glyphs,
288b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck            numGlyphs * sizeof(uint16_t), pos, paint);
289916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger
290916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger        if (font->platformData().orientation() == Vertical)
291916ae1fb7445b6b919a72f195721d8dc09ddb1fcDerek Sollenberger            canvas->restore();
292a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project    }
29385fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik
29485fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik    if (font->platformData().orientation() == Vertical)
29585fb59060a0fdfcff93ae1c70dd49e0f93e55ab6Chris Craik        gc->platformContext()->setTextOffset(FloatSize()); // reset to undo above
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdochvoid Font::drawEmphasisMarksForComplexText(WebCore::GraphicsContext*, WebCore::TextRun const&, WTF::AtomicString const&, WebCore::FloatPoint const&, int, int) const
299c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdoch{
300c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdoch    notImplemented();
301c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdoch}
302c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdoch
303c882e887207fecca865d26ab84fcc541c1b08fd9claireho#ifndef SUPPORT_COMPLEX_SCRIPTS
304c882e887207fecca865d26ab84fcc541c1b08fd9claireho
305a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source ProjectFloatRect Font::selectionRectForComplexText(const TextRun& run,
3062955a544aa75edb17e8d8c8e080a50812dfc535cKristian Monsen                                const FloatPoint& point, int h, int, int) const
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkPaint              paint;
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkScalar             width, left;
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkPaint::FontMetrics metrics;
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    primaryFont()->platformData().setupPaint(&paint);
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    width = paint.measureText(run.characters(), run.length() << 1);
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkScalar spacing = paint.getFontMetrics(&metrics);
316611087b9e5016d419f347b32251f279b8853e69dclaireho
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return FloatRect(point.x(),
318733e4cfb8b3cae83daff5cc7a426ee901227dbc6Anders Edenbrandt                     point.y(),
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                     roundf(SkScalarToFloat(width)),
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                     roundf(SkScalarToFloat(spacing)));
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
323a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Projectvoid Font::drawComplexText(GraphicsContext* gc, TextRun const& run,
324a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                           FloatPoint const& point, int, int) const
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkCanvas*   canvas = gc->platformContext()->mCanvas;
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkPaint     paint;
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!setupForText(&paint, gc, primaryFont())) {
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // go to chars, instead of glyphs, which was set by setupForText()
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    canvas->drawText(run.characters(), run.length() << 1,
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                     SkFloatToScalar(point.x()), SkFloatToScalar(point.y()),
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                     paint);
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
341d2816f16f713bc58b245e2d5c5fd16ac4bb32cb8Steve Blockfloat Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkPaint paint;
3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    primaryFont()->platformData().setupPaint(&paint);
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project//printf("--------- complext measure %d chars\n", run.to() - run.from());
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkScalar width = paint.measureText(run.characters(), run.length() << 1);
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return SkScalarToFloat(width);
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3532955a544aa75edb17e8d8c8e080a50812dfc535cKristian Monsenint Font::offsetForPositionForComplexText(const TextRun& run, float x,
354a4458b1fd08c42fec82899c0ec145e2639aa6799The Android Open Source Project                                          bool includePartialGlyphs) const
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkPaint                         paint;
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int                             count = run.length();
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkAutoSTMalloc<64, SkScalar>    storage(count);
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SkScalar*                       widths = storage.get();
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    primaryFont()->platformData().setupPaint(&paint);
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    count = paint.getTextWidths(run.characters(), count << 1, widths);
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (count > 0)
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    {
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        SkScalar pos = 0;
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        for (int i = 0; i < count; i++)
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        {
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (x < SkScalarRound(pos + SkScalarHalf(widths[i])))
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return i;
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            pos += widths[i];
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return count;
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
378c882e887207fecca865d26ab84fcc541c1b08fd9claireho#else
379c882e887207fecca865d26ab84fcc541c1b08fd9claireho
380c882e887207fecca865d26ab84fcc541c1b08fd9claireho// TODO Should we remove the multilayer support?
381c882e887207fecca865d26ab84fcc541c1b08fd9claireho// If yes. remove isCanvasMultiLayered() and adjustTextRenderMode().
382c882e887207fecca865d26ab84fcc541c1b08fd9clairehostatic bool isCanvasMultiLayered(SkCanvas* canvas)
383c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
384c882e887207fecca865d26ab84fcc541c1b08fd9claireho    SkCanvas::LayerIter layerIterator(canvas, false);
385c882e887207fecca865d26ab84fcc541c1b08fd9claireho    layerIterator.next();
386c882e887207fecca865d26ab84fcc541c1b08fd9claireho    return !layerIterator.done();
387c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
388c882e887207fecca865d26ab84fcc541c1b08fd9claireho
389c882e887207fecca865d26ab84fcc541c1b08fd9clairehostatic void adjustTextRenderMode(SkPaint* paint, bool isCanvasMultiLayered)
390c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
391c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Our layers only have a single alpha channel. This means that subpixel
392c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // rendered text cannot be compositied correctly when the layer is
393c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // collapsed. Therefore, subpixel text is disabled when we are drawing
394c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // onto a layer.
395c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (isCanvasMultiLayered)
396c882e887207fecca865d26ab84fcc541c1b08fd9claireho        paint->setLCDRenderText(false);
397c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
398c882e887207fecca865d26ab84fcc541c1b08fd9claireho
399c882e887207fecca865d26ab84fcc541c1b08fd9claireho// Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't
400c882e887207fecca865d26ab84fcc541c1b08fd9claireho// handle subpixel positioning so this function is used to truncate Harfbuzz
401c882e887207fecca865d26ab84fcc541c1b08fd9claireho// values to a number of pixels.
402c882e887207fecca865d26ab84fcc541c1b08fd9clairehostatic int truncateFixedPointToInteger(HB_Fixed value)
403c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
404c882e887207fecca865d26ab84fcc541c1b08fd9claireho    return value >> 6;
405c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
406c882e887207fecca865d26ab84fcc541c1b08fd9claireho
407c882e887207fecca865d26ab84fcc541c1b08fd9claireho// TextRunWalker walks a TextRun and presents each script run in sequence. A
408c882e887207fecca865d26ab84fcc541c1b08fd9claireho// TextRun is a sequence of code-points with the same embedding level (i.e. they
409c882e887207fecca865d26ab84fcc541c1b08fd9claireho// are all left-to-right or right-to-left). A script run is a subsequence where
410c882e887207fecca865d26ab84fcc541c1b08fd9claireho// all the characters have the same script (e.g. Arabic, Thai etc). Shaping is
411c882e887207fecca865d26ab84fcc541c1b08fd9claireho// only ever done with script runs since the shapers only know how to deal with
412c882e887207fecca865d26ab84fcc541c1b08fd9claireho// a single script.
413c882e887207fecca865d26ab84fcc541c1b08fd9claireho//
414c882e887207fecca865d26ab84fcc541c1b08fd9claireho// After creating it, the script runs are either iterated backwards or forwards.
415c882e887207fecca865d26ab84fcc541c1b08fd9claireho// It defaults to backwards for RTL and forwards otherwise (which matches the
416c882e887207fecca865d26ab84fcc541c1b08fd9claireho// presentation order), however you can set it with |setBackwardsIteration|.
417c882e887207fecca865d26ab84fcc541c1b08fd9claireho//
418c882e887207fecca865d26ab84fcc541c1b08fd9claireho// Once you have setup the object, call |nextScriptRun| to get the first script
419c882e887207fecca865d26ab84fcc541c1b08fd9claireho// run. This will return false when the iteration is complete. At any time you
420c882e887207fecca865d26ab84fcc541c1b08fd9claireho// can call |reset| to start over again.
421c882e887207fecca865d26ab84fcc541c1b08fd9clairehoclass TextRunWalker {
422c882e887207fecca865d26ab84fcc541c1b08fd9clairehopublic:
4231c0dc8f01cc996f5356b59341d2ecaecaad96c3aGeorge Mount    TextRunWalker(const TextRun&, int, int, const Font*);
424c68e499ce88a566485062518510f31f9869f41a2claireho    ~TextRunWalker();
425c882e887207fecca865d26ab84fcc541c1b08fd9claireho
426c68e499ce88a566485062518510f31f9869f41a2claireho    bool isWordBreak(unsigned, bool);
427c68e499ce88a566485062518510f31f9869f41a2claireho    // setPadding sets a number of pixels to be distributed across the TextRun.
428c68e499ce88a566485062518510f31f9869f41a2claireho    // WebKit uses this to justify text.
429c68e499ce88a566485062518510f31f9869f41a2claireho    void setPadding(int);
430c68e499ce88a566485062518510f31f9869f41a2claireho    void reset();
431c68e499ce88a566485062518510f31f9869f41a2claireho    void setBackwardsIteration(bool);
432c68e499ce88a566485062518510f31f9869f41a2claireho    // Advance to the next script run, returning false when the end of the
433c68e499ce88a566485062518510f31f9869f41a2claireho    // TextRun has been reached.
434c68e499ce88a566485062518510f31f9869f41a2claireho    bool nextScriptRun();
435c68e499ce88a566485062518510f31f9869f41a2claireho    float widthOfFullRun();
436c882e887207fecca865d26ab84fcc541c1b08fd9claireho
437611087b9e5016d419f347b32251f279b8853e69dclaireho    // setWordSpacingAdjustment sets a delta (in pixels) which is applied at
438611087b9e5016d419f347b32251f279b8853e69dclaireho    // each word break in the TextRun.
439611087b9e5016d419f347b32251f279b8853e69dclaireho    void setWordSpacingAdjustment(int wordSpacingAdjustment)
440611087b9e5016d419f347b32251f279b8853e69dclaireho    {
441611087b9e5016d419f347b32251f279b8853e69dclaireho        m_wordSpacingAdjustment = wordSpacingAdjustment;
442611087b9e5016d419f347b32251f279b8853e69dclaireho    }
443611087b9e5016d419f347b32251f279b8853e69dclaireho
444611087b9e5016d419f347b32251f279b8853e69dclaireho    // setLetterSpacingAdjustment sets an additional number of pixels that is
445611087b9e5016d419f347b32251f279b8853e69dclaireho    // added to the advance after each output cluster. This matches the behaviour
446611087b9e5016d419f347b32251f279b8853e69dclaireho    // of WidthIterator::advance.
447611087b9e5016d419f347b32251f279b8853e69dclaireho    //
448611087b9e5016d419f347b32251f279b8853e69dclaireho    // (NOTE: currently does nothing because I don't know how to get the
449611087b9e5016d419f347b32251f279b8853e69dclaireho    // cluster information from Harfbuzz.)
450611087b9e5016d419f347b32251f279b8853e69dclaireho    void setLetterSpacingAdjustment(int letterSpacingAdjustment)
451611087b9e5016d419f347b32251f279b8853e69dclaireho    {
452611087b9e5016d419f347b32251f279b8853e69dclaireho        m_letterSpacing = letterSpacingAdjustment;
453611087b9e5016d419f347b32251f279b8853e69dclaireho    }
454611087b9e5016d419f347b32251f279b8853e69dclaireho
455611087b9e5016d419f347b32251f279b8853e69dclaireho    // setWordAndLetterSpacing calls setWordSpacingAdjustment() and
456611087b9e5016d419f347b32251f279b8853e69dclaireho    // setLetterSpacingAdjustment() to override m_wordSpacingAdjustment
457611087b9e5016d419f347b32251f279b8853e69dclaireho    // and m_letterSpacing.
458c68e499ce88a566485062518510f31f9869f41a2claireho    void setWordAndLetterSpacing(int wordSpacingAdjustment, int letterSpacingAdjustment);
459c882e887207fecca865d26ab84fcc541c1b08fd9claireho
460c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Set the x offset for the next script run. This affects the values in
461c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // |xPositions|
462c68e499ce88a566485062518510f31f9869f41a2claireho    void setXOffsetToZero() { m_offsetX = 0; }
463c68e499ce88a566485062518510f31f9869f41a2claireho    bool rtl() const { return m_run.rtl(); }
464c68e499ce88a566485062518510f31f9869f41a2claireho    const uint16_t* glyphs() const { return m_glyphs16; }
465c882e887207fecca865d26ab84fcc541c1b08fd9claireho
466c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Return the length of the array returned by |glyphs|
467c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned length() const { return m_item.num_glyphs; }
468c882e887207fecca865d26ab84fcc541c1b08fd9claireho
469bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    // Return the offset for each of the glyphs. Note that this is translated
470c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // by the current x offset and that the x offset is updated for each script
471c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // run.
472bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    const SkPoint* positions() const { return m_positions; }
473c882e887207fecca865d26ab84fcc541c1b08fd9claireho
474c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Get the advances (widths) for each glyph.
475c68e499ce88a566485062518510f31f9869f41a2claireho    const HB_Fixed* advances() const { return m_item.advances; }
476c882e887207fecca865d26ab84fcc541c1b08fd9claireho
477c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Return the width (in px) of the current script run.
478c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned width() const { return m_pixelWidth; }
479c882e887207fecca865d26ab84fcc541c1b08fd9claireho
480c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Return the cluster log for the current script run. For example:
481c68e499ce88a566485062518510f31f9869f41a2claireho    //   script run: f i a n c é  (fi gets ligatured)
482c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //   log clutrs: 0 0 1 2 3 4
483c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // So, for each input code point, the log tells you which output glyph was
484c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // generated for it.
485c68e499ce88a566485062518510f31f9869f41a2claireho    const unsigned short* logClusters() const { return m_item.log_clusters; }
486c882e887207fecca865d26ab84fcc541c1b08fd9claireho
487c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // return the number of code points in the current script run
488c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned numCodePoints() const { return m_numCodePoints; }
489c882e887207fecca865d26ab84fcc541c1b08fd9claireho
490c68e499ce88a566485062518510f31f9869f41a2claireho    const FontPlatformData* fontPlatformDataForScriptRun() {
491c882e887207fecca865d26ab84fcc541c1b08fd9claireho        return reinterpret_cast<FontPlatformData*>(m_item.font->userData);
492c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
493c882e887207fecca865d26ab84fcc541c1b08fd9claireho
494c68e499ce88a566485062518510f31f9869f41a2clairehoprivate:
495c68e499ce88a566485062518510f31f9869f41a2claireho    void setupFontForScriptRun();
4962abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett    const FontPlatformData* setupComplexFont(HB_Script script, const FontPlatformData& platformData);
497c68e499ce88a566485062518510f31f9869f41a2claireho    HB_FontRec* allocHarfbuzzFont();
498c68e499ce88a566485062518510f31f9869f41a2claireho    void deleteGlyphArrays();
499c68e499ce88a566485062518510f31f9869f41a2claireho    void createGlyphArrays(int);
500c68e499ce88a566485062518510f31f9869f41a2claireho    void resetGlyphArrays();
501c68e499ce88a566485062518510f31f9869f41a2claireho    void shapeGlyphs();
502bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    void setGlyphPositions(bool);
503c68e499ce88a566485062518510f31f9869f41a2claireho
504c68e499ce88a566485062518510f31f9869f41a2claireho    static void normalizeSpacesAndMirrorChars(const UChar* source, bool rtl,
505c68e499ce88a566485062518510f31f9869f41a2claireho        UChar* destination, int length);
506c68e499ce88a566485062518510f31f9869f41a2claireho    static const TextRun& getNormalizedTextRun(const TextRun& originalRun,
507c68e499ce88a566485062518510f31f9869f41a2claireho        OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer);
508c68e499ce88a566485062518510f31f9869f41a2claireho
509c68e499ce88a566485062518510f31f9869f41a2claireho    // This matches the logic in RenderBlock::findNextLineBreak
510c68e499ce88a566485062518510f31f9869f41a2claireho    static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; }
511c68e499ce88a566485062518510f31f9869f41a2claireho
512c68e499ce88a566485062518510f31f9869f41a2claireho    const Font* const m_font;
513c68e499ce88a566485062518510f31f9869f41a2claireho    HB_ShaperItem m_item;
514c68e499ce88a566485062518510f31f9869f41a2claireho    uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
515bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    SkPoint* m_positions; // A vector of positions for each glyph.
516c68e499ce88a566485062518510f31f9869f41a2claireho    ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
5171c0dc8f01cc996f5356b59341d2ecaecaad96c3aGeorge Mount    const int m_startingX; // Offset in pixels of the first script run.
5181c0dc8f01cc996f5356b59341d2ecaecaad96c3aGeorge Mount    const int m_startingY; // Offset in pixels of the first script run.
5191c0dc8f01cc996f5356b59341d2ecaecaad96c3aGeorge Mount    int m_offsetX; // Offset in pixels to the start of the next script run.
520c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned m_pixelWidth; // Width (in px) of the current script run.
521c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned m_numCodePoints; // Code points in current script run.
522c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays.
523c882e887207fecca865d26ab84fcc541c1b08fd9claireho
524c68e499ce88a566485062518510f31f9869f41a2claireho    OwnPtr<TextRun> m_normalizedRun;
525c68e499ce88a566485062518510f31f9869f41a2claireho    OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run.
526c68e499ce88a566485062518510f31f9869f41a2claireho    const TextRun& m_run;
527c68e499ce88a566485062518510f31f9869f41a2claireho    bool m_iterateBackwards;
528c68e499ce88a566485062518510f31f9869f41a2claireho    int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break.
529c68e499ce88a566485062518510f31f9869f41a2claireho    float m_padding; // pixels to be distributed over the line at word breaks.
530c68e499ce88a566485062518510f31f9869f41a2claireho    float m_padPerWordBreak; // pixels to be added to each word break.
531c68e499ce88a566485062518510f31f9869f41a2claireho    float m_padError; // |m_padPerWordBreak| might have a fractional component.
532c68e499ce88a566485062518510f31f9869f41a2claireho                      // Since we only add a whole number of padding pixels at
533c68e499ce88a566485062518510f31f9869f41a2claireho                      // each word break we accumulate error. This is the
534c68e499ce88a566485062518510f31f9869f41a2claireho                      // number of pixels that we are behind so far.
535c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned m_letterSpacing; // pixels to be added after each glyph.
536c68e499ce88a566485062518510f31f9869f41a2claireho};
537c68e499ce88a566485062518510f31f9869f41a2claireho
5381c0dc8f01cc996f5356b59341d2ecaecaad96c3aGeorge MountTextRunWalker::TextRunWalker(const TextRun& run, int startingX, int startingY, const Font* font)
539c68e499ce88a566485062518510f31f9869f41a2claireho    : m_font(font)
540c68e499ce88a566485062518510f31f9869f41a2claireho    , m_startingX(startingX)
541bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    , m_startingY(startingY)
542c68e499ce88a566485062518510f31f9869f41a2claireho    , m_offsetX(m_startingX)
543c68e499ce88a566485062518510f31f9869f41a2claireho    , m_run(getNormalizedTextRun(run, m_normalizedRun, m_normalizedBuffer))
544c68e499ce88a566485062518510f31f9869f41a2claireho    , m_iterateBackwards(m_run.rtl())
545c68e499ce88a566485062518510f31f9869f41a2claireho    , m_wordSpacingAdjustment(0)
546c68e499ce88a566485062518510f31f9869f41a2claireho    , m_padding(0)
547c68e499ce88a566485062518510f31f9869f41a2claireho    , m_padPerWordBreak(0)
548c68e499ce88a566485062518510f31f9869f41a2claireho    , m_padError(0)
549c68e499ce88a566485062518510f31f9869f41a2claireho    , m_letterSpacing(0)
550c68e499ce88a566485062518510f31f9869f41a2claireho{
551c68e499ce88a566485062518510f31f9869f41a2claireho    // Do not use |run| inside this constructor. Use |m_run| instead.
552c68e499ce88a566485062518510f31f9869f41a2claireho
553c68e499ce88a566485062518510f31f9869f41a2claireho    memset(&m_item, 0, sizeof(m_item));
554c68e499ce88a566485062518510f31f9869f41a2claireho    // We cannot know, ahead of time, how many glyphs a given script run
555c68e499ce88a566485062518510f31f9869f41a2claireho    // will produce. We take a guess that script runs will not produce more
556c68e499ce88a566485062518510f31f9869f41a2claireho    // than twice as many glyphs as there are code points plus a bit of
557c68e499ce88a566485062518510f31f9869f41a2claireho    // padding and fallback if we find that we are wrong.
558c68e499ce88a566485062518510f31f9869f41a2claireho    createGlyphArrays((m_run.length() + 2) * 2);
559c68e499ce88a566485062518510f31f9869f41a2claireho
560c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.log_clusters = new unsigned short[m_run.length()];
561c68e499ce88a566485062518510f31f9869f41a2claireho
562c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.face = 0;
563c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.font = allocHarfbuzzFont();
564c68e499ce88a566485062518510f31f9869f41a2claireho
565c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.item.bidiLevel = m_run.rtl();
566c68e499ce88a566485062518510f31f9869f41a2claireho
567c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.string = m_run.characters();
568c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.stringLength = m_run.length();
569c68e499ce88a566485062518510f31f9869f41a2claireho
570c68e499ce88a566485062518510f31f9869f41a2claireho    reset();
571c68e499ce88a566485062518510f31f9869f41a2claireho}
572c68e499ce88a566485062518510f31f9869f41a2claireho
573c68e499ce88a566485062518510f31f9869f41a2clairehoTextRunWalker::~TextRunWalker()
574c68e499ce88a566485062518510f31f9869f41a2claireho{
575c68e499ce88a566485062518510f31f9869f41a2claireho    fastFree(m_item.font);
576c68e499ce88a566485062518510f31f9869f41a2claireho    deleteGlyphArrays();
577c68e499ce88a566485062518510f31f9869f41a2claireho    delete[] m_item.log_clusters;
578c68e499ce88a566485062518510f31f9869f41a2claireho}
579c68e499ce88a566485062518510f31f9869f41a2claireho
580c68e499ce88a566485062518510f31f9869f41a2clairehobool TextRunWalker::isWordBreak(unsigned index, bool isRTL)
581c68e499ce88a566485062518510f31f9869f41a2claireho{
582c68e499ce88a566485062518510f31f9869f41a2claireho    if (!isRTL)
583c68e499ce88a566485062518510f31f9869f41a2claireho        return index && isCodepointSpace(m_item.string[index])
584c68e499ce88a566485062518510f31f9869f41a2claireho            && !isCodepointSpace(m_item.string[index - 1]);
585c68e499ce88a566485062518510f31f9869f41a2claireho    return index != m_item.stringLength - 1 && isCodepointSpace(m_item.string[index])
586c68e499ce88a566485062518510f31f9869f41a2claireho        && !isCodepointSpace(m_item.string[index + 1]);
587c68e499ce88a566485062518510f31f9869f41a2claireho}
588c68e499ce88a566485062518510f31f9869f41a2claireho
589c68e499ce88a566485062518510f31f9869f41a2claireho// setPadding sets a number of pixels to be distributed across the TextRun.
590c68e499ce88a566485062518510f31f9869f41a2claireho// WebKit uses this to justify text.
591c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::setPadding(int padding)
592c68e499ce88a566485062518510f31f9869f41a2claireho{
593c68e499ce88a566485062518510f31f9869f41a2claireho    m_padding = padding;
594c68e499ce88a566485062518510f31f9869f41a2claireho    if (!m_padding)
595c68e499ce88a566485062518510f31f9869f41a2claireho        return;
596c68e499ce88a566485062518510f31f9869f41a2claireho
597c68e499ce88a566485062518510f31f9869f41a2claireho    // If we have padding to distribute, then we try to give an equal
598c68e499ce88a566485062518510f31f9869f41a2claireho    // amount to each space. The last space gets the smaller amount, if
599c68e499ce88a566485062518510f31f9869f41a2claireho    // any.
600c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned numWordBreaks = 0;
601c68e499ce88a566485062518510f31f9869f41a2claireho    bool isRTL = m_iterateBackwards;
602c68e499ce88a566485062518510f31f9869f41a2claireho
603c68e499ce88a566485062518510f31f9869f41a2claireho    for (unsigned i = 0; i < m_item.stringLength; i++) {
604c68e499ce88a566485062518510f31f9869f41a2claireho        if (isWordBreak(i, isRTL))
605c68e499ce88a566485062518510f31f9869f41a2claireho            numWordBreaks++;
606c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
607c882e887207fecca865d26ab84fcc541c1b08fd9claireho
608c68e499ce88a566485062518510f31f9869f41a2claireho    if (numWordBreaks)
609c68e499ce88a566485062518510f31f9869f41a2claireho        m_padPerWordBreak = m_padding / numWordBreaks;
610c68e499ce88a566485062518510f31f9869f41a2claireho    else
611c68e499ce88a566485062518510f31f9869f41a2claireho        m_padPerWordBreak = 0;
612c68e499ce88a566485062518510f31f9869f41a2claireho}
613c68e499ce88a566485062518510f31f9869f41a2claireho
614c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::reset()
615c68e499ce88a566485062518510f31f9869f41a2claireho{
616c68e499ce88a566485062518510f31f9869f41a2claireho    if (m_iterateBackwards)
617c68e499ce88a566485062518510f31f9869f41a2claireho        m_indexOfNextScriptRun = m_run.length() - 1;
618c68e499ce88a566485062518510f31f9869f41a2claireho    else
619c68e499ce88a566485062518510f31f9869f41a2claireho        m_indexOfNextScriptRun = 0;
620c68e499ce88a566485062518510f31f9869f41a2claireho    m_offsetX = m_startingX;
621c68e499ce88a566485062518510f31f9869f41a2claireho}
622c68e499ce88a566485062518510f31f9869f41a2claireho
623c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::setBackwardsIteration(bool isBackwards)
624c68e499ce88a566485062518510f31f9869f41a2claireho{
625c68e499ce88a566485062518510f31f9869f41a2claireho    m_iterateBackwards = isBackwards;
626c68e499ce88a566485062518510f31f9869f41a2claireho    reset();
627c68e499ce88a566485062518510f31f9869f41a2claireho}
628c68e499ce88a566485062518510f31f9869f41a2claireho
629c68e499ce88a566485062518510f31f9869f41a2claireho// Advance to the next script run, returning false when the end of the
630c68e499ce88a566485062518510f31f9869f41a2claireho// TextRun has been reached.
631c68e499ce88a566485062518510f31f9869f41a2clairehobool TextRunWalker::nextScriptRun()
632c68e499ce88a566485062518510f31f9869f41a2claireho{
633c68e499ce88a566485062518510f31f9869f41a2claireho    if (m_iterateBackwards) {
634c68e499ce88a566485062518510f31f9869f41a2claireho        // In right-to-left mode we need to render the shaped glyph backwards and
635c68e499ce88a566485062518510f31f9869f41a2claireho        // also render the script runs themselves backwards. So given a TextRun:
636c68e499ce88a566485062518510f31f9869f41a2claireho        //    AAAAAAACTTTTTTT   (A = Arabic, C = Common, T = Thai)
637c68e499ce88a566485062518510f31f9869f41a2claireho        // we render:
638c68e499ce88a566485062518510f31f9869f41a2claireho        //    TTTTTTCAAAAAAA
639c68e499ce88a566485062518510f31f9869f41a2claireho        // (and the glyphs in each A, C and T section are backwards too)
640c68e499ce88a566485062518510f31f9869f41a2claireho        if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(),
641c68e499ce88a566485062518510f31f9869f41a2claireho            m_run.length(), &m_indexOfNextScriptRun))
642c68e499ce88a566485062518510f31f9869f41a2claireho            return false;
643c68e499ce88a566485062518510f31f9869f41a2claireho    } else {
644c68e499ce88a566485062518510f31f9869f41a2claireho        if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(),
645c68e499ce88a566485062518510f31f9869f41a2claireho            m_run.length(), &m_indexOfNextScriptRun))
646c68e499ce88a566485062518510f31f9869f41a2claireho            return false;
647c68e499ce88a566485062518510f31f9869f41a2claireho
648c68e499ce88a566485062518510f31f9869f41a2claireho        // It is actually wrong to consider script runs at all in this code.
649c68e499ce88a566485062518510f31f9869f41a2claireho        // Other WebKit code (e.g. Mac) segments complex text just by finding
650c68e499ce88a566485062518510f31f9869f41a2claireho        // the longest span of text covered by a single font.
651c68e499ce88a566485062518510f31f9869f41a2claireho        // But we currently need to call hb_utf16_script_run_next anyway to fill
652c68e499ce88a566485062518510f31f9869f41a2claireho        // in the harfbuzz data structures to e.g. pick the correct script's shaper.
653c68e499ce88a566485062518510f31f9869f41a2claireho        // So we allow that to run first, then do a second pass over the range it
654c68e499ce88a566485062518510f31f9869f41a2claireho        // found and take the largest subregion that stays within a single font.
655c68e499ce88a566485062518510f31f9869f41a2claireho        const FontData* glyphData = m_font->glyphDataForCharacter(
656c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdoch           m_item.string[m_item.item.pos], false).fontData;
657c68e499ce88a566485062518510f31f9869f41a2claireho        unsigned endOfRun;
658c68e499ce88a566485062518510f31f9869f41a2claireho        for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) {
659c68e499ce88a566485062518510f31f9869f41a2claireho            const FontData* nextGlyphData = m_font->glyphDataForCharacter(
660c44f6b3b1e33ac1efbae8dc6e73fed0d329bafd4Ben Murdoch                m_item.string[m_item.item.pos + endOfRun], false).fontData;
661c68e499ce88a566485062518510f31f9869f41a2claireho            if (nextGlyphData != glyphData)
6625e45e11e0649161823ace17ca9e020111624a486claireho                break;
663c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
664c68e499ce88a566485062518510f31f9869f41a2claireho        m_item.item.length = endOfRun;
665c68e499ce88a566485062518510f31f9869f41a2claireho        m_indexOfNextScriptRun = m_item.item.pos + endOfRun;
666c68e499ce88a566485062518510f31f9869f41a2claireho    }
667c882e887207fecca865d26ab84fcc541c1b08fd9claireho
668c68e499ce88a566485062518510f31f9869f41a2claireho    setupFontForScriptRun();
669c68e499ce88a566485062518510f31f9869f41a2claireho    shapeGlyphs();
670bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    setGlyphPositions(rtl());
671c882e887207fecca865d26ab84fcc541c1b08fd9claireho
672c68e499ce88a566485062518510f31f9869f41a2claireho    return true;
673c68e499ce88a566485062518510f31f9869f41a2claireho}
6745e45e11e0649161823ace17ca9e020111624a486claireho
675c68e499ce88a566485062518510f31f9869f41a2clairehofloat TextRunWalker::widthOfFullRun()
676c68e499ce88a566485062518510f31f9869f41a2claireho{
677c68e499ce88a566485062518510f31f9869f41a2claireho    float widthSum = 0;
678c68e499ce88a566485062518510f31f9869f41a2claireho    while (nextScriptRun())
679c68e499ce88a566485062518510f31f9869f41a2claireho        widthSum += width();
6805e45e11e0649161823ace17ca9e020111624a486claireho
681c68e499ce88a566485062518510f31f9869f41a2claireho    return widthSum;
682c68e499ce88a566485062518510f31f9869f41a2claireho}
683c882e887207fecca865d26ab84fcc541c1b08fd9claireho
684c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::setWordAndLetterSpacing(int wordSpacingAdjustment,
685c68e499ce88a566485062518510f31f9869f41a2claireho                                            int letterSpacingAdjustment)
686c68e499ce88a566485062518510f31f9869f41a2claireho{
687c68e499ce88a566485062518510f31f9869f41a2claireho    setWordSpacingAdjustment(wordSpacingAdjustment);
688c68e499ce88a566485062518510f31f9869f41a2claireho    setLetterSpacingAdjustment(letterSpacingAdjustment);
689c68e499ce88a566485062518510f31f9869f41a2claireho}
690c882e887207fecca865d26ab84fcc541c1b08fd9claireho
6916afb175cd4fceab68383533f7f8539100067c5c9Russell Brennerconst FontPlatformData* TextRunWalker::setupComplexFont(
6922abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett    HB_Script script, const FontPlatformData& platformData)
6936afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner{
6942018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner    static FallbackHash fallbackPlatformData;
6952018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner
6962622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    // generate scriptStyleIndex - we need unique hash IDs for each style
6972622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    // of each script - normal, bold, italic, bolditalic. the first set of
6982622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    // NUM_SCRIPTS are the normal style version, followed by bold, then
6992622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    // italic, then bold italic. additional fake style bits can be added.
7002622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    int scriptStyleIndex = script;
7012622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    if (platformData.isFakeBold())
7022abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett        scriptStyleIndex += HB_ScriptCount;
7032622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    if (platformData.isFakeItalic())
7042abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett        scriptStyleIndex += HB_ScriptCount << 1;
7052622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease
7062622fb80bac785bc80c698cc7397e160b95db1e7Victoria Lease    FallbackFontKey key(scriptStyleIndex, platformData.size());
7072018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner    FontPlatformData* newPlatformData = 0;
7082018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner
7092018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner    if (!fallbackPlatformData.contains(key)) {
7102abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett        SkTypeface::Style currentStyle = SkTypeface::kNormal;
7112abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett        if (platformData.typeface())
7122abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett            currentStyle = platformData.typeface()->style();
7132abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett        SkTypeface* typeface = SkCreateTypefaceForScript(script, currentStyle,
7142abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett            SkPaint::kElegant_Variant);
7152018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner        newPlatformData = new FontPlatformData(platformData, typeface);
7166afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner        SkSafeUnref(typeface);
7172018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner        fallbackPlatformData.set(key, newPlatformData);
7186afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner    }
7196afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner
7202018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner    if (!newPlatformData)
7212018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner        newPlatformData = fallbackPlatformData.get(key);
7226afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner
7232018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner    // If we couldn't allocate a new FontPlatformData, revert to the one passed
7242018cbdd9add7cc6b5201f2bc8cba86e62bafc5cRussell Brenner    return newPlatformData ? newPlatformData : &platformData;
7256afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner}
7266afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner
727c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::setupFontForScriptRun()
728c68e499ce88a566485062518510f31f9869f41a2claireho{
7296afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner    const FontData* fontData = m_font->glyphDataForCharacter(m_run[0], false).fontData;
730c68e499ce88a566485062518510f31f9869f41a2claireho    const FontPlatformData& platformData =
731c68e499ce88a566485062518510f31f9869f41a2claireho        fontData->fontDataForCharacter(' ')->platformData();
7322abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett    const FontPlatformData* complexPlatformData = setupComplexFont(m_item.item.script, platformData);
7332abcb264d55635f9592eae8ec33a42a26e566de0Billy Hewlett
7346afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner    m_item.face = complexPlatformData->harfbuzzFace();
7356afb175cd4fceab68383533f7f8539100067c5c9Russell Brenner    m_item.font->userData = const_cast<FontPlatformData*>(complexPlatformData);
736b5adac2453b428ee1e9386919a89a395dc507bd6claireho
737b5adac2453b428ee1e9386919a89a395dc507bd6claireho    int size = complexPlatformData->size();
738b5adac2453b428ee1e9386919a89a395dc507bd6claireho    m_item.font->x_ppem = size;
739b5adac2453b428ee1e9386919a89a395dc507bd6claireho    m_item.font->y_ppem = size;
740b5adac2453b428ee1e9386919a89a395dc507bd6claireho    // x_ and y_scale are the conversion factors from font design space (fEmSize) to 1/64th of device pixels in 16.16 format.
741b5adac2453b428ee1e9386919a89a395dc507bd6claireho    const int devicePixelFraction = 64;
742b5adac2453b428ee1e9386919a89a395dc507bd6claireho    const int multiplyFor16Dot16 = 1 << 16;
743b5adac2453b428ee1e9386919a89a395dc507bd6claireho    int scale = devicePixelFraction * size * multiplyFor16Dot16 / complexPlatformData->emSizeInFontUnits();
744b5adac2453b428ee1e9386919a89a395dc507bd6claireho    m_item.font->x_scale = scale;
745b5adac2453b428ee1e9386919a89a395dc507bd6claireho    m_item.font->y_scale = scale;
746c68e499ce88a566485062518510f31f9869f41a2claireho}
747c882e887207fecca865d26ab84fcc541c1b08fd9claireho
748c68e499ce88a566485062518510f31f9869f41a2clairehoHB_FontRec* TextRunWalker::allocHarfbuzzFont()
749c68e499ce88a566485062518510f31f9869f41a2claireho{
750c68e499ce88a566485062518510f31f9869f41a2claireho    HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
751c68e499ce88a566485062518510f31f9869f41a2claireho    memset(font, 0, sizeof(HB_FontRec));
752c68e499ce88a566485062518510f31f9869f41a2claireho    font->klass = &harfbuzzSkiaClass;
753c68e499ce88a566485062518510f31f9869f41a2claireho    font->userData = 0;
754c68e499ce88a566485062518510f31f9869f41a2claireho
755c68e499ce88a566485062518510f31f9869f41a2claireho    return font;
756c68e499ce88a566485062518510f31f9869f41a2claireho}
757c882e887207fecca865d26ab84fcc541c1b08fd9claireho
758c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::deleteGlyphArrays()
759c68e499ce88a566485062518510f31f9869f41a2claireho{
760c68e499ce88a566485062518510f31f9869f41a2claireho    delete[] m_item.glyphs;
761c68e499ce88a566485062518510f31f9869f41a2claireho    delete[] m_item.attributes;
762c68e499ce88a566485062518510f31f9869f41a2claireho    delete[] m_item.advances;
763c68e499ce88a566485062518510f31f9869f41a2claireho    delete[] m_item.offsets;
764c68e499ce88a566485062518510f31f9869f41a2claireho    delete[] m_glyphs16;
765bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    delete[] m_positions;
766c68e499ce88a566485062518510f31f9869f41a2claireho}
76705b56c82bf622f2489e1f3c43355d968f7e52c79claireho
768c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::createGlyphArrays(int size)
769c68e499ce88a566485062518510f31f9869f41a2claireho{
770c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.glyphs = new HB_Glyph[size];
771c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.attributes = new HB_GlyphAttributes[size];
772c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.advances = new HB_Fixed[size];
773c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.offsets = new HB_FixedPoint[size];
77405b56c82bf622f2489e1f3c43355d968f7e52c79claireho
775c68e499ce88a566485062518510f31f9869f41a2claireho    m_glyphs16 = new uint16_t[size];
776bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    m_positions = new SkPoint[size];
77742e55eb4ff3bde03d17a4cbfe0e4244d3a7b3e14claireho
778c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.num_glyphs = size;
779c68e499ce88a566485062518510f31f9869f41a2claireho    m_glyphsArrayCapacity = size; // Save the GlyphArrays size.
780c68e499ce88a566485062518510f31f9869f41a2claireho}
781c882e887207fecca865d26ab84fcc541c1b08fd9claireho
782c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::resetGlyphArrays()
783c68e499ce88a566485062518510f31f9869f41a2claireho{
784c68e499ce88a566485062518510f31f9869f41a2claireho    int size = m_item.num_glyphs;
785c68e499ce88a566485062518510f31f9869f41a2claireho    // All the types here don't have pointers. It is safe to reset to
786c68e499ce88a566485062518510f31f9869f41a2claireho    // zero unless Harfbuzz breaks the compatibility in the future.
787c68e499ce88a566485062518510f31f9869f41a2claireho    memset(m_item.glyphs, 0, size * sizeof(m_item.glyphs[0]));
788c68e499ce88a566485062518510f31f9869f41a2claireho    memset(m_item.attributes, 0, size * sizeof(m_item.attributes[0]));
789c68e499ce88a566485062518510f31f9869f41a2claireho    memset(m_item.advances, 0, size * sizeof(m_item.advances[0]));
790c68e499ce88a566485062518510f31f9869f41a2claireho    memset(m_item.offsets, 0, size * sizeof(m_item.offsets[0]));
791c68e499ce88a566485062518510f31f9869f41a2claireho    memset(m_glyphs16, 0, size * sizeof(m_glyphs16[0]));
792bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    memset(m_positions, 0, size * sizeof(m_positions[0]));
793c68e499ce88a566485062518510f31f9869f41a2claireho}
794c68e499ce88a566485062518510f31f9869f41a2claireho
795c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::shapeGlyphs()
796c68e499ce88a566485062518510f31f9869f41a2claireho{
797c68e499ce88a566485062518510f31f9869f41a2claireho    // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to
798c68e499ce88a566485062518510f31f9869f41a2claireho    // HB_ShapeItem() used less space than was available, the capacity of
799c68e499ce88a566485062518510f31f9869f41a2claireho    // the array may be larger than the current value of m_item.num_glyphs.
800c68e499ce88a566485062518510f31f9869f41a2claireho    // So, we need to reset the num_glyphs to the capacity of the array.
801c68e499ce88a566485062518510f31f9869f41a2claireho    m_item.num_glyphs = m_glyphsArrayCapacity;
802c68e499ce88a566485062518510f31f9869f41a2claireho    resetGlyphArrays();
803c68e499ce88a566485062518510f31f9869f41a2claireho    while (!HB_ShapeItem(&m_item)) {
804c68e499ce88a566485062518510f31f9869f41a2claireho        // We overflowed our arrays. Resize and retry.
805c68e499ce88a566485062518510f31f9869f41a2claireho        // HB_ShapeItem fills in m_item.num_glyphs with the needed size.
806c68e499ce88a566485062518510f31f9869f41a2claireho        deleteGlyphArrays();
807c68e499ce88a566485062518510f31f9869f41a2claireho        createGlyphArrays(m_item.num_glyphs << 1);
80842e55eb4ff3bde03d17a4cbfe0e4244d3a7b3e14claireho        resetGlyphArrays();
809c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
810c68e499ce88a566485062518510f31f9869f41a2claireho}
811c882e887207fecca865d26ab84fcc541c1b08fd9claireho
812bdc9320d5f7265f1f893f8adebdef0414edd8e5bclairehovoid TextRunWalker::setGlyphPositions(bool isRTL)
813c68e499ce88a566485062518510f31f9869f41a2claireho{
814c68e499ce88a566485062518510f31f9869f41a2claireho    int position = 0;
815c68e499ce88a566485062518510f31f9869f41a2claireho    // logClustersIndex indexes logClusters for the first (or last when
816c68e499ce88a566485062518510f31f9869f41a2claireho    // RTL) codepoint of the current glyph.  Each time we advance a glyph,
817c68e499ce88a566485062518510f31f9869f41a2claireho    // we skip over all the codepoints that contributed to the current
818c68e499ce88a566485062518510f31f9869f41a2claireho    // glyph.
819c68e499ce88a566485062518510f31f9869f41a2claireho    unsigned logClustersIndex = isRTL && m_item.num_glyphs ? m_item.num_glyphs - 1 : 0;
820c68e499ce88a566485062518510f31f9869f41a2claireho
821c68e499ce88a566485062518510f31f9869f41a2claireho    for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) {
822c68e499ce88a566485062518510f31f9869f41a2claireho        // Glyphs are stored in logical order, but for layout purposes we
823c68e499ce88a566485062518510f31f9869f41a2claireho        // always go left to right.
824c68e499ce88a566485062518510f31f9869f41a2claireho        int i = isRTL ? m_item.num_glyphs - iter - 1 : iter;
825c68e499ce88a566485062518510f31f9869f41a2claireho
826c68e499ce88a566485062518510f31f9869f41a2claireho        m_glyphs16[i] = m_item.glyphs[i];
827b5adac2453b428ee1e9386919a89a395dc507bd6claireho        int offsetX = truncateFixedPointToInteger(m_item.offsets[i].x);
828b5adac2453b428ee1e9386919a89a395dc507bd6claireho        int offsetY = truncateFixedPointToInteger(m_item.offsets[i].y);
829b5adac2453b428ee1e9386919a89a395dc507bd6claireho        m_positions[i].set(SkIntToScalar(m_offsetX + position) + offsetX, m_startingY + offsetY);
830c68e499ce88a566485062518510f31f9869f41a2claireho
831c68e499ce88a566485062518510f31f9869f41a2claireho        int advance = truncateFixedPointToInteger(m_item.advances[i]);
832c68e499ce88a566485062518510f31f9869f41a2claireho        // The first half of the conjunction works around the case where
833c68e499ce88a566485062518510f31f9869f41a2claireho        // output glyphs aren't associated with any codepoints by the
834c68e499ce88a566485062518510f31f9869f41a2claireho        // clusters log.
835c68e499ce88a566485062518510f31f9869f41a2claireho        if (logClustersIndex < m_item.item.length
836c68e499ce88a566485062518510f31f9869f41a2claireho            && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) {
837c68e499ce88a566485062518510f31f9869f41a2claireho            advance += m_wordSpacingAdjustment;
838c68e499ce88a566485062518510f31f9869f41a2claireho
839c68e499ce88a566485062518510f31f9869f41a2claireho            if (m_padding > 0) {
840c68e499ce88a566485062518510f31f9869f41a2claireho                int toPad = roundf(m_padPerWordBreak + m_padError);
841c68e499ce88a566485062518510f31f9869f41a2claireho                m_padError += m_padPerWordBreak - toPad;
842c68e499ce88a566485062518510f31f9869f41a2claireho
843c68e499ce88a566485062518510f31f9869f41a2claireho                if (m_padding < toPad)
844c68e499ce88a566485062518510f31f9869f41a2claireho                    toPad = m_padding;
845c68e499ce88a566485062518510f31f9869f41a2claireho                m_padding -= toPad;
846c68e499ce88a566485062518510f31f9869f41a2claireho                advance += toPad;
847611087b9e5016d419f347b32251f279b8853e69dclaireho            }
848c68e499ce88a566485062518510f31f9869f41a2claireho        }
849611087b9e5016d419f347b32251f279b8853e69dclaireho
850af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        // ZeroWidthJoiners and ZeroWidthNonJoiners should be stripped by
851af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        // Harfbuzz, but aren't. Check for zwj and zwnj and replace with a
852af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        // zero width space. We get the glyph data for space instead of
853af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        // zeroWidthSpace because the latter was seen to render with an
854af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        // unexpected code point (the symbol for a cloud). Since the standard
855af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        // space is in page zero and since we've also confirmed that there is
856af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        // no advance on this glyph, that should be ok.
857af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        if (0 == m_item.advances[i]) {
858af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner            const HB_UChar16 c = m_item.string[m_item.item.pos + logClustersIndex];
859af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner            if ((c == zeroWidthJoiner) || (c == zeroWidthNonJoiner)) {
860af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner                static Glyph spaceGlyph = m_font->glyphDataForCharacter(space, false).glyph;
861af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner                m_glyphs16[i] = spaceGlyph;
862af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner            }
863af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        }
864af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner
865c68e499ce88a566485062518510f31f9869f41a2claireho        // TODO We would like to add m_letterSpacing after each cluster, but I
866c68e499ce88a566485062518510f31f9869f41a2claireho        // don't know where the cluster information is. This is typically
867c68e499ce88a566485062518510f31f9869f41a2claireho        // fine for Roman languages, but breaks more complex languages
868c68e499ce88a566485062518510f31f9869f41a2claireho        // terribly.
869c68e499ce88a566485062518510f31f9869f41a2claireho        // advance += m_letterSpacing;
870611087b9e5016d419f347b32251f279b8853e69dclaireho
871c68e499ce88a566485062518510f31f9869f41a2claireho        if (isRTL) {
872c68e499ce88a566485062518510f31f9869f41a2claireho            while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i)
873c68e499ce88a566485062518510f31f9869f41a2claireho                logClustersIndex--;
874c68e499ce88a566485062518510f31f9869f41a2claireho        } else {
875c68e499ce88a566485062518510f31f9869f41a2claireho            while (logClustersIndex < m_item.item.length
876c68e499ce88a566485062518510f31f9869f41a2claireho                   && logClusters()[logClustersIndex] == i)
877c68e499ce88a566485062518510f31f9869f41a2claireho                logClustersIndex++;
878c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
879c68e499ce88a566485062518510f31f9869f41a2claireho
880c68e499ce88a566485062518510f31f9869f41a2claireho        position += advance;
881c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
882c882e887207fecca865d26ab84fcc541c1b08fd9claireho
883c68e499ce88a566485062518510f31f9869f41a2claireho    m_pixelWidth = position;
884c68e499ce88a566485062518510f31f9869f41a2claireho    m_offsetX += m_pixelWidth;
885c68e499ce88a566485062518510f31f9869f41a2claireho}
886c68e499ce88a566485062518510f31f9869f41a2claireho
887c68e499ce88a566485062518510f31f9869f41a2clairehovoid TextRunWalker::normalizeSpacesAndMirrorChars(const UChar* source, bool rtl,
888c68e499ce88a566485062518510f31f9869f41a2claireho    UChar* destination, int length)
889c68e499ce88a566485062518510f31f9869f41a2claireho{
890c68e499ce88a566485062518510f31f9869f41a2claireho    int position = 0;
891c68e499ce88a566485062518510f31f9869f41a2claireho    bool error = false;
892c68e499ce88a566485062518510f31f9869f41a2claireho    // Iterate characters in source and mirror character if needed.
893c68e499ce88a566485062518510f31f9869f41a2claireho    while (position < length) {
894c68e499ce88a566485062518510f31f9869f41a2claireho        UChar32 character;
895c68e499ce88a566485062518510f31f9869f41a2claireho        int nextPosition = position;
896c68e499ce88a566485062518510f31f9869f41a2claireho        U16_NEXT(source, nextPosition, length, character);
897469c7a77ed7557a04a0797ff8ca3e4335a1c1be0Russell Brenner
898c68e499ce88a566485062518510f31f9869f41a2claireho        if (Font::treatAsSpace(character))
899469c7a77ed7557a04a0797ff8ca3e4335a1c1be0Russell Brenner            character = space;
900af8d2bfb02e56e28a749583c78e453288edce719Russell Brenner        else if (Font::treatAsZeroWidthSpaceInComplexScript(character))
901469c7a77ed7557a04a0797ff8ca3e4335a1c1be0Russell Brenner            character = zeroWidthSpace;
902c68e499ce88a566485062518510f31f9869f41a2claireho        else if (rtl)
903c68e499ce88a566485062518510f31f9869f41a2claireho            character = u_charMirror(character);
904469c7a77ed7557a04a0797ff8ca3e4335a1c1be0Russell Brenner
905c68e499ce88a566485062518510f31f9869f41a2claireho        U16_APPEND(destination, position, length, character, error);
906c68e499ce88a566485062518510f31f9869f41a2claireho        ASSERT(!error);
907c68e499ce88a566485062518510f31f9869f41a2claireho        position = nextPosition;
908c68e499ce88a566485062518510f31f9869f41a2claireho    }
909c68e499ce88a566485062518510f31f9869f41a2claireho}
910c68e499ce88a566485062518510f31f9869f41a2claireho
911c68e499ce88a566485062518510f31f9869f41a2clairehoconst TextRun& TextRunWalker::getNormalizedTextRun(const TextRun& originalRun,
912c68e499ce88a566485062518510f31f9869f41a2claireho    OwnPtr<TextRun>& normalizedRun, OwnArrayPtr<UChar>& normalizedBuffer)
913c68e499ce88a566485062518510f31f9869f41a2claireho{
914c68e499ce88a566485062518510f31f9869f41a2claireho    // Normalize the text run in three ways:
915c68e499ce88a566485062518510f31f9869f41a2claireho    // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks
916c68e499ce88a566485062518510f31f9869f41a2claireho    // (U+0300..) are used in the run. This conversion is necessary since most OpenType
917c68e499ce88a566485062518510f31f9869f41a2claireho    // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in
918c68e499ce88a566485062518510f31f9869f41a2claireho    // their GSUB tables.
919c68e499ce88a566485062518510f31f9869f41a2claireho    //
920c68e499ce88a566485062518510f31f9869f41a2claireho    // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since
921c68e499ce88a566485062518510f31f9869f41a2claireho    // the API returns FALSE (= not normalized) for complex runs that don't require NFC
922c68e499ce88a566485062518510f31f9869f41a2claireho    // normalization (e.g., Arabic text). Unless the run contains the diacritical marks,
923c68e499ce88a566485062518510f31f9869f41a2claireho    // Harfbuzz will do the same thing for us using the GSUB table.
924c68e499ce88a566485062518510f31f9869f41a2claireho    // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs
925c68e499ce88a566485062518510f31f9869f41a2claireho    // for characters like '\n' otherwise.
926c68e499ce88a566485062518510f31f9869f41a2claireho    // 3) Convert mirrored characters such as parenthesis for rtl text.
927c68e499ce88a566485062518510f31f9869f41a2claireho
928c68e499ce88a566485062518510f31f9869f41a2claireho    // Convert to NFC form if the text has diacritical marks.
929c68e499ce88a566485062518510f31f9869f41a2claireho    icu::UnicodeString normalizedString;
930c68e499ce88a566485062518510f31f9869f41a2claireho    UErrorCode error = U_ZERO_ERROR;
931c68e499ce88a566485062518510f31f9869f41a2claireho
932c68e499ce88a566485062518510f31f9869f41a2claireho    for (int16_t i = 0; i < originalRun.length(); ++i) {
933c68e499ce88a566485062518510f31f9869f41a2claireho        UChar ch = originalRun[i];
934c68e499ce88a566485062518510f31f9869f41a2claireho        if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
935c68e499ce88a566485062518510f31f9869f41a2claireho            icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(),
936c68e499ce88a566485062518510f31f9869f41a2claireho                                       originalRun.length()), UNORM_NFC, 0 /* no options */,
937c68e499ce88a566485062518510f31f9869f41a2claireho                                       normalizedString, error);
938c68e499ce88a566485062518510f31f9869f41a2claireho            if (U_FAILURE(error))
939c68e499ce88a566485062518510f31f9869f41a2claireho                return originalRun;
940c68e499ce88a566485062518510f31f9869f41a2claireho            break;
941abb274d1eae5637eee465c5618aac1266d8ce695claireho        }
942abb274d1eae5637eee465c5618aac1266d8ce695claireho    }
943abb274d1eae5637eee465c5618aac1266d8ce695claireho
944c68e499ce88a566485062518510f31f9869f41a2claireho    // Normalize space and mirror parenthesis for rtl text.
945c68e499ce88a566485062518510f31f9869f41a2claireho    int normalizedBufferLength;
946c68e499ce88a566485062518510f31f9869f41a2claireho    const UChar* sourceText;
947c68e499ce88a566485062518510f31f9869f41a2claireho    if (normalizedString.isEmpty()) {
948c68e499ce88a566485062518510f31f9869f41a2claireho        normalizedBufferLength = originalRun.length();
949c68e499ce88a566485062518510f31f9869f41a2claireho        sourceText = originalRun.characters();
950c68e499ce88a566485062518510f31f9869f41a2claireho    } else {
951c68e499ce88a566485062518510f31f9869f41a2claireho        normalizedBufferLength = normalizedString.length();
952c68e499ce88a566485062518510f31f9869f41a2claireho        sourceText = normalizedString.getBuffer();
953611087b9e5016d419f347b32251f279b8853e69dclaireho    }
954611087b9e5016d419f347b32251f279b8853e69dclaireho
955a299dfda6bbcec93b532b7ad3d118a9609fa9b75Steve Block    normalizedBuffer = adoptArrayPtr(new UChar[normalizedBufferLength + 1]);
956c882e887207fecca865d26ab84fcc541c1b08fd9claireho
957c68e499ce88a566485062518510f31f9869f41a2claireho    normalizeSpacesAndMirrorChars(sourceText, originalRun.rtl(), normalizedBuffer.get(),
958c68e499ce88a566485062518510f31f9869f41a2claireho                                  normalizedBufferLength);
959c882e887207fecca865d26ab84fcc541c1b08fd9claireho
960a299dfda6bbcec93b532b7ad3d118a9609fa9b75Steve Block    normalizedRun = adoptPtr(new TextRun(originalRun));
961c68e499ce88a566485062518510f31f9869f41a2claireho    normalizedRun->setText(normalizedBuffer.get(), normalizedBufferLength);
962c68e499ce88a566485062518510f31f9869f41a2claireho    return *normalizedRun;
963c68e499ce88a566485062518510f31f9869f41a2claireho}
964c882e887207fecca865d26ab84fcc541c1b08fd9claireho
965c882e887207fecca865d26ab84fcc541c1b08fd9clairehoFloatRect Font::selectionRectForComplexText(const TextRun& run,
966ccb5a79614e295dfefe24149ecc73f46e8bff0e7Kristian Monsen    const FloatPoint& point, int height, int from, int to) const
967c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
968d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount    int fromX = -1;
969d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount    int toX = -1;
970bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    TextRunWalker walker(run, 0, 0, this);
971611087b9e5016d419f347b32251f279b8853e69dclaireho    walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
972c882e887207fecca865d26ab84fcc541c1b08fd9claireho
973c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Base will point to the x offset for the current script run. Note that, in
974c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // the LTR case, width will be 0.
975c882e887207fecca865d26ab84fcc541c1b08fd9claireho    int base = walker.rtl() ? walker.widthOfFullRun() : 0;
976c882e887207fecca865d26ab84fcc541c1b08fd9claireho    const int leftEdge = base;
977c882e887207fecca865d26ab84fcc541c1b08fd9claireho
978c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // We want to enumerate the script runs in code point order in the following
979c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // code. This call also resets |walker|.
980c882e887207fecca865d26ab84fcc541c1b08fd9claireho    walker.setBackwardsIteration(false);
981d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount    if (!from)
982d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount        fromX = leftEdge;
983d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount    if (!to)
984d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount        toX = leftEdge;
985c882e887207fecca865d26ab84fcc541c1b08fd9claireho
986c882e887207fecca865d26ab84fcc541c1b08fd9claireho    while (walker.nextScriptRun() && (fromX == -1 || toX == -1)) {
987c882e887207fecca865d26ab84fcc541c1b08fd9claireho        // TextRunWalker will helpfully accumulate the x offsets for different
988c882e887207fecca865d26ab84fcc541c1b08fd9claireho        // script runs for us. For this code, however, we always want the x
989c882e887207fecca865d26ab84fcc541c1b08fd9claireho        // offsets to start from zero so we call this before each script run.
990c882e887207fecca865d26ab84fcc541c1b08fd9claireho        walker.setXOffsetToZero();
991c882e887207fecca865d26ab84fcc541c1b08fd9claireho
992c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (walker.rtl())
993c882e887207fecca865d26ab84fcc541c1b08fd9claireho            base -= walker.width();
994c882e887207fecca865d26ab84fcc541c1b08fd9claireho
995c882e887207fecca865d26ab84fcc541c1b08fd9claireho        int numCodePoints = static_cast<int>(walker.numCodePoints());
996c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (fromX == -1 && from < numCodePoints) {
997c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // |from| is within this script run. So we index the clusters log to
998c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // find which glyph this code-point contributed to and find its x
999c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // position.
1000c882e887207fecca865d26ab84fcc541c1b08fd9claireho            int glyph = walker.logClusters()[from];
1001bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho            fromX = base + walker.positions()[glyph].x();
1002d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount            if (walker.rtl())
1003d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount                fromX += truncateFixedPointToInteger(walker.advances()[glyph]);
1004d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount        } else
1005c882e887207fecca865d26ab84fcc541c1b08fd9claireho            from -= numCodePoints;
1006c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1007c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (toX == -1 && to < numCodePoints) {
1008c882e887207fecca865d26ab84fcc541c1b08fd9claireho            int glyph = walker.logClusters()[to];
1009bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho            toX = base + walker.positions()[glyph].x();
1010d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount            if (walker.rtl())
1011d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount                toX += truncateFixedPointToInteger(walker.advances()[glyph]);
1012d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount        } else
1013c882e887207fecca865d26ab84fcc541c1b08fd9claireho            to -= numCodePoints;
1014c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1015c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (!walker.rtl())
1016c882e887207fecca865d26ab84fcc541c1b08fd9claireho            base += walker.width();
1017c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
1018c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1019c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // The position in question might be just after the text.
1020c882e887207fecca865d26ab84fcc541c1b08fd9claireho    const int rightEdge = base;
1021c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (fromX == -1 && !from)
1022d6dc991adc33f2d0c1cb5c8ebea30d1a07d741a2George Mount        fromX = rightEdge;
1023c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (toX == -1 && !to)
1024c882e887207fecca865d26ab84fcc541c1b08fd9claireho        toX = rightEdge;
1025c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1026c882e887207fecca865d26ab84fcc541c1b08fd9claireho    ASSERT(fromX != -1 && toX != -1);
1027c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1028c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (fromX < toX)
1029c882e887207fecca865d26ab84fcc541c1b08fd9claireho        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
1030c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1031c882e887207fecca865d26ab84fcc541c1b08fd9claireho    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
1032c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
1033c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1034c882e887207fecca865d26ab84fcc541c1b08fd9clairehovoid Font::drawComplexText(GraphicsContext* gc, TextRun const& run,
1035c882e887207fecca865d26ab84fcc541c1b08fd9claireho                           FloatPoint const& point, int, int) const
1036c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
1037c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (!run.length())
1038c882e887207fecca865d26ab84fcc541c1b08fd9claireho        return;
1039c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1040c882e887207fecca865d26ab84fcc541c1b08fd9claireho    int mode = gc->textDrawingMode();
1041b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch    bool fill = mode & TextModeFill;
1042b2a9e2728d6dcf8aecf09fe037e942a8dba233c1Ben Murdoch    bool stroke = mode & TextModeStroke;
1043c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (!fill && !stroke)
1044c882e887207fecca865d26ab84fcc541c1b08fd9claireho        return;
1045c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1046c882e887207fecca865d26ab84fcc541c1b08fd9claireho    SkPaint fillPaint, strokePaint;
1047c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (fill)
1048c882e887207fecca865d26ab84fcc541c1b08fd9claireho        setupFill(&fillPaint, gc, primaryFont());
1049c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (stroke)
1050c882e887207fecca865d26ab84fcc541c1b08fd9claireho        setupStroke(&strokePaint, gc, primaryFont());
1051c882e887207fecca865d26ab84fcc541c1b08fd9claireho
105264e4b265f84573b97d408f7d3e5aa99a647be057Nicolas Roard    SkCanvas* canvas = gc->platformContext()->recordingCanvas();
105364e4b265f84573b97d408f7d3e5aa99a647be057Nicolas Roard
1054c882e887207fecca865d26ab84fcc541c1b08fd9claireho    bool haveMultipleLayers = isCanvasMultiLayered(canvas);
1055bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    TextRunWalker walker(run, point.x(), point.y(), this);
1056611087b9e5016d419f347b32251f279b8853e69dclaireho    walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
105722864c0fcfca794950482bfa8a79f37da16f509dSteve Block    walker.setPadding(run.expansion());
1058611087b9e5016d419f347b32251f279b8853e69dclaireho
1059c882e887207fecca865d26ab84fcc541c1b08fd9claireho    while (walker.nextScriptRun()) {
1060c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (fill) {
1061c882e887207fecca865d26ab84fcc541c1b08fd9claireho            walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
1062c882e887207fecca865d26ab84fcc541c1b08fd9claireho            adjustTextRenderMode(&fillPaint, haveMultipleLayers);
1063b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck            canvas->drawPosText(walker.glyphs(),
1064b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck                walker.length() << 1, walker.positions(), fillPaint);
1065c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
1066c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (stroke) {
1067c882e887207fecca865d26ab84fcc541c1b08fd9claireho            walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
1068c882e887207fecca865d26ab84fcc541c1b08fd9claireho            adjustTextRenderMode(&strokePaint, haveMultipleLayers);
1069b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck            canvas->drawPosText(walker.glyphs(),
1070b9f38925d3cdae56548c3c18300c2964d207ed4eJohn Reck                walker.length() << 1, walker.positions(), strokePaint);
1071c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
1072c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
107364e4b265f84573b97d408f7d3e5aa99a647be057Nicolas Roard
1074c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
1075c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1076c882e887207fecca865d26ab84fcc541c1b08fd9clairehofloat Font::floatWidthForComplexText(const TextRun& run,
1077c882e887207fecca865d26ab84fcc541c1b08fd9claireho            HashSet<const SimpleFontData*>*, GlyphOverflow*) const
1078c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
1079bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    TextRunWalker walker(run, 0, 0, this);
1080611087b9e5016d419f347b32251f279b8853e69dclaireho    walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
1081c882e887207fecca865d26ab84fcc541c1b08fd9claireho    return walker.widthOfFullRun();
1082c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
1083c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1084c882e887207fecca865d26ab84fcc541c1b08fd9clairehostatic int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x)
1085c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
1086c882e887207fecca865d26ab84fcc541c1b08fd9claireho    const HB_Fixed* advances = walker.advances();
1087c882e887207fecca865d26ab84fcc541c1b08fd9claireho    int glyphIndex;
1088c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (walker.rtl()) {
1089c882e887207fecca865d26ab84fcc541c1b08fd9claireho        for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) {
1090c882e887207fecca865d26ab84fcc541c1b08fd9claireho            if (x < truncateFixedPointToInteger(advances[glyphIndex]))
1091c882e887207fecca865d26ab84fcc541c1b08fd9claireho                break;
1092c882e887207fecca865d26ab84fcc541c1b08fd9claireho            x -= truncateFixedPointToInteger(advances[glyphIndex]);
1093c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
1094c882e887207fecca865d26ab84fcc541c1b08fd9claireho    } else {
1095c882e887207fecca865d26ab84fcc541c1b08fd9claireho        for (glyphIndex = 0; glyphIndex < static_cast<int>(walker.length());
1096c882e887207fecca865d26ab84fcc541c1b08fd9claireho             ++glyphIndex) {
1097c882e887207fecca865d26ab84fcc541c1b08fd9claireho            if (x < truncateFixedPointToInteger(advances[glyphIndex]))
1098c882e887207fecca865d26ab84fcc541c1b08fd9claireho                break;
1099c882e887207fecca865d26ab84fcc541c1b08fd9claireho            x -= truncateFixedPointToInteger(advances[glyphIndex]);
1100c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
1101c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
1102c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1103c882e887207fecca865d26ab84fcc541c1b08fd9claireho    return glyphIndex;
1104c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
1105c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1106ccb5a79614e295dfefe24149ecc73f46e8bff0e7Kristian Monsenint Font::offsetForPositionForComplexText(const TextRun& run, float x,
1107c882e887207fecca865d26ab84fcc541c1b08fd9claireho                                          bool includePartialGlyphs) const
1108c882e887207fecca865d26ab84fcc541c1b08fd9claireho{
1109c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // (Mac code ignores includePartialGlyphs, and they don't know what it's
1110c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // supposed to do, so we just ignore it as well.)
1111bdc9320d5f7265f1f893f8adebdef0414edd8e5bclaireho    TextRunWalker walker(run, 0, 0, this);
1112611087b9e5016d419f347b32251f279b8853e69dclaireho    walker.setWordAndLetterSpacing(wordSpacing(), letterSpacing());
1113c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1114c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // If this is RTL text, the first glyph from the left is actually the last
1115c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // code point. So we need to know how many code points there are total in
1116c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // order to subtract. This is different from the length of the TextRun
1117c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // because UTF-16 surrogate pairs are a single code point, but 32-bits long.
1118c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // In LTR we leave this as 0 so that we get the correct value for
1119c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // |basePosition|, below.
1120c882e887207fecca865d26ab84fcc541c1b08fd9claireho    unsigned totalCodePoints = 0;
1121c882e887207fecca865d26ab84fcc541c1b08fd9claireho    if (walker.rtl()) {
1122c882e887207fecca865d26ab84fcc541c1b08fd9claireho        ssize_t offset = 0;
1123c882e887207fecca865d26ab84fcc541c1b08fd9claireho        while (offset < run.length()) {
1124c882e887207fecca865d26ab84fcc541c1b08fd9claireho            utf16_to_code_point(run.characters(), run.length(), &offset);
1125c882e887207fecca865d26ab84fcc541c1b08fd9claireho            totalCodePoints++;
1126c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
1127c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
1128c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1129c882e887207fecca865d26ab84fcc541c1b08fd9claireho    unsigned basePosition = totalCodePoints;
1130c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1131c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // For RTL:
1132c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //   code-point order:  abcd efg hijkl
1133c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //   on screen:         lkjih gfe dcba
1134c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //                                ^   ^
1135c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //                                |   |
1136c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //                  basePosition--|   |
1137c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //                 totalCodePoints----|
1138c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // Since basePosition is currently the total number of code-points, the
1139c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // first thing we do is decrement it so that it's pointing to the start of
1140c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // the current script-run.
1141c882e887207fecca865d26ab84fcc541c1b08fd9claireho    //
1142c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // For LTR, basePosition is zero so it already points to the start of the
1143c882e887207fecca865d26ab84fcc541c1b08fd9claireho    // first script run.
1144c882e887207fecca865d26ab84fcc541c1b08fd9claireho    while (walker.nextScriptRun()) {
1145c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (walker.rtl())
1146c882e887207fecca865d26ab84fcc541c1b08fd9claireho            basePosition -= walker.numCodePoints();
1147c882e887207fecca865d26ab84fcc541c1b08fd9claireho
114805b56c82bf622f2489e1f3c43355d968f7e52c79claireho        if (x >= 0 && x < static_cast<int>(walker.width())) {
1149c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // The x value in question is within this script run. We consider
1150c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // each glyph in presentation order and stop when we find the one
1151c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // covering this position.
1152c882e887207fecca865d26ab84fcc541c1b08fd9claireho            const int glyphIndex = glyphIndexForXPositionInScriptRun(walker, x);
1153c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1154c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // Now that we have a glyph index, we have to turn that into a
1155c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // code-point index. Because of ligatures, several code-points may
1156c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // have gone into a single glyph. We iterate over the clusters log
1157c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // and find the first code-point which contributed to the glyph.
1158c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1159c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // Some shapers (i.e. Khmer) will produce cluster logs which report
1160c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // that /no/ code points contributed to certain glyphs. Because of
1161c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // this, we take any code point which contributed to the glyph in
1162c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // question, or any subsequent glyph. If we run off the end, then
1163c882e887207fecca865d26ab84fcc541c1b08fd9claireho            // we take the last code point.
1164c882e887207fecca865d26ab84fcc541c1b08fd9claireho            const unsigned short* log = walker.logClusters();
1165c882e887207fecca865d26ab84fcc541c1b08fd9claireho            for (unsigned j = 0; j < walker.numCodePoints(); ++j) {
1166c882e887207fecca865d26ab84fcc541c1b08fd9claireho                if (log[j] >= glyphIndex)
1167c882e887207fecca865d26ab84fcc541c1b08fd9claireho                    return basePosition + j;
1168c882e887207fecca865d26ab84fcc541c1b08fd9claireho            }
1169c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1170c882e887207fecca865d26ab84fcc541c1b08fd9claireho            return basePosition + walker.numCodePoints() - 1;
1171c882e887207fecca865d26ab84fcc541c1b08fd9claireho        }
1172c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1173c882e887207fecca865d26ab84fcc541c1b08fd9claireho        x -= walker.width();
1174c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1175c882e887207fecca865d26ab84fcc541c1b08fd9claireho        if (!walker.rtl())
1176c882e887207fecca865d26ab84fcc541c1b08fd9claireho            basePosition += walker.numCodePoints();
1177c882e887207fecca865d26ab84fcc541c1b08fd9claireho    }
1178c882e887207fecca865d26ab84fcc541c1b08fd9claireho
1179c882e887207fecca865d26ab84fcc541c1b08fd9claireho    return basePosition;
1180c882e887207fecca865d26ab84fcc541c1b08fd9claireho}
1181c882e887207fecca865d26ab84fcc541c1b08fd9claireho#endif
1182c882e887207fecca865d26ab84fcc541c1b08fd9claireho
11838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1184