1/* 2 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 3 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21#include "config.h" 22 23#if ENABLE(SVG_FONTS) 24#include "SVGGlyph.h" 25 26namespace WebCore { 27 28// Helper functions to determine the arabic character forms (initial, medial, terminal, isolated) 29enum ArabicCharShapingMode { 30 SNone = 0, 31 SRight = 1, 32 SDual = 2 33}; 34 35static const ArabicCharShapingMode s_arabicCharShapingMode[222] = { 36 SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, SDual , SDual , SDual , SDual , SDual , SRight, /* 0x0622 - 0x062F */ 37 SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SNone , SNone , SNone , SNone , SNone , /* 0x0630 - 0x063F */ 38 SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDual , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0640 - 0x064F */ 39 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0650 - 0x065F */ 40 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0660 - 0x066F */ 41 SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0670 - 0x067F */ 42 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */ 43 SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0690 - 0x069F */ 44 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06A0 - 0x06AF */ 45 SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06B0 - 0x06BF */ 46 SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, /* 0x06C0 - 0x06CF */ 47 SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06D0 - 0x06DF */ 48 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06E0 - 0x06EF */ 49 SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SDual , SDual , SDual , SNone , SNone , SNone /* 0x06F0 - 0x06FF */ 50}; 51 52static inline SVGGlyph::ArabicForm processArabicFormDetection(const UChar& curChar, bool& lastCharShapesRight, SVGGlyph::ArabicForm* prevForm) 53{ 54 SVGGlyph::ArabicForm curForm; 55 56 ArabicCharShapingMode shapingMode = SNone; 57 if (curChar >= 0x0622 && curChar <= 0x06FF) 58 shapingMode = s_arabicCharShapingMode[curChar - 0x0622]; 59 60 // Use a simple state machine to identify the actual arabic form 61 // It depends on the order of the arabic form enum: 62 // enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial }; 63 64 if (lastCharShapesRight && shapingMode == SDual) { 65 if (prevForm) { 66 int correctedForm = (int) *prevForm + 1; 67 ASSERT(correctedForm >= SVGGlyph::None && correctedForm <= SVGGlyph::Medial); 68 *prevForm = static_cast<SVGGlyph::ArabicForm>(correctedForm); 69 } 70 71 curForm = SVGGlyph::Initial; 72 } else 73 curForm = shapingMode == SNone ? SVGGlyph::None : SVGGlyph::Isolated; 74 75 lastCharShapesRight = shapingMode != SNone; 76 return curForm; 77} 78 79Vector<SVGGlyph::ArabicForm> charactersWithArabicForm(const String& input, bool rtl) 80{ 81 Vector<SVGGlyph::ArabicForm> forms; 82 unsigned length = input.length(); 83 84 bool containsArabic = false; 85 for (unsigned i = 0; i < length; ++i) { 86 if (ublock_getCode(input[i]) == UBLOCK_ARABIC) { 87 containsArabic = true; 88 break; 89 } 90 } 91 92 if (!containsArabic) 93 return forms; 94 95 bool lastCharShapesRight = false; 96 97 // Start identifying arabic forms 98 if (rtl) { 99 for (int i = length - 1; i >= 0; --i) 100 forms.insert(0, processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first())); 101 } else { 102 for (unsigned i = 0; i < length; ++i) 103 forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last())); 104 } 105 106 return forms; 107} 108 109static inline bool isCompatibleArabicForm(const SVGGlyph& identifier, const Vector<SVGGlyph::ArabicForm>& chars, unsigned startPosition, unsigned endPosition) 110{ 111 if (chars.isEmpty()) 112 return true; 113 114 Vector<SVGGlyph::ArabicForm>::const_iterator realEnd = chars.end(); 115 Vector<SVGGlyph::ArabicForm>::const_iterator it = chars.begin() + startPosition; 116 if (it >= realEnd) 117 return true; 118 119 Vector<SVGGlyph::ArabicForm>::const_iterator end = chars.begin() + endPosition; 120 if (end >= realEnd) 121 end = realEnd; 122 123 for (; it != end; ++it) { 124 if (*it != static_cast<SVGGlyph::ArabicForm>(identifier.arabicForm) && *it != SVGGlyph::None) 125 return false; 126 } 127 128 return true; 129} 130 131bool isCompatibleGlyph(const SVGGlyph& identifier, bool isVerticalText, const String& language, 132 const Vector<SVGGlyph::ArabicForm>& chars, unsigned startPosition, unsigned endPosition) 133{ 134 bool valid = true; 135 136 // Check wheter orientation if glyph fits within the request 137 switch (identifier.orientation) { 138 case SVGGlyph::Vertical: 139 valid = isVerticalText; 140 break; 141 case SVGGlyph::Horizontal: 142 valid = !isVerticalText; 143 break; 144 case SVGGlyph::Both: 145 break; 146 } 147 148 if (!valid) 149 return false; 150 151 // Check wheter languages are compatible 152 if (!identifier.languages.isEmpty()) { 153 // This glyph exists only in certain languages, if we're not specifying a 154 // language on the referencing element we're unable to use this glyph. 155 if (language.isEmpty()) 156 return false; 157 158 // Split subcode from language, if existant. 159 String languagePrefix; 160 161 size_t subCodeSeparator = language.find('-'); 162 if (subCodeSeparator != notFound) 163 languagePrefix = language.left(subCodeSeparator); 164 165 Vector<String>::const_iterator it = identifier.languages.begin(); 166 Vector<String>::const_iterator end = identifier.languages.end(); 167 168 bool found = false; 169 for (; it != end; ++it) { 170 const String& cur = *it; 171 if (cur == language || cur == languagePrefix) { 172 found = true; 173 break; 174 } 175 } 176 177 if (!found) 178 return false; 179 } 180 181 // Check wheter arabic form is compatible 182 return isCompatibleArabicForm(identifier, chars, startPosition, endPosition); 183} 184 185} 186 187#endif 188