blob: 1acfbb1113a237d89a1575c3d4dec6b1987df05a [file] [log] [blame]
/*
* Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#if ENABLE(SVG_FONTS)
#include "core/platform/graphics/SVGGlyph.h"
#include "wtf/unicode/Unicode.h"
using namespace WTF::Unicode;
namespace WebCore {
// Helper functions to determine the arabic character forms (initial, medial, terminal, isolated)
enum ArabicCharShapingMode {
SNone = 0,
SRight = 1,
SDual = 2
};
static const ArabicCharShapingMode s_arabicCharShapingMode[222] = {
SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, SDual , SDual , SDual , SDual , SDual , SRight, /* 0x0622 - 0x062F */
SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SNone , SNone , SNone , SNone , SNone , /* 0x0630 - 0x063F */
SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDual , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0640 - 0x064F */
SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0650 - 0x065F */
SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0660 - 0x066F */
SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0670 - 0x067F */
SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */
SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0690 - 0x069F */
SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06A0 - 0x06AF */
SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06B0 - 0x06BF */
SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, /* 0x06C0 - 0x06CF */
SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06D0 - 0x06DF */
SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06E0 - 0x06EF */
SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SDual , SDual , SDual , SNone , SNone , SNone /* 0x06F0 - 0x06FF */
};
static inline SVGGlyph::ArabicForm processArabicFormDetection(const UChar& curChar, bool& lastCharShapesRight, SVGGlyph::ArabicForm* prevForm)
{
SVGGlyph::ArabicForm curForm;
ArabicCharShapingMode shapingMode = SNone;
if (curChar >= 0x0622 && curChar <= 0x06FF)
shapingMode = s_arabicCharShapingMode[curChar - 0x0622];
// Use a simple state machine to identify the actual arabic form
// It depends on the order of the arabic form enum:
// enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial };
if (lastCharShapesRight && shapingMode == SDual) {
if (prevForm) {
int correctedForm = (int) *prevForm + 1;
ASSERT(correctedForm >= SVGGlyph::None && correctedForm <= SVGGlyph::Medial);
*prevForm = static_cast<SVGGlyph::ArabicForm>(correctedForm);
}
curForm = SVGGlyph::Initial;
} else
curForm = shapingMode == SNone ? SVGGlyph::None : SVGGlyph::Isolated;
lastCharShapesRight = shapingMode != SNone;
return curForm;
}
Vector<SVGGlyph::ArabicForm> charactersWithArabicForm(const String& input, bool rtl)
{
Vector<SVGGlyph::ArabicForm> forms;
unsigned length = input.length();
bool containsArabic = false;
for (unsigned i = 0; i < length; ++i) {
if (isArabicChar(input[i])) {
containsArabic = true;
break;
}
}
if (!containsArabic)
return forms;
bool lastCharShapesRight = false;
// Start identifying arabic forms
if (rtl) {
for (int i = length - 1; i >= 0; --i)
forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first()));
} else {
for (unsigned i = 0; i < length; ++i)
forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last()));
}
return forms;
}
static inline bool isCompatibleArabicForm(const SVGGlyph& identifier, const Vector<SVGGlyph::ArabicForm>& chars, unsigned startPosition, unsigned endPosition)
{
if (chars.isEmpty())
return true;
Vector<SVGGlyph::ArabicForm>::const_iterator realEnd = chars.end();
Vector<SVGGlyph::ArabicForm>::const_iterator it = chars.begin() + startPosition;
if (it >= realEnd)
return true;
Vector<SVGGlyph::ArabicForm>::const_iterator end = chars.begin() + endPosition;
if (end >= realEnd)
end = realEnd;
for (; it != end; ++it) {
if (*it != static_cast<SVGGlyph::ArabicForm>(identifier.arabicForm) && *it != SVGGlyph::None)
return false;
}
return true;
}
bool isCompatibleGlyph(const SVGGlyph& identifier, bool isVerticalText, const String& language,
const Vector<SVGGlyph::ArabicForm>& chars, unsigned startPosition, unsigned endPosition)
{
bool valid = true;
// Check wheter orientation if glyph fits within the request
switch (identifier.orientation) {
case SVGGlyph::Vertical:
valid = isVerticalText;
break;
case SVGGlyph::Horizontal:
valid = !isVerticalText;
break;
case SVGGlyph::Both:
break;
}
if (!valid)
return false;
// Check wheter languages are compatible
if (!identifier.languages.isEmpty()) {
// This glyph exists only in certain languages, if we're not specifying a
// language on the referencing element we're unable to use this glyph.
if (language.isEmpty())
return false;
// Split subcode from language, if existant.
String languagePrefix;
size_t subCodeSeparator = language.find('-');
if (subCodeSeparator != kNotFound)
languagePrefix = language.left(subCodeSeparator);
Vector<String>::const_iterator it = identifier.languages.begin();
Vector<String>::const_iterator end = identifier.languages.end();
bool found = false;
for (; it != end; ++it) {
const String& cur = *it;
if (cur == language || cur == languagePrefix) {
found = true;
break;
}
}
if (!found)
return false;
}
// Check wheter arabic form is compatible
return isCompatibleArabicForm(identifier, chars, startPosition, endPosition);
}
}
#endif