FontCacheBlackBerry.cpp [plain text]
#include "config.h"
#include "FontCache.h"
#include "Font.h"
#include "FontDescription.h"
#include "FontPlatformData.h"
#include "ITypeUtils.h"
#include "Logging.h"
#include "NotImplemented.h"
#include "SimpleFontData.h"
#include <BlackBerryPlatformGraphicsContext.h>
#include <fontconfig/fontconfig.h>
#include <fs_api.h>
#include <unicode/locid.h>
#include <unistd.h>
#include <wtf/Assertions.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/CString.h>
namespace WebCore {
void FontCache::platformInit()
{
if (!FcInit())
CRASH();
}
void FontCache::getFontFamilyForCharacters(const UChar* characters, size_t numCharacters, const char*, const FontDescription& description, SimpleFontFamily* family)
{
FcCharSet* cset = FcCharSetCreate();
for (size_t i = 0; i < numCharacters; ++i) {
if (U16_IS_SURROGATE(characters[i])
&& U16_IS_SURROGATE_LEAD(characters[i])
&& i != numCharacters - 1
&& U16_IS_TRAIL(characters[i + 1])) {
FcCharSetAddChar(cset, U16_GET_SUPPLEMENTARY(characters[i], characters[i+1]));
i++;
} else
FcCharSetAddChar(cset, characters[i]);
}
FcPattern* pattern = FcPatternCreate();
FcValue fcvalue;
fcvalue.type = FcTypeCharSet;
fcvalue.u.c = cset;
FcPatternAdd(pattern, FC_CHARSET, fcvalue, FcFalse);
fcvalue.type = FcTypeBool;
fcvalue.u.b = FcTrue;
FcPatternAdd(pattern, FC_SCALABLE, fcvalue, FcFalse);
fcvalue.type = FcTypeInteger;
fcvalue.u.i = (description.weight() >= FontWeightBold) ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
FcPatternAdd(pattern, FC_WEIGHT, fcvalue, FcFalse);
fcvalue.type = FcTypeInteger;
fcvalue.u.i = (description.italic() == FontItalicOn) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
FcPatternAdd(pattern, FC_SLANT, fcvalue, FcFalse);
FcConfigSubstitute(0, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
FcResult result;
FcFontSet* fontSet = FcFontSort(0, pattern, 0, 0, &result);
FcPatternDestroy(pattern);
FcCharSetDestroy(cset);
if (!fontSet) {
family->name = String();
family->isBold = false;
family->isItalic = false;
return;
}
for (int i = 0; i < fontSet->nfont; ++i) {
FcPattern* current = fontSet->fonts[i];
FcBool isScalable;
if (FcPatternGetBool(current, FC_SCALABLE, 0, &isScalable) != FcResultMatch
|| !isScalable)
continue;
FcChar8* cFilename;
if (FcPatternGetString(current, FC_FILE, 0, &cFilename) != FcResultMatch)
continue;
if (access(reinterpret_cast<char*>(cFilename), R_OK))
continue;
FcChar8* familyName;
if (FcPatternGetString(current, FC_FAMILY, 0, &familyName) == FcResultMatch) {
const char* charFamily = reinterpret_cast<char*>(familyName);
family->name = String::fromUTF8(charFamily, strlen(charFamily));
}
int weight;
if (FcPatternGetInteger(current, FC_WEIGHT, 0, &weight) == FcResultMatch)
family->isBold = weight >= FC_WEIGHT_BOLD;
else
family->isBold = false;
int slant;
if (FcPatternGetInteger(current, FC_SLANT, 0, &slant) == FcResultMatch)
family->isItalic = slant != FC_SLANT_ROMAN;
else
family->isItalic = false;
FcFontSetDestroy(fontSet);
return;
}
FcFontSetDestroy(fontSet);
}
PassRefPtr<SimpleFontData> FontCache::systemFallbackForCharacters(const FontDescription& fontDescription, const SimpleFontData*, bool, const UChar* characters, int length)
{
icu::Locale locale = icu::Locale::getDefault();
FontCache::SimpleFontFamily family;
FontCache::getFontFamilyForCharacters(characters, length, locale.getLanguage(), fontDescription, &family);
if (family.name.isEmpty())
return 0;
AtomicString atomicFamily(family.name);
bool shouldSetFakeBold = false;
bool shouldSetFakeItalic = false;
FontDescription description(fontDescription);
if (family.isBold && description.weight() < FontWeightBold)
description.setWeight(FontWeightBold);
if (!family.isBold && description.weight() >= FontWeightBold) {
shouldSetFakeBold = true;
description.setWeight(FontWeightNormal);
}
if (family.isItalic && description.italic() == FontItalicOff)
description.setItalic(FontItalicOn);
if (!family.isItalic && description.italic() == FontItalicOn) {
shouldSetFakeItalic = true;
description.setItalic(FontItalicOff);
}
FontPlatformData* substitutePlatformData = getCachedFontPlatformData(description, atomicFamily, DoNotRetain);
if (!substitutePlatformData)
return 0;
FontPlatformData platformData = FontPlatformData(*substitutePlatformData);
platformData.setFakeBold(shouldSetFakeBold);
platformData.setFakeItalic(shouldSetFakeItalic);
return getCachedFontData(&platformData, DoNotRetain);
}
PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& description, ShouldRetain)
{
DEFINE_STATIC_LOCAL(const AtomicString, sansStr, ("Sans"));
DEFINE_STATIC_LOCAL(const AtomicString, serifStr, ("Serif"));
DEFINE_STATIC_LOCAL(const AtomicString, monospaceStr, ("Monospace"));
FontPlatformData* fontPlatformData = 0;
switch (description.genericFamily()) {
case FontDescription::SerifFamily:
fontPlatformData = getCachedFontPlatformData(description, serifStr);
break;
case FontDescription::MonospaceFamily:
fontPlatformData = getCachedFontPlatformData(description, monospaceStr);
break;
case FontDescription::SansSerifFamily:
default:
fontPlatformData = getCachedFontPlatformData(description, sansStr);
break;
}
if (!fontPlatformData) {
DEFINE_STATIC_LOCAL(const AtomicString, arialStr, ("Arial"));
fontPlatformData = getCachedFontPlatformData(description, arialStr);
}
ASSERT(fontPlatformData);
return getCachedFontData(fontPlatformData);
}
void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&)
{
notImplemented();
}
static String getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family)
{
if (family.length() && !family.startsWith("-webkit-"))
return family.string();
switch (fontDescription.genericFamily()) {
case FontDescription::StandardFamily:
case FontDescription::SerifFamily:
return "serif";
case FontDescription::SansSerifFamily:
return "sans-serif";
case FontDescription::MonospaceFamily:
return "monospace";
case FontDescription::CursiveFamily:
return "cursive";
case FontDescription::FantasyFamily:
return "fantasy";
case FontDescription::NoFamily:
default:
return "";
}
}
int fontWeightToFontconfigWeight(FontWeight weight)
{
switch (weight) {
case FontWeight100:
return FC_WEIGHT_THIN;
case FontWeight200:
return FC_WEIGHT_ULTRALIGHT;
case FontWeight300:
return FC_WEIGHT_LIGHT;
case FontWeight400:
return FC_WEIGHT_REGULAR;
case FontWeight500:
return FC_WEIGHT_MEDIUM;
case FontWeight600:
return FC_WEIGHT_SEMIBOLD;
case FontWeight700:
return FC_WEIGHT_BOLD;
case FontWeight800:
return FC_WEIGHT_EXTRABOLD;
case FontWeight900:
return FC_WEIGHT_ULTRABLACK;
default:
ASSERT_NOT_REACHED();
return FC_WEIGHT_REGULAR;
}
}
PassOwnPtr<FontPlatformData> FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
{
FcPattern* pattern = FcPatternCreate();
String familyNameString(getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family));
if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data())))
return nullptr;
bool italic = fontDescription.italic();
if (!FcPatternAddInteger(pattern, FC_SLANT, italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN))
return nullptr;
if (!FcPatternAddInteger(pattern, FC_WEIGHT, fontWeightToFontconfigWeight(fontDescription.weight())))
return nullptr;
if (!FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontDescription.computedPixelSize()))
return nullptr;
FcConfigSubstitute(0, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
FcChar8* fontConfigFamilyNameAfterConfiguration;
FcPatternGetString(pattern, FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration);
String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration));
FcResult fontConfigResult;
FcPattern* resultPattern = FcFontMatch(0, pattern, &fontConfigResult);
FcPatternDestroy(pattern);
if (!resultPattern) return nullptr;
FcChar8* fontConfigFamilyNameAfterMatching;
FcPatternGetString(resultPattern, FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching);
String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching));
if (!equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching)
&& !(equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif")
|| equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace")
|| equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive")))
return nullptr;
int fontWeight;
FcPatternGetInteger(resultPattern, FC_WEIGHT, 0, &fontWeight);
bool shouldFakeBold = fontWeight < FC_WEIGHT_BOLD && fontDescription.weight() >= FontWeightBold;
int fontSlant;
FcPatternGetInteger(resultPattern, FC_SLANT, 0, &fontSlant);
bool shouldFakeItalic = fontSlant == FC_SLANT_ROMAN && fontDescription.italic() == FontItalicOn;
FcChar8* fontFileName;
FcPatternGetString(resultPattern, FC_FILE, 0, &fontFileName);
FcPatternDestroy(resultPattern);
FILECHAR name[MAX_FONT_NAME_LEN+1];
memset(name, 0, MAX_FONT_NAME_LEN+1);
if (FS_load_font(BlackBerry::Platform::Graphics::getIType(), reinterpret_cast<FILECHAR*>(fontFileName), 0, 0, MAX_FONT_NAME_LEN, name) != SUCCESS)
return nullptr;
return adoptPtr(new FontPlatformData(name, fontDescription.computedSize(), shouldFakeBold, shouldFakeItalic, fontDescription.orientation()));
}
}