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