diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
commit | 635860845790a19bf50bbc51ba8fb66a96dde068 (patch) | |
tree | ef6ad9ff73a5b57f65249d4232a202fa77e6a140 /WebCore/platform/graphics/chromium | |
parent | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (diff) | |
download | external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.zip external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.gz external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.bz2 |
auto import from //depot/cupcake/@136594
Diffstat (limited to 'WebCore/platform/graphics/chromium')
31 files changed, 5462 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/chromium/ColorChromium.cpp b/WebCore/platform/graphics/chromium/ColorChromium.cpp new file mode 100644 index 0000000..16ca17d --- /dev/null +++ b/WebCore/platform/graphics/chromium/ColorChromium.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2008 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +namespace WebCore { + +Color focusRingColor() +{ +// FIXME: This should be split up to ColorChromiumWin and ColorChromiumMac. +#if PLATFORM(DARWIN) + // To avoid the Mac Chromium build having to rebasline 500+ layout tests and + // continue to do this w/ new tests that get landed in WebKit, we want to + // run the layout tests w/ the same color that stock WebKit uses. + // + // TODO: For now we've hard coded the color that WebKit uses for layout + // tests. We need to revisit this and do either of the following: + // A. Fully honor the color from the UI, which means collecting the color + // (and change notifications) in the browser process, and messaging the + // color to the render process. + // B. Adding a "layout tests" flag, to control the orage vs. blue colors + // depending if we're running layout tests. + // To see the WebKit implementation of using the UI color and/or a flag for + // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm. + // (Reality is we just need an api to override the focus color and both + // of the above are covered for what this file needs to provide, the + // two options would be details that happen in other places.) + + // From WebKit: + // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9; + static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF); + return oldAquaFocusRingColor; +#else + static Color focusRingColor(229, 151, 0, 255); + return focusRingColor; +#endif +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp new file mode 100644 index 0000000..03583a0 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontCache.h" + +#include "ChromiumBridge.h" +#include "Font.h" +#include "FontUtilsChromiumWin.h" +#include "HashMap.h" +#include "HashSet.h" +#include "SimpleFontData.h" +#include "StringHash.h" +#include <unicode/uniset.h> + +#include <windows.h> +#include <objidl.h> +#include <mlang.h> + +using std::min; + +namespace WebCore +{ + +void FontCache::platformInit() +{ + // Not needed on Windows. +} + +// FIXME: consider adding to WebKit String class +static bool charactersAreAllASCII(const String& s) +{ + return charactersAreAllASCII(s.characters(), s.length()); +} + +// When asked for a CJK font with a native name under a non-CJK locale or +// asked for a CJK font with a Romanized name under a CJK locale, +// |GetTextFace| (after |CreateFont*|) returns a 'bogus' value (e.g. Arial). +// This is not consistent with what MSDN says !! +// Therefore, before we call |CreateFont*|, we have to map a Romanized name to +// the corresponding native name under a CJK locale and vice versa +// under a non-CJK locale. +// See the corresponding gecko bugs at +// https://bugzilla.mozilla.org/show_bug.cgi?id=373952 +// https://bugzilla.mozilla.org/show_bug.cgi?id=231426 +static bool LookupAltName(const String& name, String& altName) +{ + struct FontCodepage { + WCHAR* name; + int codePage; + }; + + struct NamePair { + WCHAR* name; + FontCodepage altNameCodepage; + }; + + const int japaneseCodepage = 932; + const int simplifiedChineseCodepage = 936; + const int koreanCodepage = 949; + const int traditionalChineseCodepage = 950; + + // FIXME(jungshik) : This list probably covers 99% of cases. + // To cover the remaining 1% and cut down the file size, + // consider accessing 'NAME' table of a truetype font + // using |GetFontData| and caching the mapping. + // In the table below, the ASCII keys are all lower-cased for + // case-insensitive matching. + static const NamePair namePairs[] = { + // MS Pゴシック, MS PGothic + {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", {L"MS PGothic", japaneseCodepage}}, + {L"ms pgothic", {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, + // MS P明朝, MS PMincho + {L"\xFF2D\xFF33 \xFF30\x660E\x671D", {L"MS PMincho", japaneseCodepage}}, + {L"ms pmincho", {L"\xFF2D\xFF33 \xFF30\x660E\x671D", japaneseCodepage}}, + // MSゴシック, MS Gothic + {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", {L"MS Gothic", japaneseCodepage}}, + {L"ms gothic", {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, + // MS 明朝, MS Mincho + {L"\xFF2D\xFF33 \x660E\x671D", {L"MS Mincho", japaneseCodepage}}, + {L"ms mincho", {L"\xFF2D\xFF33 \x660E\x671D", japaneseCodepage}}, + // メイリオ, Meiryo + {L"\x30E1\x30A4\x30EA\x30AA", {L"Meiryo", japaneseCodepage}}, + {L"meiryo", {L"\x30E1\x30A4\x30EA\x30AA", japaneseCodepage}}, + // 바탕, Batang + {L"\xBC14\xD0D5", {L"Batang", koreanCodepage}}, + {L"batang", {L"\xBC14\xD0D5", koreanCodepage}}, + // 바탕체, Batangche + {L"\xBC14\xD0D5\xCCB4", {L"Batangche", koreanCodepage}}, + {L"batangche", {L"\xBC14\xD0D5\xCCB4", koreanCodepage}}, + // 굴림, Gulim + {L"\xAD74\xB9BC", {L"Gulim", koreanCodepage}}, + {L"gulim", {L"\xAD74\xB9BC", koreanCodepage}}, + // 굴림체, Gulimche + {L"\xAD74\xB9BC\xCCB4", {L"Gulimche", koreanCodepage}}, + {L"gulimche", {L"\xAD74\xB9BC\xCCB4", koreanCodepage}}, + // 돋움, Dotum + {L"\xB3CB\xC6C0", {L"Dotum", koreanCodepage}}, + {L"dotum", {L"\xB3CB\xC6C0", koreanCodepage}}, + // 돋움체, Dotumche + {L"\xB3CB\xC6C0\xCCB4", {L"Dotumche", koreanCodepage}}, + {L"dotumche", {L"\xB3CB\xC6C0\xCCB4", koreanCodepage}}, + // 궁서, Gungsuh + {L"\xAD81\xC11C", {L"Gungsuh", koreanCodepage}}, + {L"gungsuh", {L"\xAD81\xC11C", koreanCodepage}}, + // 궁서체, Gungsuhche + {L"\xAD81\xC11C\xCCB4", {L"Gungsuhche", koreanCodepage}}, + {L"gungsuhche", {L"\xAD81\xC11C\xCCB4", koreanCodepage}}, + // 맑은 고딕, Malgun Gothic + {L"\xB9D1\xC740 \xACE0\xB515", {L"Malgun Gothic", koreanCodepage}}, + {L"malgun gothic", {L"\xB9D1\xC740 \xACE0\xB515", koreanCodepage}}, + // 宋体, SimSun + {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}}, + {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}}, + // 黑体, SimHei + {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}}, + {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}}, + // 新宋体, NSimSun + {L"\x65B0\x5B8B\x4F53", {L"NSimSun", simplifiedChineseCodepage}}, + {L"nsimsun", {L"\x65B0\x5B8B\x4F53", simplifiedChineseCodepage}}, + // 微软雅黑, Microsoft Yahei + {L"\x5FAE\x8F6F\x96C5\x9ED1", {L"Microsoft Yahei", simplifiedChineseCodepage}}, + {L"microsoft yahei", {L"\x5FAE\x8F6F\x96C5\x9ED1", simplifiedChineseCodepage}}, + // 仿宋, FangSong + {L"\x4EFF\x5B8B", {L"FangSong", simplifiedChineseCodepage}}, + {L"fangsong", {L"\x4EFF\x5B8B", simplifiedChineseCodepage}}, + // 楷体, KaiTi + {L"\x6977\x4F53", {L"KaiTi", simplifiedChineseCodepage}}, + {L"kaiti", {L"\x6977\x4F53", simplifiedChineseCodepage}}, + // 仿宋_GB2312, FangSong_GB2312 + {L"\x4EFF\x5B8B_GB2312", {L"FangSong_GB2312", simplifiedChineseCodepage}}, + {L"fangsong_gb2312", {L"\x4EFF\x5B8B_gb2312", simplifiedChineseCodepage}}, + // 楷体_GB2312, KaiTi_GB2312 + {L"\x6977\x4F53", {L"KaiTi_GB2312", simplifiedChineseCodepage}}, + {L"kaiti_gb2312", {L"\x6977\x4F53_gb2312", simplifiedChineseCodepage}}, + // 新細明體, PMingLiu + {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}}, + {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, + // 細明體, MingLiu + {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}}, + {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, + // 微軟正黑體, Microsoft JhengHei + {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalChineseCodepage}}, + {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalChineseCodepage}}, + // 標楷體, DFKai-SB + {L"\x6A19\x6977\x9AD4", {L"DFKai-SB", traditionalChineseCodepage}}, + {L"dfkai-sb", {L"\x6A19\x6977\x9AD4", traditionalChineseCodepage}}, + // WenQuanYi Zen Hei + {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", {L"WenQuanYi Zen Hei", traditionalChineseCodepage}}, + {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", traditionalChineseCodepage}}, + // WenQuanYi Zen Hei + {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", {L"WenQuanYi Zen Hei", simplifiedChineseCodepage}}, + {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", simplifiedChineseCodepage}}, + // AR PL ShanHeiSun Uni, + {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", + {L"AR PL ShanHeiSun Uni", traditionalChineseCodepage}}, + {L"ar pl shanheisun uni", + {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", traditionalChineseCodepage}}, + // AR PL ShanHeiSun Uni, + {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", + {L"AR PL ShanHeiSun Uni", simplifiedChineseCodepage}}, + {L"ar pl shanheisun uni", + {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", simplifiedChineseCodepage}}, + // AR PL ZenKai Uni + // Traditional Chinese and Simplified Chinese names are + // identical. + {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", traditionalChineseCodepage}}, + {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", traditionalChineseCodepage}}, + {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", simplifiedChineseCodepage}}, + {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", simplifiedChineseCodepage}}, + }; + + typedef HashMap<String, const FontCodepage*> NameMap; + static NameMap* fontNameMap = 0; + + if (!fontNameMap) { + size_t numElements = sizeof(namePairs) / sizeof(NamePair); + fontNameMap = new NameMap; + for (size_t i = 0; i < numElements; ++i) + fontNameMap->set(String(namePairs[i].name), &(namePairs[i].altNameCodepage)); + } + + bool isAscii = false; + String n; + // use |lower| only for ASCII names + // For non-ASCII names, we don't want to invoke an expensive + // and unnecessary |lower|. + if (charactersAreAllASCII(name)) { + isAscii = true; + n = name.lower(); + } else + n = name; + + NameMap::iterator iter = fontNameMap->find(n); + if (iter == fontNameMap->end()) + return false; + + static int systemCp = ::GetACP(); + int fontCp = iter->second->codePage; + + if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) { + altName = String(iter->second->name); + return true; + } + + return false; +} + +static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winfont, String* winName) +{ + int len = min(static_cast<int>(family.length()), LF_FACESIZE - 1); + memcpy(winfont->lfFaceName, family.characters(), len * sizeof(WORD)); + winfont->lfFaceName[len] = '\0'; + + HFONT hfont = CreateFontIndirect(winfont); + if (!hfont) + return 0; + + HDC dc = GetDC(0); + HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont)); + WCHAR name[LF_FACESIZE]; + unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name); + if (resultLength > 0) + resultLength--; // ignore the null terminator + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + *winName = String(name, resultLength); + return hfont; +} + +// This maps font family names to their repertoires of supported Unicode +// characters. Because it's family names rather than font faces we use +// as keys, there might be edge cases where one face of a font family +// has a different repertoire from another face of the same family. +typedef HashMap<const wchar_t*, UnicodeSet*> FontCmapCache; + +static bool fontContainsCharacter(const FontPlatformData* fontData, + const wchar_t* family, UChar32 character) +{ + // FIXME: For non-BMP characters, GetFontUnicodeRanges is of + // no use. We have to read directly from the cmap table of a font. + // Return true for now. + if (character > 0xFFFF) + return true; + + // This cache is just leaked on shutdown. + static FontCmapCache* fontCmapCache = 0; + if (!fontCmapCache) + fontCmapCache = new FontCmapCache; + + HashMap<const wchar_t*, UnicodeSet*>::iterator it = fontCmapCache->find(family); + if (it != fontCmapCache->end()) + return it->second->contains(character); + + HFONT hfont = fontData->hfont(); + HDC hdc = GetDC(0); + HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont)); + int count = GetFontUnicodeRanges(hdc, 0); + if (count == 0 && ChromiumBridge::ensureFontLoaded(hfont)) + count = GetFontUnicodeRanges(hdc, 0); + if (count == 0) { + ASSERT_NOT_REACHED(); + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + return true; + } + + static Vector<char, 512> glyphsetBuffer; + glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); + GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data()); + // In addition, refering to the OS/2 table and converting the codepage list + // to the coverage map might be faster. + count = GetFontUnicodeRanges(hdc, glyphset); + ASSERT(count > 0); + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + + // FIXME: consider doing either of the following two: + // 1) port back ICU 4.0's faster look-up code for UnicodeSet + // 2) port Mozilla's CompressedCharMap or gfxSparseBitset + unsigned i = 0; + UnicodeSet* cmap = new UnicodeSet; + while (i < glyphset->cRanges) { + WCHAR start = glyphset->ranges[i].wcLow; + cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); + i++; + } + cmap->freeze(); + // We don't lowercase |family| because all of them are under our control + // and they're already lowercased. + fontCmapCache->set(family, cmap); + return cmap->contains(character); +} + +// Given the desired base font, this will create a SimpleFontData for a specific +// font that can be used to render the given range of characters. +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + // FIXME: Consider passing fontDescription.dominantScript() + // to GetFallbackFamily here. + FontDescription fontDescription = font.fontDescription(); + UChar32 c; + UScriptCode script; + const wchar_t* family = getFallbackFamily(characters, length, + fontDescription.genericFamily(), &c, &script); + FontPlatformData* data = 0; + if (family) + data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)), false); + + // Last resort font list : PanUnicode. CJK fonts have a pretty + // large repertoire. Eventually, we need to scan all the fonts + // on the system to have a Firefox-like coverage. + // Make sure that all of them are lowercased. + const static wchar_t* const cjkFonts[] = { + L"arial unicode ms", + L"ms pgothic", + L"simsun", + L"gulim", + L"pmingliu", + L"wenquanyi zen hei", // partial CJK Ext. A coverage but more + // widely known to Chinese users. + L"ar pl shanheisun uni", + L"ar pl zenkai uni", + L"han nom a", // Complete CJK Ext. A coverage + L"code2000", // Complete CJK Ext. A coverage + // CJK Ext. B fonts are not listed here because it's of no use + // with our current non-BMP character handling because we use + // Uniscribe for it and that code path does not go through here. + }; + + const static wchar_t* const commonFonts[] = { + L"tahoma", + L"arial unicode ms", + L"lucida sans unicode", + L"microsoft sans serif", + L"palatino linotype", + // Four fonts below (and code2000 at the end) are not from MS, but + // once installed, cover a very wide range of characters. + L"freeserif", + L"freesans", + L"gentium", + L"gentiumalt", + L"ms pgothic", + L"simsun", + L"gulim", + L"pmingliu", + L"code2000", + }; + + const wchar_t* const* panUniFonts = 0; + int numFonts = 0; + if (script == USCRIPT_HAN) { + panUniFonts = cjkFonts; + numFonts = ARRAYSIZE(cjkFonts); + } else { + panUniFonts = commonFonts; + numFonts = ARRAYSIZE(commonFonts); + } + // Font returned from GetFallbackFamily may not cover |characters| + // because it's based on script to font mapping. This problem is + // critical enough for non-Latin scripts (especially Han) to + // warrant an additional (real coverage) check with fontCotainsCharacter. + int i; + for (i = 0; (!data || !fontContainsCharacter(data, family, c)) && i < numFonts; ++i) { + family = panUniFonts[i]; + data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family))); + } + if (i < numFonts) // we found the font that covers this character ! + return getCachedFontData(data); + + return 0; + +} + +const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName) +{ + // Note that mapping to Courier is removed because + // because it's a bitmap font on Windows. + // Alias Courier -> Courier New + static AtomicString courier("Courier"), courierNew("Courier New"); + if (equalIgnoringCase(familyName, courier)) + return courierNew; + + // Alias Times <-> Times New Roman. + static AtomicString times("Times"), timesNewRoman("Times New Roman"); + if (equalIgnoringCase(familyName, times)) + return timesNewRoman; + if (equalIgnoringCase(familyName, timesNewRoman)) + return times; + + // Alias Helvetica <-> Arial + static AtomicString arial("Arial"), helvetica("Helvetica"); + if (equalIgnoringCase(familyName, helvetica)) + return arial; + if (equalIgnoringCase(familyName, arial)) + return helvetica; + + // We block bitmap fonts altogether so that we have to + // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font) + static AtomicString msSans("MS Sans Serif"); + static AtomicString microsoftSans("Microsoft Sans Serif"); + if (equalIgnoringCase(familyName, msSans)) + return microsoftSans; + + // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no + // 'Microsoft Sans Serif-equivalent' for Serif. + static AtomicString msSerif("MS Serif"); + if (equalIgnoringCase(familyName, msSerif)) + return timesNewRoman; + + // FIXME: should we map 'system' to something ('Tahoma') ? + return emptyAtom; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) +{ + FontDescription::GenericFamilyType generic = description.genericFamily(); + // FIXME: Mapping webkit generic to GenericFamilyType needs to + // be more intelligent. + // This spot rarely gets reached. GetFontDataForCharacters() gets hit a lot + // more often (see FIXME comment there). + const wchar_t* family = getFontFamilyForScript(description.dominantScript(), generic); + + if (family) + return getCachedFontPlatformData(description, AtomicString(family, wcslen(family))); + + // FIXME: Would be even better to somehow get the user's default font here. + // For now we'll pick the default that the user would get without changing + // any prefs. + static AtomicString timesStr("Times New Roman"); + static AtomicString courierStr("Courier New"); + static AtomicString arialStr("Arial"); + + AtomicString& fontStr = timesStr; + if (generic == FontDescription::SansSerifFamily) + fontStr = arialStr; + else if (generic == FontDescription::MonospaceFamily) + fontStr = courierStr; + + return getCachedFontPlatformData(description, fontStr); +} + +static LONG toGDIFontWeight(FontWeight fontWeight) +{ + static LONG gdiFontWeights[] = { + FW_THIN, // FontWeight100 + FW_EXTRALIGHT, // FontWeight200 + FW_LIGHT, // FontWeight300 + FW_NORMAL, // FontWeight400 + FW_MEDIUM, // FontWeight500 + FW_SEMIBOLD, // FontWeight600 + FW_BOLD, // FontWeight700 + FW_EXTRABOLD, // FontWeight800 + FW_HEAVY // FontWeight900 + }; + return gdiFontWeights[fontWeight]; +} + +// FIXME: This may not be the best place to put this function +AtomicString FontCache::getGenericFontForScript(UScriptCode script, const FontDescription& description) +{ + const wchar_t* scriptFont = getFontFamilyForScript( script, description.genericFamily()); + return scriptFont ? AtomicString(scriptFont, wcslen(scriptFont)) : emptyAtom; +} + +static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) +{ + // The size here looks unusual. The negative number is intentional. + // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be + // some kind of artifact of their CG backend, or something. + winfont->lfHeight = -fontDescription.computedPixelSize(); + winfont->lfWidth = 0; + winfont->lfEscapement = 0; + winfont->lfOrientation = 0; + winfont->lfUnderline = false; + winfont->lfStrikeOut = false; + winfont->lfCharSet = DEFAULT_CHARSET; + winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; + winfont->lfQuality = ChromiumBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings. + winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + winfont->lfItalic = fontDescription.italic(); + winfont->lfWeight = toGDIFontWeight(fontDescription.weight()); +} + +struct TraitsInFamilyProcData { + TraitsInFamilyProcData(const AtomicString& familyName) + : m_familyName(familyName) + { + } + + const AtomicString& m_familyName; + HashSet<unsigned> m_traitsMasks; +}; + +static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) +{ + TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); + + unsigned traitsMask = 0; + traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; + traitsMask |= FontVariantNormalMask; + LONG weight = logFont->lfWeight; + traitsMask |= weight == FW_THIN ? FontWeight100Mask : + weight == FW_EXTRALIGHT ? FontWeight200Mask : + weight == FW_LIGHT ? FontWeight300Mask : + weight == FW_NORMAL ? FontWeight400Mask : + weight == FW_MEDIUM ? FontWeight500Mask : + weight == FW_SEMIBOLD ? FontWeight600Mask : + weight == FW_BOLD ? FontWeight700Mask : + weight == FW_EXTRABOLD ? FontWeight800Mask : + FontWeight900Mask; + procData->m_traitsMasks.add(traitsMask); + return 1; +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +{ + HDC hdc = GetDC(0); + + LOGFONT logFont; + logFont.lfCharSet = DEFAULT_CHARSET; + unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1)); + memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); + logFont.lfFaceName[familyLength] = 0; + logFont.lfPitchAndFamily = 0; + + TraitsInFamilyProcData procData(familyName); + EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); + copyToVector(procData.m_traitsMasks, traitsMasks); + + ReleaseDC(0, hdc); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + LOGFONT winfont = {0}; + FillLogFont(fontDescription, &winfont); + + // Windows will always give us a valid pointer here, even if the face name + // is non-existent. We have to double-check and see if the family name was + // really used. + String winName; + HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName); + if (!hfont) + return 0; + + // FIXME: Do we need to use predefined fonts "guaranteed" to exist + // when we're running in layout-test mode? + if (!equalIgnoringCase(family, winName)) { + // For CJK fonts with both English and native names, + // GetTextFace returns a native name under the font's "locale" + // and an English name under other locales regardless of + // lfFaceName field of LOGFONT. As a result, we need to check + // if a font has an alternate name. If there is, we need to + // compare it with what's requested in the first place. + String altName; + if (!LookupAltName(family, altName) || + !equalIgnoringCase(altName, winName)) { + DeleteObject(hfont); + return 0; + } + } + + return new FontPlatformData(hfont, + fontDescription.computedPixelSize()); +} + +} diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp new file mode 100644 index 0000000..f187c55 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontCache.h" + +#include <fontconfig/fontconfig.h> + +#include "AtomicString.h" +#include "CString.h" +#include "Font.h" +#include "FontDescription.h" +#include "FontPlatformData.h" +#include "Logging.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" + +#include "SkPaint.h" +#include "SkTypeface.h" +#include "SkUtils.h" + +namespace WebCore { + +void FontCache::platformInit() +{ +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, + const UChar* characters, + int length) +{ + FcCharSet* cset = FcCharSetCreate(); + for (int i = 0; i < length; ++i) + FcCharSetAddChar(cset, characters[i]); + + FcPattern* pattern = FcPatternCreate(); + + FcValue fcvalue; + fcvalue.type = FcTypeCharSet; + fcvalue.u.c = cset; + FcPatternAdd(pattern, FC_CHARSET, fcvalue, 0); + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern* match = FcFontMatch(0, pattern, &result); + FcPatternDestroy(pattern); + + SimpleFontData* ret = 0; + + if (match) { + FcChar8* family; + if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) { + FontPlatformData* fpd = + createFontPlatformData(font.fontDescription(), AtomicString((char*) family)); + ret = new SimpleFontData(*fpd); + } + FcPatternDestroy(match); + } + + FcCharSetDestroy(cset); + + return ret; +} + +const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName) +{ + notImplemented(); + + // This is just to stop GCC emitting a warning about returning a reference + // to a temporary variable + static AtomicString a; + return a; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) +{ + static AtomicString arialStr("Arial"); + return getCachedFontPlatformData(description, arialStr); +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, + Vector<unsigned>& traitsMasks) +{ + notImplemented(); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, + const AtomicString& family) +{ + const char* name = 0; + CString s; + + if (family.length() == 0) { + static const struct { + FontDescription::GenericFamilyType mType; + const char* mName; + } fontDescriptions[] = { + { FontDescription::SerifFamily, "serif" }, + { FontDescription::SansSerifFamily, "sans-serif" }, + { FontDescription::MonospaceFamily, "monospace" }, + { FontDescription::CursiveFamily, "cursive" }, + { FontDescription::FantasyFamily, "fantasy" } + }; + + FontDescription::GenericFamilyType type = fontDescription.genericFamily(); + for (unsigned i = 0; i < SK_ARRAY_COUNT(fontDescriptions); i++) { + if (type == fontDescriptions[i].mType) { + name = fontDescriptions[i].mName; + break; + } + } + // if we fall out of the loop, it's ok for name to still be 0 + } + else { // convert the name to utf8 + s = family.string().utf8(); + name = s.data(); + } + + int style = SkTypeface::kNormal; + if (fontDescription.weight() >= FontWeightBold) + style |= SkTypeface::kBold; + if (fontDescription.italic()) + style |= SkTypeface::kItalic; + + SkTypeface* tf = SkTypeface::Create(name, static_cast<SkTypeface::Style>(style)); + if (!tf) + return 0; + + FontPlatformData* result = + new FontPlatformData(tf, + fontDescription.computedSize(), + (style & SkTypeface::kBold) && !tf->isBold(), + (style & SkTypeface::kItalic) && !tf->isItalic()); + tf->unref(); + return result; +} + +AtomicString FontCache::getGenericFontForScript(UScriptCode script, + const FontDescription& descript) +{ + notImplemented(); + return AtomicString(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp new file mode 100644 index 0000000..3cf18a6 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "TransformationMatrix.h" +#include "ChromiumBridge.h" +#include "FontFallbackList.h" +#include "GlyphBuffer.h" +#include "PlatformContextSkia.h" +#include "SimpleFontData.h" +#include "SkiaFontWin.h" +#include "SkiaUtils.h" +#include "UniscribeHelperTextRun.h" + +#include "skia/ext/platform_canvas_win.h" +#include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency. + +#include <windows.h> + +namespace WebCore { + +static bool windowsCanHandleTextDrawing(GraphicsContext* context) +{ + // Check for non-translation transforms. Sometimes zooms will look better in + // Skia, and sometimes better in Windows. The main problem is that zooming + // in using Skia will show you the hinted outlines for the smaller size, + // which look weird. All else being equal, it's better to use Windows' text + // drawing, so we don't check for zooms. + const TransformationMatrix& matrix = context->getCTM(); + if (matrix.b() != 0 || matrix.c() != 0) // Check for skew. + return false; + + // Check for stroke effects. + if (context->platformContext()->getTextDrawingMode() != cTextFill) + return false; + + // Check for shadow effects. + if (context->platformContext()->getDrawLooper()) + return false; + + return true; +} + +// Skia equivalents to Windows text drawing functions. They +// will get the outlines from Windows and draw then using Skia using the given +// parameters in the paint arguments. This allows more complex effects and +// transforms to be drawn than Windows allows. +// +// These functions will be significantly slower than Windows GDI, and the text +// will look different (no ClearType), so use only when necessary. +// +// When you call a Skia* text drawing function, various glyph outlines will be +// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont +// when the font is destroyed so that the cache does not outlive the font (since +// the HFONTs are recycled). + +// Analog of the Windows GDI function DrawText, except using the given SkPaint +// attributes for the text. See above for more. +// +// Returns true of the text was drawn successfully. False indicates an error +// from Windows. +static bool skiaDrawText(HFONT hfont, + SkCanvas* canvas, + const SkPoint& point, + SkPaint* paint, + const WORD* glyphs, + const int* advances, + int numGlyphs) +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont); + + canvas->save(); + canvas->translate(point.fX, point.fY); + + for (int i = 0; i < numGlyphs; i++) { + const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]); + if (!path) + return false; + canvas->drawPath(*path, *paint); + canvas->translate(advances[i], 0); + } + + canvas->restore(); + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return true; +} + +static bool paintSkiaText(PlatformContextSkia* platformContext, + HFONT hfont, + int numGlyphs, + const WORD* glyphs, + const int* advances, + const SkPoint& origin) +{ + int textMode = platformContext->getTextDrawingMode(); + + // Filling (if necessary). This is the common case. + SkPaint paint; + platformContext->setupPaintForFilling(&paint); + paint.setFlags(SkPaint::kAntiAlias_Flag); + bool didFill = false; + if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) { + if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs)) + return false; + didFill = true; + } + + // Stroking on top (if necessary). + if ((textMode & WebCore::cTextStroke) + && platformContext->getStrokeStyle() != NoStroke + && platformContext->getStrokeThickness() > 0) { + + paint.reset(); + platformContext->setupPaintForStroking(&paint, 0, 0); + paint.setFlags(SkPaint::kAntiAlias_Flag); + if (didFill) { + // If there is a shadow and we filled above, there will already be + // a shadow. We don't want to draw it again or it will be too dark + // and it will go on top of the fill. + // + // Note that this isn't strictly correct, since the stroke could be + // very thick and the shadow wouldn't account for this. The "right" + // thing would be to draw to a new layer and then draw that layer + // with a shadow. But this is a lot of extra work for something + // that isn't normally an issue. + paint.setLooper(0)->safeUnref(); + } + + if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs)) + return false; + } + return true; +} + +void Font::drawGlyphs(GraphicsContext* graphicsContext, + const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, + int from, + int numGlyphs, + const FloatPoint& point) const +{ + PlatformGraphicsContext* context = graphicsContext->platformContext(); + + // Max buffer length passed to the underlying windows API. + const int kMaxBufferLength = 1024; + // Default size for the buffer. It should be enough for most of cases. + const int kDefaultBufferLength = 256; + + SkColor color = context->fillColor(); + unsigned char alpha = SkColorGetA(color); + // Skip 100% transparent text; no need to draw anything. + if (!alpha && context->getStrokeStyle() == NoStroke) + return; + + // Set up our graphics context. + HDC hdc = context->canvas()->beginPlatformPaint(); + HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont()); + + // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency. + // Enforce non-transparent color. + color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); + SetTextColor(hdc, skia::SkColorToCOLORREF(color)); + SetBkMode(hdc, TRANSPARENT); + + // Windows needs the characters and the advances in nice contiguous + // buffers, which we build here. + Vector<WORD, kDefaultBufferLength> glyphs; + Vector<int, kDefaultBufferLength> advances; + + // Compute the coordinate. The 'origin' represents the baseline, so we need + // to move it up to the top of the bounding square. + int x = static_cast<int>(point.x()); + int lineTop = static_cast<int>(point.y()) - font->ascent(); + + bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext); + + // We draw the glyphs in chunks to avoid having to do a heap allocation for + // the arrays of characters and advances. Since ExtTextOut is the + // lowest-level text output function on Windows, there should be little + // penalty for splitting up the text. On the other hand, the buffer cannot + // be bigger than 4094 or the function will fail. + int glyphIndex = 0; + while (glyphIndex < numGlyphs) { + // how many chars will be in this chunk? + int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); + + glyphs.resize(curLen); + advances.resize(curLen); + + int curWidth = 0; + for (int i = 0; i < curLen; ++i, ++glyphIndex) { + glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); + advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex)); + curWidth += advances[i]; + } + + bool success = false; + for (int executions = 0; executions < 2; ++executions) { + if (canUseGDI) + success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), curLen, &advances[0]); + else { + // Skia's text draing origin is the baseline, like WebKit, not + // the top, like Windows. + SkPoint origin = { x, point.y() }; + success = paintSkiaText(context, font->platformData().hfont(), numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]), &advances[0], origin); + } + + if (!success && executions == 0) { + // Ask the browser to load the font for us and retry. + ChromiumBridge::ensureFontLoaded(font->platformData().hfont()); + continue; + } + break; + } + + ASSERT(success); + + x += curWidth; + } + + SelectObject(hdc, oldFont); + context->canvas()->endPlatformPaint(); +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, + const IntPoint& point, + int h, + int from, + int to) const +{ + UniscribeHelperTextRun state(run, *this); + float left = static_cast<float>(point.x() + state.characterToX(from)); + float right = static_cast<float>(point.x() + state.characterToX(to)); + + // If the text is RTL, left will actually be after right. + if (left < right) + return FloatRect(left, static_cast<float>(point.y()), + right - left, static_cast<float>(h)); + + return FloatRect(right, static_cast<float>(point.y()), + left - right, static_cast<float>(h)); +} + +void Font::drawComplexText(GraphicsContext* graphicsContext, + const TextRun& run, + const FloatPoint& point, + int from, + int to) const +{ + PlatformGraphicsContext* context = graphicsContext->platformContext(); + UniscribeHelperTextRun state(run, *this); + + SkColor color = context->fillColor(); + unsigned char alpha = SkColorGetA(color); + // Skip 100% transparent text; no need to draw anything. + if (!alpha) + return; + + HDC hdc = context->canvas()->beginPlatformPaint(); + + // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency. + // Enforce non-transparent color. + color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); + SetTextColor(hdc, skia::SkColorToCOLORREF(color)); + SetBkMode(hdc, TRANSPARENT); + + // Uniscribe counts the coordinates from the upper left, while WebKit uses + // the baseline, so we have to subtract off the ascent. + state.draw(hdc, static_cast<int>(point.x()), static_cast<int>(point.y() - ascent()), from, to); + context->canvas()->endPlatformPaint(); +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + UniscribeHelperTextRun state(run, *this); + return static_cast<float>(state.width()); +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int x, + bool includePartialGlyphs) const +{ + // Mac code ignores includePartialGlyphs, and they don't know what it's + // supposed to do, so we just ignore it as well. + UniscribeHelperTextRun state(run, *this); + int charIndex = state.xToCharacter(x); + + // XToCharacter will return -1 if the position is before the first + // character (we get called like this sometimes). + if (charIndex < 0) + charIndex = 0; + return charIndex; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp new file mode 100644 index 0000000..8f8df88 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#if PLATFORM(WIN_OS) +#include "Base64.h" +#include "ChromiumBridge.h" +#include "OpenTypeUtilities.h" +#endif + +#include "FontPlatformData.h" +#include "NotImplemented.h" +#include "SharedBuffer.h" + +#if PLATFORM(WIN_OS) +#include <objbase.h> +#include <t2embapi.h> +#pragma comment(lib, "t2embed") +#endif + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ +#if PLATFORM(WIN_OS) + if (m_fontReference) { + if (m_name.isNull()) { + ULONG status; + TTDeleteEmbeddedFont(m_fontReference, 0, &status); + } else + RemoveFontMemResourceEx(m_fontReference); + } +#endif +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode mode) +{ +#if PLATFORM(WIN_OS) + ASSERT(m_fontReference); + + LOGFONT logFont; + if (m_name.isNull()) + TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0); + else { + // m_name comes from createUniqueFontName, which, in turn, gets + // it from base64-encoded uuid (128-bit). So, m_name + // can never be longer than LF_FACESIZE (32). + if (m_name.length() + 1 >= LF_FACESIZE) { + ASSERT_NOT_REACHED(); + return FontPlatformData(); + } + memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), + sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); + } + + // FIXME: almost identical to FillLogFont in FontCacheWin.cpp. + // Need to refactor. + logFont.lfHeight = -size; + logFont.lfWidth = 0; + logFont.lfEscapement = 0; + logFont.lfOrientation = 0; + logFont.lfUnderline = false; + logFont.lfStrikeOut = false; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; + logFont.lfQuality = ChromiumBridge::layoutTestMode() ? + NONANTIALIASED_QUALITY : + DEFAULT_QUALITY; // Honor user's desktop settings. + logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + logFont.lfItalic = italic; + logFont.lfWeight = bold ? 700 : 400; + + HFONT hfont = CreateFontIndirect(&logFont); + return FontPlatformData(hfont, size); +#else + notImplemented(); + return FontPlatformData(); +#endif +} + +#if PLATFORM(WIN_OS) +// FIXME: EOTStream class and static functions in this #if block are +// duplicated from platform/graphics/win/FontCustomPlatformData.cpp +// and need to be shared. + +// Streams the concatenation of a header and font data. +class EOTStream { +public: + EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) + : m_eotHeader(eotHeader) + , m_fontData(fontData) + , m_overlayDst(overlayDst) + , m_overlaySrc(overlaySrc) + , m_overlayLength(overlayLength) + , m_offset(0) + , m_inHeader(true) + { + } + + size_t read(void* buffer, size_t count); + +private: + const Vector<UInt8, 512>& m_eotHeader; + const SharedBuffer* m_fontData; + size_t m_overlayDst; + size_t m_overlaySrc; + size_t m_overlayLength; + size_t m_offset; + bool m_inHeader; +}; + +size_t EOTStream::read(void* buffer, size_t count) +{ + size_t bytesToRead = count; + if (m_inHeader) { + size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count); + memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); + m_offset += bytesFromHeader; + bytesToRead -= bytesFromHeader; + if (m_offset == m_eotHeader.size()) { + m_inHeader = false; + m_offset = 0; + } + } + if (bytesToRead && !m_inHeader) { + size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead); + memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); + if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) { + size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0); + size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst); + size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset); + memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy); + } + m_offset += bytesFromData; + bytesToRead -= bytesFromData; + } + return count - bytesToRead; +} + +static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length) +{ + return static_cast<EOTStream*>(stream)->read(buffer, length); +} + +// Creates a unique and unpredictable font name, in order to avoid collisions and to +// not allow access from CSS. +static String createUniqueFontName() +{ + Vector<char> fontUuid(sizeof(GUID)); + CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data())); + + Vector<char> fontNameVector; + base64Encode(fontUuid, fontNameVector); + ASSERT(fontNameVector.size() < LF_FACESIZE); + return String(fontNameVector.data(), fontNameVector.size()); +} +#endif + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + +#if PLATFORM(WIN_OS) + // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's + // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the + // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name + // we avoid namespace collisions. + + String fontName = createUniqueFontName(); + + // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, + // so we need to create an EOT header and prepend it to the font data. + Vector<UInt8, 512> eotHeader; + size_t overlayDst; + size_t overlaySrc; + size_t overlayLength; + + if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) + return 0; + + HANDLE fontReference; + ULONG privStatus; + ULONG status; + EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength); + + LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0); + if (loadEmbeddedFontResult == E_NONE) + fontName = String(); + else { + fontReference = renameAndActivateFont(buffer, fontName); + if (!fontReference) + return 0; + } + + return new FontCustomPlatformData(fontReference, fontName); +#else + notImplemented();; + return 0; +#endif +} + +} diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h new file mode 100644 index 0000000..2f1a597 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include <wtf/Noncopyable.h> + +#if PLATFORM(WIN_OS) +#include "FontRenderingMode.h" +#include "PlatformString.h" +#include <windows.h> +#endif + +namespace WebCore { + +class FontPlatformData; +class SharedBuffer; + +struct FontCustomPlatformData : Noncopyable { +#if PLATFORM(WIN_OS) + FontCustomPlatformData(HANDLE fontReference, const String& name) + : m_fontReference(fontReference) + , m_name(name) + {} +#endif + + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic, + FontRenderingMode = NormalRenderingMode); + +#if PLATFORM(WIN_OS) + HANDLE m_fontReference; + String m_name; +#endif +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); +} + +#endif // FontCustomPlatformData_h diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp new file mode 100644 index 0000000..7a3e614 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2007, 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "FloatRect.h" +#include "GlyphBuffer.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PlatformContextSkia.h" +#include "SimpleFontData.h" + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkTemplates.h" +#include "SkTypeface.h" +#include "SkUtils.h" + +namespace WebCore { + +void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, int from, int numGlyphs, + const FloatPoint& point) const { + SkCanvas* canvas = gc->platformContext()->canvas(); + SkPaint paint; + + gc->platformContext()->setupPaintCommon(&paint); + font->platformData().setupPaint(&paint); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setColor(gc->fillColor().rgb()); + + SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert + + const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); + SkScalar x = SkFloatToScalar(point.x()); + SkScalar y = SkFloatToScalar(point.y()); + + // FIXME: text rendering speed: + // Android has code in their WebCore fork to special case when the + // GlyphBuffer has no advances other than the defaults. In that case the + // text drawing can proceed faster. However, it's unclear when those + // patches may be upstreamed to WebKit so we always use the slower path + // here. + const GlyphBufferAdvance* adv = glyphBuffer.advances(from); + SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); + SkPoint* pos = storage.get(); + + for (int i = 0; i < numGlyphs; i++) { + pos[i].set(x, y); + x += SkFloatToScalar(adv[i].width()); + y += SkFloatToScalar(adv[i].height()); + } + canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, + const FloatPoint& point, int from, int to) const +{ + notImplemented(); +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + notImplemented(); + return 0; +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int x, + bool includePartialGlyphs) const +{ + notImplemented(); + return 0; +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, + const IntPoint& point, int h, + int from, int to) const +{ + notImplemented(); + return FloatRect(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontPlatformData.h b/WebCore/platform/graphics/chromium/FontPlatformData.h new file mode 100644 index 0000000..c6f1912 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformData.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2007, 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontPlatformData_h +#define FontPlatformData_h + +#if PLATFORM(WIN_OS) +#include "FontPlatformDataChromiumWin.h" +#elif defined(__linux__) +#include "FontPlatformDataLinux.h" +#endif + +#endif // FontPlatformData_h diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp new file mode 100644 index 0000000..767fe76 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontPlatformData.h" + +#include <windows.h> +#include <objidl.h> +#include <mlang.h> + +#include "ChromiumBridge.h" +#include "SkiaFontWin.h" + +namespace WebCore { + +FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType) + : m_font(hashTableDeletedFontValue()) + , m_size(-1) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData::FontPlatformData() + : m_font(0) + , m_size(0) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData::FontPlatformData(HFONT font, float size) + : m_font(RefCountedHFONT::create(font)) + , m_size(size) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) + : m_font(0) + , m_size(size) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData::FontPlatformData(const FontPlatformData& data) + : m_font(data.m_font) + , m_size(data.m_size) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data) +{ + if (this != &data) { + m_font = data.m_font; + m_size = data.m_size; + + // The following fields will get re-computed if necessary. + ScriptFreeCache(&m_scriptCache); + m_scriptCache = 0; + + delete m_scriptFontProperties; + m_scriptFontProperties = 0; + } + return *this; +} + +FontPlatformData::~FontPlatformData() +{ + ScriptFreeCache(&m_scriptCache); + m_scriptCache = 0; + + delete m_scriptFontProperties; + m_scriptFontProperties = 0; +} + +FontPlatformData::RefCountedHFONT::~RefCountedHFONT() +{ + if (m_hfont != reinterpret_cast<HFONT>(-1)) { + SkiaWinOutlineCache::removePathsForFont(m_hfont); + DeleteObject(m_hfont); + } +} + +FontPlatformData::RefCountedHFONT* FontPlatformData::hashTableDeletedFontValue() +{ + static RefPtr<RefCountedHFONT> deletedValue = + RefCountedHFONT::create(reinterpret_cast<HFONT>(-1)); + return deletedValue.get(); +} + +SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const +{ + if (!m_scriptFontProperties) { + m_scriptFontProperties = new SCRIPT_FONTPROPERTIES; + memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES)); + m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES); + HRESULT result = ScriptGetFontProperties(0, scriptCache(), + m_scriptFontProperties); + if (result == E_PENDING) { + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont()); + HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), + m_scriptFontProperties); + if (S_OK != hr) { + if (ChromiumBridge::ensureFontLoaded(hfont())) { + // FIXME: Handle gracefully the error if this call also fails. + hr = ScriptGetFontProperties(dc, scriptCache(), + m_scriptFontProperties); + if (S_OK != hr) { + ASSERT_NOT_REACHED(); + } + } + } + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + } + } + return m_scriptFontProperties; +} + +} diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h new file mode 100644 index 0000000..ce15a93 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontPlatformDataWin_h +#define FontPlatformDataWin_h + +#include "config.h" + +#include "StringImpl.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#include <usp10.h> + +typedef struct HFONT__ *HFONT; + +namespace WebCore { + +class FontDescription; + +class FontPlatformData { +public: + // Used for deleted values in the font cache's hash tables. The hash table + // will create us with this structure, and it will compare other values + // to this "Deleted" one. It expects the Deleted one to be differentiable + // from the NULL one (created with the empty constructor), so we can't just + // set everything to NULL. + FontPlatformData(WTF::HashTableDeletedValueType); + FontPlatformData(); + FontPlatformData(HFONT, float size); + FontPlatformData(float size, bool bold, bool oblique); + FontPlatformData(const FontPlatformData&); + + FontPlatformData& operator=(const FontPlatformData&); + + bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); } + + ~FontPlatformData(); + + HFONT hfont() const { return m_font ? m_font->hfont() : 0; } + float size() const { return m_size; } + + unsigned hash() const + { + return m_font ? m_font->hash() : NULL; + } + + bool operator==(const FontPlatformData& other) const + { + return m_font == other.m_font && m_size == other.m_size; + } + + SCRIPT_FONTPROPERTIES* scriptFontProperties() const; + SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; } + +private: + // We refcount the internal HFONT so that FontPlatformData can be + // efficiently copied. WebKit depends on being able to copy it, and we + // don't really want to re-create the HFONT. + class RefCountedHFONT : public RefCounted<RefCountedHFONT> { + public: + static PassRefPtr<RefCountedHFONT> create(HFONT hfont) + { + return adoptRef(new RefCountedHFONT(hfont)); + } + + ~RefCountedHFONT(); + + HFONT hfont() const { return m_hfont; } + unsigned hash() const + { + return StringImpl::computeHash(reinterpret_cast<const UChar*>(&m_hfont), sizeof(HFONT) / sizeof(UChar)); + } + + bool operator==(const RefCountedHFONT& other) const + { + return m_hfont == other.m_hfont; + } + + private: + // The create() function assumes there is already a refcount of one + // so it can do adoptRef. + RefCountedHFONT(HFONT hfont) : m_hfont(hfont) + { + } + + HFONT m_hfont; + }; + + static RefCountedHFONT* hashTableDeletedFontValue(); + + RefPtr<RefCountedHFONT> m_font; + float m_size; // Point size of the font in pixels. + + mutable SCRIPT_CACHE m_scriptCache; + mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties; +}; + +} // WebCore + +#endif // FontPlatformDataWin_h diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp new file mode 100644 index 0000000..86f96ee --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontPlatformData.h" + +#include "StringImpl.h" +#include "NotImplemented.h" + +#include "SkPaint.h" +#include "SkTypeface.h" + +namespace WebCore { + +FontPlatformData::FontPlatformData(const FontPlatformData& src) + : m_typeface(src.m_typeface) + , m_textSize(src.m_textSize) + , m_fakeBold(src.m_fakeBold) + , m_fakeItalic(src.m_fakeItalic) +{ + m_typeface->safeRef(); +} + +FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic) + : m_typeface(tf) + , m_textSize(textSize) + , m_fakeBold(fakeBold) + , m_fakeItalic(fakeItalic) +{ + m_typeface->safeRef(); +} + +FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) + : m_typeface(src.m_typeface) + , m_textSize(textSize) + , m_fakeBold(src.m_fakeBold) + , m_fakeItalic(src.m_fakeItalic) +{ + m_typeface->safeRef(); +} + +FontPlatformData::~FontPlatformData() +{ + m_typeface->safeUnref(); +} + +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) +{ + SkRefCnt_SafeAssign(m_typeface, src.m_typeface); + + m_textSize = src.m_textSize; + m_fakeBold = src.m_fakeBold; + m_fakeItalic = src.m_fakeItalic; + + return *this; +} + +void FontPlatformData::setupPaint(SkPaint* paint) const +{ + const float ts = m_textSize > 0 ? m_textSize : 12; + + paint->setAntiAlias(false); + paint->setSubpixelText(false); + paint->setTextSize(SkFloatToScalar(ts)); + paint->setTypeface(m_typeface); + paint->setFakeBoldText(m_fakeBold); + paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0); + paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); +} + +bool FontPlatformData::operator==(const FontPlatformData& a) const +{ + // If either of the typeface pointers are invalid (either NULL or the + // special deleted value) then we test for pointer equality. Otherwise, we + // call SkTypeface::Equal on the valid pointers. + bool typefacesEqual; + if (m_typeface == hashTableDeletedFontValue() + || a.m_typeface == hashTableDeletedFontValue() + || !m_typeface + || !a.m_typeface) + typefacesEqual = m_typeface == a.m_typeface; + else + typefacesEqual = SkTypeface::Equal(m_typeface, a.m_typeface); + + return typefacesEqual + && m_textSize == a.m_textSize + && m_fakeBold == a.m_fakeBold + && m_fakeItalic == a.m_fakeItalic; +} + +unsigned FontPlatformData::hash() const +{ + unsigned h = SkTypeface::UniqueID(m_typeface); + h ^= 0x01010101 * ((static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic)); + + // This memcpy is to avoid a reinterpret_cast that breaks strict-aliasing + // rules. Memcpy is generally optimized enough so that performance doesn't + // matter here. + uint32_t textSizeBytes; + memcpy(&textSizeBytes, &m_textSize, sizeof(uint32_t)); + h ^= textSizeBytes; + + return h; +} + +bool FontPlatformData::isFixedPitch() const +{ + notImplemented(); + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h new file mode 100644 index 0000000..ec7d837 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontPlatformDataLinux_h +#define FontPlatformDataLinux_h + +#include "StringImpl.h" +#include <wtf/RefPtr.h> + +class SkPaint; +class SkTypeface; + +namespace WebCore { + +class FontDescription; + +// ----------------------------------------------------------------------------- +// FontPlatformData is the handle which WebKit has on a specific face. A face +// is the tuple of (font, size, ...etc). Here we are just wrapping a Skia +// SkTypeface pointer and dealing with the reference counting etc. +// ----------------------------------------------------------------------------- +class FontPlatformData { +public: + // Used for deleted values in the font cache's hash tables. The hash table + // will create us with this structure, and it will compare other values + // to this "Deleted" one. It expects the Deleted one to be differentiable + // from the NULL one (created with the empty constructor), so we can't just + // set everything to NULL. + FontPlatformData(WTF::HashTableDeletedValueType) + : m_typeface(hashTableDeletedFontValue()) + , m_textSize(0) + , m_fakeBold(false) + , m_fakeItalic(false) + { } + + FontPlatformData() + : m_typeface(0) + , m_textSize(0) + , m_fakeBold(false) + , m_fakeItalic(false) + { } + + FontPlatformData(float textSize, bool fakeBold, bool fakeItalic) + : m_typeface(0) + , m_textSize(textSize) + , m_fakeBold(fakeBold) + , m_fakeItalic(fakeItalic) + { } + + FontPlatformData(const FontPlatformData&); + FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic); + FontPlatformData(const FontPlatformData& src, float textSize); + ~FontPlatformData(); + + // ------------------------------------------------------------------------- + // Return true iff this font is monospaced (i.e. every glyph has an equal x + // advance) + // ------------------------------------------------------------------------- + bool isFixedPitch() const; + + // ------------------------------------------------------------------------- + // Setup a Skia painting context to use this font. + // ------------------------------------------------------------------------- + void setupPaint(SkPaint*) const; + + unsigned hash() const; + float size() const { return m_textSize; } + + bool operator==(const FontPlatformData&) const; + FontPlatformData& operator=(const FontPlatformData&); + bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); } + +private: + // FIXME: Could SkAutoUnref be used here? + SkTypeface* m_typeface; + float m_textSize; + bool m_fakeBold; + bool m_fakeItalic; + + SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); } +}; + +} // namespace WebCore + +#endif // ifdef FontPlatformData_h diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp new file mode 100644 index 0000000..ed326c8 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontUtilsChromiumWin.h" + +#include <limits> + +#include "PlatformString.h" +#include "StringHash.h" +#include "UniscribeHelper.h" +#include <unicode/locid.h> +#include <unicode/uchar.h> +#include <wtf/HashMap.h> + +namespace WebCore { + +namespace { + +// A simple mapping from UScriptCode to family name. This is a sparse array, +// which works well since the range of UScriptCode values is small. +typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT]; + +void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) +{ + struct FontMap { + UScriptCode script; + const UChar* family; + }; + + const static FontMap fontMap[] = { + {USCRIPT_LATIN, L"times new roman"}, + {USCRIPT_GREEK, L"times new roman"}, + {USCRIPT_CYRILLIC, L"times new roman"}, + {USCRIPT_SIMPLIFIED_HAN, L"simsun"}, + {USCRIPT_HIRAGANA, L"ms pgothic"}, + {USCRIPT_KATAKANA, L"ms pgothic"}, + {USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"}, + {USCRIPT_HANGUL, L"gulim"}, + {USCRIPT_THAI, L"tahoma"}, + {USCRIPT_HEBREW, L"david"}, + {USCRIPT_ARABIC, L"tahoma"}, + {USCRIPT_DEVANAGARI, L"mangal"}, + {USCRIPT_BENGALI, L"vrinda"}, + {USCRIPT_GURMUKHI, L"raavi"}, + {USCRIPT_GUJARATI, L"shruti"}, + {USCRIPT_ORIYA, L"kalinga"}, + {USCRIPT_TAMIL, L"latha"}, + {USCRIPT_TELUGU, L"gautami"}, + {USCRIPT_KANNADA, L"tunga"}, + {USCRIPT_MALAYALAM, L"kartika"}, + {USCRIPT_LAO, L"dokchampa"}, + {USCRIPT_TIBETAN, L"microsoft himalaya"}, + {USCRIPT_GEORGIAN, L"sylfaen"}, + {USCRIPT_ARMENIAN, L"sylfaen"}, + {USCRIPT_ETHIOPIC, L"nyala"}, + {USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"}, + {USCRIPT_CHEROKEE, L"plantagenet cherokee"}, + {USCRIPT_YI, L"microsoft yi balti"}, + {USCRIPT_SINHALA, L"iskoola pota"}, + {USCRIPT_SYRIAC, L"estrangelo edessa"}, + {USCRIPT_KHMER, L"daunpenh"}, + {USCRIPT_THAANA, L"mv boli"}, + {USCRIPT_MONGOLIAN, L"mongolian balti"}, + {USCRIPT_MYANMAR, L"padauk"}, + // For USCRIPT_COMMON, we map blocks to scripts when + // that makes sense. + }; + + for (int i = 0; i < sizeof(fontMap) / sizeof(fontMap[0]); ++i) + scriptFontMap[fontMap[i].script] = fontMap[i].family; + + // Initialize the locale-dependent mapping. + // Since Chrome synchronizes the ICU default locale with its UI locale, + // this ICU locale tells the current UI locale of Chrome. + Locale locale = Locale::getDefault(); + const UChar* localeFamily = 0; + if (locale == Locale::getJapanese()) + localeFamily = scriptFontMap[USCRIPT_HIRAGANA]; + else if (locale == Locale::getKorean()) + localeFamily = scriptFontMap[USCRIPT_HANGUL]; + else { + // Use Simplified Chinese font for all other locales including + // Traditional Chinese because Simsun (SC font) has a wider + // coverage (covering both SC and TC) than PMingLiu (TC font). + // Note that |fontMap| does not have a separate entry for + // USCRIPT_TRADITIONAL_HAN for that reason. + // This also speeds up the TC version of Chrome when rendering SC + // pages. + localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN]; + } + if (localeFamily) + scriptFontMap[USCRIPT_HAN] = localeFamily; +} + +const int kUndefinedAscent = std::numeric_limits<int>::min(); + +// Given an HFONT, return the ascent. If GetTextMetrics fails, +// kUndefinedAscent is returned, instead. +int getAscent(HFONT hfont) +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont); + TEXTMETRIC tm; + BOOL gotMetrics = GetTextMetrics(dc, &tm); + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return gotMetrics ? tm.tmAscent : kUndefinedAscent; +} + +struct FontData { + FontData() + : hfont(0) + , ascent(kUndefinedAscent) + , scriptCache(0) + { + } + + HFONT hfont; + int ascent; + mutable SCRIPT_CACHE scriptCache; +}; + +// Again, using hash_map does not earn us much here. page_cycler_test intl2 +// gave us a 'better' result with map than with hash_map even though they're +// well-within 1-sigma of each other so that the difference is not significant. +// On the other hand, some pages in intl2 seem to take longer to load with map +// in the 1st pass. Need to experiment further. +typedef HashMap<String, FontData> FontDataCache; + +} // namespace + +// FIXME: this is font fallback code version 0.1 +// - Cover all the scripts +// - Get the default font for each script/generic family from the +// preference instead of hardcoding in the source. +// (at least, read values from the registry for IE font settings). +// - Support generic families (from FontDescription) +// - If the default font for a script is not available, +// try some more fonts known to support it. Finally, we can +// use EnumFontFamilies or similar APIs to come up with a list of +// fonts supporting the script and cache the result. +// - Consider using UnicodeSet (or UnicodeMap) converted from +// GLYPHSET (BMP) or directly read from truetype cmap tables to +// keep track of which character is supported by which font +// - Update script_font_cache in response to WM_FONTCHANGE + +const UChar* getFontFamilyForScript(UScriptCode script, + FontDescription::GenericFamilyType generic) +{ + static ScriptToFontMap scriptFontMap; + static bool initialized = false; + if (!initialized) { + initializeScriptFontMap(scriptFontMap); + initialized = true; + } + if (script == USCRIPT_INVALID_CODE) + return 0; + ASSERT(script < USCRIPT_CODE_LIMIT); + return scriptFontMap[script]; +} + +// FIXME: +// - Handle 'Inherited', 'Common' and 'Unknown' +// (see http://www.unicode.org/reports/tr24/#Usage_Model ) +// For 'Inherited' and 'Common', perhaps we need to +// accept another parameter indicating the previous family +// and just return it. +// - All the characters (or characters up to the point a single +// font can cover) need to be taken into account +const UChar* getFallbackFamily(const UChar* characters, + int length, + FontDescription::GenericFamilyType generic, + UChar32* charChecked, + UScriptCode* scriptChecked) +{ + ASSERT(characters && characters[0] && length > 0); + UScriptCode script = USCRIPT_COMMON; + + // Sometimes characters common to script (e.g. space) is at + // the beginning of a string so that we need to skip them + // to get a font required to render the string. + int i = 0; + UChar32 ucs4 = 0; + while (i < length && script == USCRIPT_COMMON || script == USCRIPT_INVALID_CODE) { + U16_NEXT(characters, i, length, ucs4); + UErrorCode err = U_ZERO_ERROR; + script = uscript_getScript(ucs4, &err); + // silently ignore the error + } + + // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for + // Han (determined in a locale-dependent way above). Full-width ASCII + // characters are rather widely used in Japanese and Chinese documents and + // they're fully covered by Chinese, Japanese and Korean fonts. + if (0xFF00 < ucs4 && ucs4 < 0xFF5F) + script = USCRIPT_HAN; + + // There are a lot of characters in USCRIPT_COMMON that can be covered + // by fonts for scripts closely related to them. See + // http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:] + // FIXME: make this more efficient with a wider coverage + if (script == USCRIPT_COMMON || script == USCRIPT_INHERITED) { + UBlockCode block = ublock_getCode(ucs4); + switch (block) { + case UBLOCK_BASIC_LATIN: + script = USCRIPT_LATIN; + break; + case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: + script = USCRIPT_HAN; + break; + case UBLOCK_HIRAGANA: + case UBLOCK_KATAKANA: + script = USCRIPT_HIRAGANA; + break; + case UBLOCK_ARABIC: + script = USCRIPT_ARABIC; + break; + case UBLOCK_GREEK: + script = USCRIPT_GREEK; + break; + case UBLOCK_DEVANAGARI: + // For Danda and Double Danda (U+0964, U+0965), use a Devanagari + // font for now although they're used by other scripts as well. + // Without a context, we can't do any better. + script = USCRIPT_DEVANAGARI; + break; + case UBLOCK_ARMENIAN: + script = USCRIPT_ARMENIAN; + break; + case UBLOCK_GEORGIAN: + script = USCRIPT_GEORGIAN; + break; + case UBLOCK_KANNADA: + script = USCRIPT_KANNADA; + break; + } + } + + // Another lame work-around to cover non-BMP characters. + const UChar* family = getFontFamilyForScript(script, generic); + if (!family) { + int plane = ucs4 >> 16; + switch (plane) { + case 1: + family = L"code2001"; + break; + case 2: + family = L"simsun-extb"; + break; + default: + family = L"lucida sans unicode"; + } + } + + if (charChecked) + *charChecked = ucs4; + if (scriptChecked) + *scriptChecked = script; + return family; +} + +// Be aware that this is not thread-safe. +bool getDerivedFontData(const UChar* family, + int style, + LOGFONT* logfont, + int* ascent, + HFONT* hfont, + SCRIPT_CACHE** scriptCache) +{ + ASSERT(logfont); + ASSERT(family); + ASSERT(*family); + + // It does not matter that we leak font data when we exit. + static FontDataCache fontDataCache; + + // FIXME: This comes up pretty high in the profile so that + // we need to measure whether using SHA256 (after coercing all the + // fields to char*) is faster than String::format. + String fontKey = String::format("%1d:%d:%ls", style, logfont->lfHeight, family); + FontDataCache::iterator iter = fontDataCache.find(fontKey); + FontData* derived; + if (iter == fontDataCache.end()) { + ASSERT(wcslen(family) < LF_FACESIZE); + wcscpy_s(logfont->lfFaceName, LF_FACESIZE, family); + // FIXME: CreateFontIndirect always comes up with + // a font even if there's no font matching the name. Need to + // check it against what we actually want (as is done in + // FontCacheWin.cpp) + pair<FontDataCache::iterator, bool> entry = fontDataCache.add(fontKey, FontData()); + derived = &entry.first->second; + derived->hfont = CreateFontIndirect(logfont); + // GetAscent may return kUndefinedAscent, but we still want to + // cache it so that we won't have to call CreateFontIndirect once + // more for HFONT next time. + derived->ascent = getAscent(derived->hfont); + } else { + derived = &iter->second; + // Last time, GetAscent failed so that only HFONT was + // cached. Try once more assuming that TryPreloadFont + // was called by a caller between calls. + if (kUndefinedAscent == derived->ascent) + derived->ascent = getAscent(derived->hfont); + } + *hfont = derived->hfont; + *ascent = derived->ascent; + *scriptCache = &(derived->scriptCache); + return *ascent != kUndefinedAscent; +} + +int getStyleFromLogfont(const LOGFONT* logfont) +{ + // FIXME: consider defining UNDEFINED or INVALID for style and + // returning it when logfont is 0 + if (!logfont) { + ASSERT_NOT_REACHED(); + return FontStyleNormal; + } + return (logfont->lfItalic ? FontStyleItalic : FontStyleNormal) | + (logfont->lfUnderline ? FontStyleUnderlined : FontStyleNormal) | + (logfont->lfWeight >= 700 ? FontStyleBold : FontStyleNormal); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h new file mode 100644 index 0000000..6a964c4 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// A collection of utilities for font handling. + +// FIXME: Move all methods to the files that have their callsites and remove this file. +// *Utils files are not very WebKit-ty. + +#ifndef FontUtilsWin_h +#define FontUtilsWin_h + +#include <usp10.h> +#include <wchar.h> +#include <windows.h> + +#include "FontDescription.h" +#include <unicode/uscript.h> + +namespace WebCore { + +// Return a font family that supports a script and belongs to |generic| font +// family. It can return NULL and a caller has to implement its own fallback. +const UChar* getFontFamilyForScript(UScriptCode, FontDescription::GenericFamilyType); + +// Return a font family that can render |characters| based on +// what script characters belong to. When char_checked is non-NULL, +// it's filled with the character used to determine the script. +// When script_checked is non-NULL, the script used to determine +// the family is returned. +// FIXME: This function needs a total overhaul. +const UChar* getFallbackFamily(const UChar* characters, int length, + FontDescription::GenericFamilyType, + UChar32* charChecked, + UScriptCode* scriptChecked); + +// Derive a new HFONT by replacing lfFaceName of LOGFONT with |family|, +// calculate the ascent for the derived HFONT, and initialize SCRIPT_CACHE +// in FontData. +// |style| is only used for cache key generation. |style| is +// bit-wise OR of BOLD(1), UNDERLINED(2) and ITALIC(4) and +// should match what's contained in LOGFONT. It should be calculated +// by calling GetStyleFromLogFont. +// Returns false if the font is not accessible, in which case |ascent| field +// of |fontdata| is set to kUndefinedAscent. +// Be aware that this is not thread-safe. +// FIXME: Instead of having three out params, we'd better have one +// (|*FontData|), but somehow it mysteriously messes up the layout for +// certain complex script pages (e.g. hi.wikipedia.org) and also crashes +// at the start-up if recently visited page list includes pages with complex +// scripts in their title. Moreover, somehow the very first-pass of +// intl2 page-cycler test is noticeably slower with one out param than +// the current version although the subsequent 9 passes take about the +// same time. +bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**); + +enum { + FontStyleNormal = 0, + FontStyleBold = 1, + FontStyleItalic = 2, + FontStyleUnderlined = 4 +}; + +// Derive style (bit-wise OR of FONT_STYLE_BOLD, FONT_STYLE_UNDERLINED, and +// FONT_STYLE_ITALIC) from LOGFONT. Returns 0 if |*logfont| is NULL. +int getStyleFromLogfont(const LOGFONT*); + +} // namespace WebCore + +#endif // FontUtilsWin_h diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp new file mode 100644 index 0000000..4c5cf7b --- /dev/null +++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include <windows.h> +#include <vector> + +#include "ChromiumBridge.h" +#include "Font.h" +#include "GlyphPageTreeNode.h" +#include "SimpleFontData.h" +#include "UniscribeHelperTextRun.h" +#include "WindowsVersion.h" + +namespace WebCore { + +// Fills one page of font data pointers with 0 to indicate that there +// are no glyphs for the characters. +static void fillEmptyGlyphs(GlyphPage* page) +{ + for (int i = 0; i < GlyphPage::size; ++i) + page->setGlyphDataForIndex(i, 0, 0); +} + +// Lazily initializes space glyph +static Glyph initSpaceGlyph(HDC dc, Glyph* spaceGlyph) +{ + if (*spaceGlyph) + return *spaceGlyph; + + static wchar_t space = ' '; + GetGlyphIndices(dc, &space, 1, spaceGlyph, 0); + return *spaceGlyph; +} + +// Fills |length| glyphs starting at |offset| in a |page| in the Basic +// Multilingual Plane (<= U+FFFF). The input buffer size should be the +// same as |length|. We can use the standard Windows GDI functions here. +// Returns true if any glyphs were found. +static bool fillBMPGlyphs(unsigned offset, + unsigned length, + UChar* buffer, + GlyphPage* page, + const SimpleFontData* fontData, + bool recurse) +{ + HDC dc = GetDC((HWND)0); + HGDIOBJ oldFont = SelectObject(dc, fontData->m_font.hfont()); + + TEXTMETRIC tm = {0}; + if (!GetTextMetrics(dc, &tm)) { + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + + if (recurse) { + if (ChromiumBridge::ensureFontLoaded(fontData->m_font.hfont())) + return fillBMPGlyphs(offset, length, buffer, page, fontData, false); + else { + fillEmptyGlyphs(page); + return false; + } + } else { + // FIXME: This should never happen. We want to crash the + // process and receive a crash dump. We should revisit this code later. + // See http://crbug.com/6401 + ASSERT_NOT_REACHED(); + fillEmptyGlyphs(page); + return false; + } + } + + // FIXME: GetGlyphIndices() sets each item of localGlyphBuffer[] + // with the one of the values listed below. + // * With the GGI_MARK_NONEXISTING_GLYPHS flag + // + If the font has a glyph available for the character, + // localGlyphBuffer[i] > 0x0. + // + If the font does not have glyphs available for the character, + // localGlyphBuffer[i] = 0x1F (TrueType Collection?) or + // 0xFFFF (OpenType?). + // * Without the GGI_MARK_NONEXISTING_GLYPHS flag + // + If the font has a glyph available for the character, + // localGlyphBuffer[i] > 0x0. + // + If the font does not have glyphs available for the character, + // localGlyphBuffer[i] = 0x80. + // (Windows automatically assigns the glyph for a box character to + // prevent ExtTextOut() from returning errors.) + // To avoid from hurting the rendering performance, this code just + // tells WebKit whether or not the all glyph indices for the given + // characters are 0x80 (i.e. a possibly-invalid glyph) and let it + // use alternative fonts for the characters. + // Although this may cause a problem, it seems to work fine as far as I + // have tested. (Obviously, I need more tests.) + WORD localGlyphBuffer[GlyphPage::size]; + + // FIXME: I find some Chinese characters can not be correctly displayed + // when call GetGlyphIndices without flag GGI_MARK_NONEXISTING_GLYPHS, + // because the corresponding glyph index is set as 0x20 when current font + // does not have glyphs available for the character. According a blog post + // http://blogs.msdn.com/michkap/archive/2006/06/28/649791.aspx + // I think we should switch to the way about calling GetGlyphIndices with + // flag GGI_MARK_NONEXISTING_GLYPHS, it should be OK according the + // description of MSDN. + // Also according to Jungshik and Hironori's suggestion and modification + // we treat turetype and raster Font as different way when windows version + // is less than Vista. + GetGlyphIndices(dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS); + + // Copy the output to the GlyphPage + bool haveGlyphs = false; + int invalidGlyph = 0xFFFF; + if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE)) + invalidGlyph = 0x1F; + + Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled. + + for (unsigned i = 0; i < length; i++) { + UChar c = buffer[i]; + Glyph glyph = localGlyphBuffer[i]; + const SimpleFontData* glyphFontData = fontData; + // When this character should be a space, we ignore whatever the font + // says and use a space. Otherwise, if fonts don't map one of these + // space or zero width glyphs, we will get a box. + if (Font::treatAsSpace(c)) + // Hard code the glyph indices for characters that should be + // treated like spaces. + glyph = initSpaceGlyph(dc, &spaceGlyph); + else if (Font::treatAsZeroWidthSpace(c) || c == 0x200B) { + // FIXME: change Font::treatAsZeroWidthSpace to use + // u_hasBinaryProperty, per jungshik's comment here: + // https://bugs.webkit.org/show_bug.cgi?id=20237#c6. + // Then the additional OR above won't be necessary. + glyph = initSpaceGlyph(dc, &spaceGlyph); + glyphFontData = fontData->zeroWidthFontData(); + } else if (glyph == invalidGlyph) { + // WebKit expects both the glyph index and FontData + // pointer to be 0 if the glyph is not present + glyph = 0; + glyphFontData = 0; + } else { + if (SimpleFontData::isCJKCodePoint(c)) + glyphFontData = fontData->cjkWidthFontData(); + haveGlyphs = true; + } + page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData); + } + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return haveGlyphs; +} + +// For non-BMP characters, each is two words (UTF-16) and the input buffer +// size is 2 * |length|. Since GDI doesn't know how to handle non-BMP +// characters, we must use Uniscribe to tell us the glyph indices. +// +// We don't want to call this in the case of "regular" characters since some +// fonts may not have the correct combining rules for accents. See the notes +// at the bottom of ScriptGetCMap. We can't use ScriptGetCMap, though, since +// it doesn't seem to support UTF-16, despite what this blog post says: +// http://blogs.msdn.com/michkap/archive/2006/06/29/650680.aspx +// +// So we fire up the full Uniscribe doohicky, give it our string, and it will +// correctly handle the UTF-16 for us. The hard part is taking this and getting +// the glyph indices back out that correspond to the correct input characters, +// since they may be missing. +// +// Returns true if any glyphs were found. +static bool fillNonBMPGlyphs(unsigned offset, + unsigned length, + UChar* buffer, + GlyphPage* page, + const SimpleFontData* fontData) +{ + bool haveGlyphs = false; + + UniscribeHelperTextRun state(buffer, length * 2, false, + fontData->m_font.hfont(), + fontData->m_font.scriptCache(), + fontData->m_font.scriptFontProperties()); + state.setInhibitLigate(true); + state.init(); + + for (unsigned i = 0; i < length; i++) { + // Each character in this input buffer is a surrogate pair, which + // consists of two UChars. So, the offset for its i-th character is + // (i * 2). + WORD glyph = state.firstGlyphForCharacter(i * 2); + if (glyph) { + haveGlyphs = true; + page->setGlyphDataForIndex(offset + i, glyph, fontData); + } else + // Clear both glyph and fontData fields. + page->setGlyphDataForIndex(offset + i, 0, 0); + } + return haveGlyphs; +} + +// We're supposed to return true if there are any glyphs in the range +// specified by |offset| and |length| in our font, +// false if there are none. +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer, + unsigned bufferLength, const SimpleFontData* fontData) +{ + // We have to handle BMP and non-BMP characters differently. + // FIXME: Add assertions to make sure that buffer is entirely in BMP + // or entirely in non-BMP. + if (bufferLength == length) + return fillBMPGlyphs(offset, length, characterBuffer, this, fontData, true); + + if (bufferLength == 2 * length) { + // A non-BMP input buffer will be twice as long as output glyph buffer + // because each character in the non-BMP input buffer will be + // represented by a surrogate pair (two UChar's). + return fillNonBMPGlyphs(offset, length, characterBuffer, this, fontData); + } + + ASSERT_NOT_REACHED(); + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp new file mode 100644 index 0000000..6024d43 --- /dev/null +++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphPageTreeNode.h" + +#include "Font.h" +#include "SimpleFontData.h" + +#include "SkTemplates.h" +#include "SkPaint.h" +#include "SkUtils.h" + +namespace WebCore { + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { + SkDebugf("%s last char is high-surrogate", __FUNCTION__); + return false; + } + + SkPaint paint; + fontData->platformData().setupPaint(&paint); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length); + uint16_t* glyphs = glyphStorage.get(); + // textToGlyphs takes a byte count, not a glyph count so we multiply by two. + unsigned count = paint.textToGlyphs(buffer, bufferLength * 2, glyphs); + if (count != length) { + SkDebugf("%s count != length\n", __FUNCTION__); + return false; + } + + unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero + for (unsigned i = 0; i < length; i++) { + setGlyphDataForIndex(offset + i, glyphs[i], glyphs[i] ? fontData : NULL); + allGlyphs |= glyphs[i]; + } + + return allGlyphs != 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp new file mode 100644 index 0000000..a5a6e1f --- /dev/null +++ b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Icon.h" + +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PlatformString.h" + +namespace WebCore { + +Icon::Icon(const PlatformIcon& icon) + : m_icon(icon) +{ +} + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::createIconForFile(const String&) +{ + notImplemented(); + return 0; +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) +{ + notImplemented(); + return 0; +} + +void Icon::paint(GraphicsContext*, const IntRect&) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp new file mode 100644 index 0000000..93e36ba --- /dev/null +++ b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Icon.h" + +#include "PassRefPtr.h" + +// FIXME: These are temporary stubs, we need real implementations which +// may come in the form of IconChromium.cpp. The Windows Chromium +// implementation is currently in IconWin.cpp. + +namespace WebCore { + +PassRefPtr<Icon> Icon::createIconForFile(const String&) +{ + return 0; +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) +{ + return 0; +} + +Icon::~Icon() +{ +} + +void Icon::paint(GraphicsContext*, const IntRect&) +{ +} + +} diff --git a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp new file mode 100644 index 0000000..b419e6f --- /dev/null +++ b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Icon.h" + +#include <windows.h> +#include <shellapi.h> + +#include "GraphicsContext.h" +#include "PlatformContextSkia.h" +#include "PlatformString.h" +#include "SkiaUtils.h" + +namespace WebCore { + +Icon::Icon(const PlatformIcon& icon) + : m_icon(icon) +{ +} + +Icon::~Icon() +{ + if (m_icon) + DestroyIcon(m_icon); +} + +PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +{ + SHFILEINFO sfi; + memset(&sfi, 0, sizeof(sfi)); + + String tmpFilename = filename; + if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + return 0; + + return adoptRef(new Icon(sfi.hIcon)); +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + // FIXME: support multiple files. + // http://code.google.com/p/chromium/issues/detail?id=4092 + if (!filenames.size()) + return 0; + + return createIconForFile(filenames[0]); +} + +void Icon::paint(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + HDC hdc = context->platformContext()->canvas()->beginPlatformPaint(); + DrawIconEx(hdc, rect.x(), rect.y(), m_icon, rect.width(), rect.height(), 0, 0, DI_NORMAL); + context->platformContext()->canvas()->endPlatformPaint(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/ImageBufferData.h b/WebCore/platform/graphics/chromium/ImageBufferData.h new file mode 100644 index 0000000..504b893 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ImageBufferData.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageBufferData_h +#define ImageBufferData_h + +#include "PlatformContextSkia.h" + +#include "skia/ext/platform_canvas.h" + +namespace WebCore { + +class ImageBufferData { +public: + ImageBufferData(const IntSize&); + + skia::PlatformCanvas m_canvas; + PlatformContextSkia m_platformContext; +}; + +} // namespace WebCore + +#endif // ImageBufferData_h diff --git a/WebCore/platform/graphics/chromium/ImageChromiumMac.mm b/WebCore/platform/graphics/chromium/ImageChromiumMac.mm new file mode 100644 index 0000000..073a409 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ImageChromiumMac.mm @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// A wrapper around Uniscribe that provides a reasonable API. + +#include "config.h" +#include "BitmapImage.h" + +#include "ChromiumBridge.h" +#include "Image.h" + +namespace WebCore { + +PassRefPtr<Image> Image::loadPlatformResource(const char* name) +{ + return ChromiumBridge::loadPlatformImageResource(name); +} + +// FIXME: These are temporary stubs, we need real implementations which +// may come in the form of ImageChromium.cpp. The Windows Chromium +// implementation is currently in ImageSkia.cpp. + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h new file mode 100644 index 0000000..959147a --- /dev/null +++ b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayerPrivateChromium_h +#define MediaPlayerPrivateChromium_h + +#if ENABLE(VIDEO) + +#include "MediaPlayer.h" + +namespace WebCore { + +class MediaPlayerPrivate : public Noncopyable { +public: + MediaPlayerPrivate(MediaPlayer*); + ~MediaPlayerPrivate(); + + IntSize naturalSize() const; + bool hasVideo() const; + + void load(const String& url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + + int dataRate() const; + + MediaPlayer::NetworkState networkState() const; + MediaPlayer::ReadyState readyState() const; + + float maxTimeBuffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + bool totalBytesKnown() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setRect(const IntRect&); + + void paint(GraphicsContext*, const IntRect&); + + static void getSupportedTypes(HashSet<String>&); + static bool isAvailable(); + + // Public methods to be called by WebMediaPlayer + FrameView* frameView(); + void networkStateChanged(); + void readyStateChanged(); + void timeChanged(); + void volumeChanged(); + void repaint(); + +private: + MediaPlayer* m_player; + void* m_data; +}; + +} // namespace WebCore + +#endif + +#endif // MediaPlayerPrivateChromium_h diff --git a/WebCore/platform/graphics/chromium/PlatformIcon.h b/WebCore/platform/graphics/chromium/PlatformIcon.h new file mode 100644 index 0000000..51613b8 --- /dev/null +++ b/WebCore/platform/graphics/chromium/PlatformIcon.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PlatformIcon_h +#define PlatformIcon_h + +typedef struct HICON__* HICON; + +namespace WebCore { + +typedef HICON PlatformIcon; + +} // namespace WebCore + +#endif // PlatformIcon_h diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp new file mode 100644 index 0000000..06e997f --- /dev/null +++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All Rights Reserved. + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include "ChromiumBridge.h" +#include "Font.h" +#include "FontCache.h" +#include "FloatRect.h" +#include "FontDescription.h" +#include <wtf/MathExtras.h> + +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <objidl.h> +#include <mlang.h> + +namespace WebCore { + +static inline float scaleEmToUnits(float x, int unitsPerEm) +{ + return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x; +} + +void SimpleFontData::platformInit() +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + + TEXTMETRIC textMetric = {0}; + if (!GetTextMetrics(dc, &textMetric)) { + if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + // Retry GetTextMetrics. + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401. + if (!GetTextMetrics(dc, &textMetric)) + ASSERT_NOT_REACHED(); + } + } + + m_avgCharWidth = textMetric.tmAveCharWidth; + m_maxCharWidth = textMetric.tmMaxCharWidth; + + m_ascent = textMetric.tmAscent; + m_descent = textMetric.tmDescent; + m_lineGap = textMetric.tmExternalLeading; + m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. + + OUTLINETEXTMETRIC outlineTextMetric; + if (GetOutlineTextMetrics(dc, sizeof(outlineTextMetric), &outlineTextMetric) > 0) { + // This is a TrueType font. We might be able to get an accurate xHeight. + GLYPHMETRICS glyphMetrics = {0}; + MAT2 identityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; + DWORD len = GetGlyphOutlineW(dc, 'x', GGO_METRICS, &glyphMetrics, 0, 0, &identityMatrix); + if (len != GDI_ERROR && glyphMetrics.gmBlackBoxY > 0) + m_xHeight = static_cast<float>(glyphMetrics.gmBlackBoxY); + } + + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); +} + +void SimpleFontData::platformDestroy() +{ + // We don't hash this on Win32, so it's effectively owned by us. + delete m_smallCapsFontData; + m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + LOGFONT winFont; + GetObject(m_font.hfont(), sizeof(LOGFONT), &winFont); + float smallCapsSize = 0.70f * fontDescription.computedSize(); + // Unlike WebKit trunk, we don't multiply the size by 32. That seems + // to be some kind of artifact of their CG backend, or something. + winFont.lfHeight = -lroundf(smallCapsSize); + HFONT hfont = CreateFontIndirect(&winFont); + m_smallCapsFontData = + new SimpleFontData(FontPlatformData(hfont, smallCapsSize)); + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + // This used to be implemented with IMLangFontLink2, but since that code has + // been disabled, this would always return false anyway. + return false; +} + +void SimpleFontData::determinePitch() +{ + // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + + // Yes, this looks backwards, but the fixed pitch bit is actually set if the font + // is *not* fixed pitch. Unbelievable but true. + TEXTMETRIC textMetric = {0}; + if (!GetTextMetrics(dc, &textMetric)) { + if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + // Retry GetTextMetrics. + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401. + if (!GetTextMetrics(dc, &textMetric)) + ASSERT_NOT_REACHED(); + } + } + + m_treatAsFixedPitch = ((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + + int width = 0; + if (!GetCharWidthI(dc, glyph, 1, 0, &width)) { + // Ask the browser to preload the font and retry. + if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401. + if (!GetCharWidthI(dc, glyph, 1, 0, &width)) + ASSERT_NOT_REACHED(); + } + } + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + + return static_cast<float>(width); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp new file mode 100644 index 0000000..8200175 --- /dev/null +++ b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include "Font.h" +#include "FontCache.h" +#include "FloatRect.h" +#include "FontDescription.h" +#include "Logging.h" +#include "NotImplemented.h" + +#include "SkPaint.h" +#include "SkTypeface.h" +#include "SkTime.h" + +namespace WebCore { + +// Smallcaps versions of fonts are 70% the size of the normal font. +static const float smallCapsFraction = 0.7f; + +void SimpleFontData::platformInit() +{ + SkPaint paint; + SkPaint::FontMetrics metrics; + + m_font.setupPaint(&paint); + paint.getFontMetrics(&metrics); + + // Beware those who step here: This code is designed to match Win32 font + // metrics *exactly*. + if (metrics.fVDMXMetricsValid) { + m_ascent = metrics.fVDMXAscent; + m_descent = metrics.fVDMXDescent; + } else { + m_ascent = SkScalarRound(-metrics.fAscent); + m_descent = SkScalarRound(metrics.fHeight) - m_ascent; + } + + if (metrics.fXHeight) + m_xHeight = metrics.fXHeight; + else { + // hack taken from the Windows port + m_xHeight = static_cast<float>(m_ascent) * 0.56; + } + + m_lineGap = SkScalarRound(metrics.fLeading); + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is + // calculated for us, but we need to calculate m_maxCharWidth and + // m_avgCharWidth in order for text entry widgets to be sized correctly. + + m_maxCharWidth = SkScalarRound(metrics.fXRange * SkScalarRound(m_font.size())); + + if (metrics.fAvgCharWidth) + m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); + else { + m_avgCharWidth = m_xHeight; + + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + + if (glyphPageZero) { + static const UChar32 x_char = 'x'; + const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(x_char).glyph; + + if (xGlyph) + m_avgCharWidth = widthForGlyph(xGlyph); + } + } +} + +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; + m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + const float smallCapsSize = lroundf(fontDescription.computedSize() * smallCapsFraction); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, smallCapsSize)); + } + + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + SkPaint paint; + static const unsigned maxBufferCount = 64; + uint16_t glyphs[maxBufferCount]; + + m_font.setupPaint(&paint); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + while (length > 0) { + int n = SkMin32(length, SK_ARRAY_COUNT(glyphs)); + + // textToGlyphs takes a byte count so we double the character count. + int count = paint.textToGlyphs(characters, n * 2, glyphs); + for (int i = 0; i < count; i++) { + if (0 == glyphs[i]) + return false; // missing glyph + } + + characters += n; + length -= n; + } + + return true; +} + +void SimpleFontData::determinePitch() +{ + m_treatAsFixedPitch = platformData().isFixedPitch(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + SkASSERT(sizeof(glyph) == 2); // compile-time assert + + SkPaint paint; + + m_font.setupPaint(&paint); + + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkScalar width = paint.measureText(&glyph, 2); + + return SkScalarToFloat(width); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp new file mode 100644 index 0000000..798ee32 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ThemeHelperChromiumWin.h" + +#include "FloatRect.h" +#include "GraphicsContext.h" + +namespace WebCore { + +ThemeHelperWin::ThemeHelperWin(GraphicsContext* context, const IntRect& rect) + : m_orgContext(context) + , m_orgMatrix(context->getCTM()) + , m_orgRect(rect) +{ + if (m_orgMatrix.b() != 0 || m_orgMatrix.c() != 0) { // Check for skew. + // Complicated effects, make a copy and draw the bitmap there. + m_type = COPY; + m_rect.setSize(rect.size()); + + m_newBuffer.set(ImageBuffer::create(rect.size(), false).release()); + + // Theme drawing messes with the transparency. + // FIXME: Ideally, we would leave this transparent, but I was + // having problems with button drawing, so we fill with white. Buttons + // looked good with transparent here and no fixing up of the alpha + // later, but text areas didn't. This makes text areas look good but + // gives buttons a white halo. Is there a way to fix this? I think + // buttons actually have antialised edges which is just not possible + // to handle on a transparent background given that it messes with the + // alpha channel. + FloatRect newContextRect(0, 0, rect.width(), rect.height()); + GraphicsContext* newContext = m_newBuffer->context(); + newContext->setFillColor(Color::white); + newContext->fillRect(newContextRect); + + return; + } + + if (m_orgMatrix.a() != 1.0 || m_orgMatrix.d() != 1.0) { // Check for scale. + // Only a scaling is applied. + m_type = SCALE; + + // Save the transformed coordinates to draw. + m_rect = m_orgMatrix.mapRect(rect); + + m_orgContext->save(); + m_orgContext->concatCTM(m_orgContext->getCTM().inverse()); + return; + } + + // Nothing interesting. + m_rect = rect; + m_type = ORIGINAL; +} + +ThemeHelperWin::~ThemeHelperWin() +{ + switch (m_type) { + case SCALE: + m_orgContext->restore(); + break; + case COPY: { + // Copy the duplicate bitmap with our control to the original canvas. + FloatRect destRect(m_orgRect); + m_newBuffer->context()->platformContext()->canvas()-> + getTopPlatformDevice().fixupAlphaBeforeCompositing(); + m_orgContext->drawImage(m_newBuffer->image(), destRect); + break; + } + case ORIGINAL: + break; + } +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h new file mode 100644 index 0000000..1771fb4 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ThemeHelperWin_h +#define ThemeHelperWin_h + +#include "TransformationMatrix.h" +#include "ImageBuffer.h" +#include "IntRect.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class GraphicsContext; +class IntRect; + +// Helps drawing theme elements like buttons and scroll bars. This will handle +// translations and scalings that Windows might not, by either making Windows +// draw the appropriate sized control, or by rendering it into an off-screen +// context and transforming it ourselves. +class ThemeHelperWin { + enum Type { + // Use the original canvas with no changes. This is the normal mode. + ORIGINAL, + + // Use the original canvas but scale the rectangle of the control so + // that it will be the correct size, undoing any scale already on the + // canvas. This will have the effect of just drawing the control bigger + // or smaller and not actually expanding or contracting the pixels in + // it. This usually looks better. + SCALE, + + // Make a copy of the control and then transform it ourselves after + // Windows draws it. This allows us to get complex effects. + COPY, + }; + +public: + // Prepares drawing a control with the given rect to the given context. + ThemeHelperWin(GraphicsContext* context, const IntRect& rect); + ~ThemeHelperWin(); + + // Returns the context to draw the control into, which may be the original + // or the copy, depending on the mode. + GraphicsContext* context() + { + return m_newBuffer.get() ? m_newBuffer->context() : m_orgContext; + } + + // Returns the rectangle in which to draw into the canvas() by Windows. + const IntRect& rect() { return m_rect; } + +private: + Type m_type; + + // The original canvas to wrote to. Not owned by this class. + GraphicsContext* m_orgContext; + TransformationMatrix m_orgMatrix; + IntRect m_orgRect; + + // When m_type == COPY, this will be a new surface owned by this class that + // represents the copy. + OwnPtr<ImageBuffer> m_newBuffer; + + // The control rectangle in the coordinate space of canvas(). + IntRect m_rect; +}; + +} // namespace WebCore + +#endif // ThemeHelperWin_h diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp new file mode 100644 index 0000000..caeb959 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -0,0 +1,902 @@ +/* + * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "UniscribeHelper.h" + +#include <windows.h> + +#include "FontUtilsChromiumWin.h" +#include <wtf/Assertions.h> + +namespace WebCore { + +// This function is used to see where word spacing should be applied inside +// runs. Note that this must match Font::treatAsSpace so we all agree where +// and how much space this is, so we don't want to do more general Unicode +// "is this a word break" thing. +static bool treatAsSpace(UChar c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; +} + +// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid +// and blank glyphs. Just because ScriptShape succeeds does not mean +// that a text run is rendered correctly. Some characters may be rendered +// with default/invalid/blank glyphs. Therefore, we need to check if the glyph +// array returned by ScriptShape contains any of those glyphs to make +// sure that the text run is rendered successfully. +static bool containsMissingGlyphs(WORD *glyphs, + int length, + SCRIPT_FONTPROPERTIES* properties) +{ + for (int i = 0; i < length; ++i) { + if (glyphs[i] == properties->wgDefault + || (glyphs[i] == properties->wgInvalid + && glyphs[i] != properties->wgBlank)) + return true; + } + + return false; +} + +// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque +// handle and we can't directly query it to make a new HFONT sharing +// its characteristics (height, style, etc) except for family name. +// This function uses GetObject to convert HFONT back to LOGFONT, +// resets the fields of LOGFONT and calculates style to use later +// for the creation of a font identical to HFONT other than family name. +static void setLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style) +{ + ASSERT(hfont && logfont); + if (!hfont || !logfont) + return; + + GetObject(hfont, sizeof(LOGFONT), logfont); + // We reset these fields to values appropriate for CreateFontIndirect. + // while keeping lfHeight, which is the most important value in creating + // a new font similar to hfont. + logfont->lfWidth = 0; + logfont->lfEscapement = 0; + logfont->lfOrientation = 0; + logfont->lfCharSet = DEFAULT_CHARSET; + logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; + logfont->lfQuality = DEFAULT_QUALITY; // Honor user's desktop settings. + logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + if (style) + *style = getStyleFromLogfont(logfont); +} + +UniscribeHelper::UniscribeHelper(const UChar* input, + int inputLength, + bool isRtl, + HFONT hfont, + SCRIPT_CACHE* scriptCache, + SCRIPT_FONTPROPERTIES* fontProperties) + : m_input(input) + , m_inputLength(inputLength) + , m_isRtl(isRtl) + , m_hfont(hfont) + , m_scriptCache(scriptCache) + , m_fontProperties(fontProperties) + , m_directionalOverride(false) + , m_inhibitLigate(false) + , m_letterSpacing(0) + , m_spaceWidth(0) + , m_wordSpacing(0) + , m_ascent(0) +{ + m_logfont.lfFaceName[0] = 0; +} + +UniscribeHelper::~UniscribeHelper() +{ +} + +void UniscribeHelper::initWithOptionalLengthProtection(bool lengthProtection) +{ + // We cap the input length and just don't do anything. We'll allocate a lot + // of things of the size of the number of characters, so the allocated + // memory will be several times the input length. Plus shaping such a large + // buffer may be a form of denial of service. No legitimate text should be + // this long. It also appears that Uniscribe flatly rejects very long + // strings, so we don't lose anything by doing this. + // + // The input length protection may be disabled by the unit tests to cause + // an error condition. + static const int kMaxInputLength = 65535; + if (m_inputLength == 0 || (lengthProtection && m_inputLength > kMaxInputLength)) + return; + + fillRuns(); + fillShapes(); + fillScreenOrder(); +} + +int UniscribeHelper::width() const +{ + int width = 0; + for (int itemIndex = 0; itemIndex < static_cast<int>(m_runs.size()); itemIndex++) + width += advanceForItem(itemIndex); + return width; +} + +void UniscribeHelper::justify(int additionalSpace) +{ + // Count the total number of glyphs we have so we know how big to make the + // buffers below. + int totalGlyphs = 0; + for (size_t run = 0; run < m_runs.size(); run++) { + int runIndex = m_screenOrder[run]; + totalGlyphs += static_cast<int>(m_shapes[runIndex].glyphLength()); + } + if (totalGlyphs == 0) + return; // Nothing to do. + + // We make one big buffer in screen order of all the glyphs we are drawing + // across runs so that the justification function will adjust evenly across + // all glyphs. + Vector<SCRIPT_VISATTR, 64> visualAttributes; + visualAttributes.resize(totalGlyphs); + Vector<int, 64> advances; + advances.resize(totalGlyphs); + Vector<int, 64> justify; + justify.resize(totalGlyphs); + + // Build the packed input. + int destIndex = 0; + for (size_t run = 0; run < m_runs.size(); run++) { + int runIndex = m_screenOrder[run]; + const Shaping& shaping = m_shapes[runIndex]; + + for (int i = 0; i < shaping.glyphLength(); i++, destIndex++) { + memcpy(&visualAttributes[destIndex], &shaping.m_visualAttributes[i], + sizeof(SCRIPT_VISATTR)); + advances[destIndex] = shaping.m_advance[i]; + } + } + + // The documentation for Scriptjustify is wrong, the parameter is the space + // to add and not the width of the column you want. + const int minKashida = 1; // How do we decide what this should be? + ScriptJustify(&visualAttributes[0], &advances[0], totalGlyphs, + additionalSpace, minKashida, &justify[0]); + + // Now we have to unpack the justification amounts back into the runs so + // the glyph indices match. + int globalGlyphIndex = 0; + for (size_t run = 0; run < m_runs.size(); run++) { + int runIndex = m_screenOrder[run]; + Shaping& shaping = m_shapes[runIndex]; + + shaping.m_justify.resize(shaping.glyphLength()); + for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++) + shaping.m_justify[i] = justify[globalGlyphIndex]; + } +} + +int UniscribeHelper::characterToX(int offset) const +{ + HRESULT hr; + ASSERT(offset <= m_inputLength); + + // Our algorithm is to traverse the items in screen order from left to + // right, adding in each item's screen width until we find the item with + // the requested character in it. + int width = 0; + for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) { + // Compute the length of this run. + int itemIndex = m_screenOrder[screenIndex]; + const SCRIPT_ITEM& item = m_runs[itemIndex]; + const Shaping& shaping = m_shapes[itemIndex]; + int itemLength = shaping.charLength(); + + if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) { + // Character offset is in this run. + int charLength = offset - item.iCharPos; + + int curX = 0; + hr = ScriptCPtoX(charLength, FALSE, itemLength, + shaping.glyphLength(), + &shaping.m_logs[0], &shaping.m_visualAttributes[0], + shaping.effectiveAdvances(), &item.a, &curX); + if (FAILED(hr)) + return 0; + + width += curX + shaping.m_prePadding; + ASSERT(width >= 0); + return width; + } + + // Move to the next item. + width += advanceForItem(itemIndex); + } + ASSERT(width >= 0); + return width; +} + +int UniscribeHelper::xToCharacter(int x) const +{ + // We iterate in screen order until we find the item with the given pixel + // position in it. When we find that guy, we ask Uniscribe for the + // character index. + HRESULT hr; + for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) { + int itemIndex = m_screenOrder[screenIndex]; + int itemAdvance = advanceForItem(itemIndex); + + // Note that the run may be empty if shaping failed, so we want to skip + // over it. + const Shaping& shaping = m_shapes[itemIndex]; + int itemLength = shaping.charLength(); + if (x <= itemAdvance && itemLength > 0) { + // The requested offset is within this item. + const SCRIPT_ITEM& item = m_runs[itemIndex]; + + // Account for the leading space we've added to this run that + // Uniscribe doesn't know about. + x -= shaping.m_prePadding; + + int charX = 0; + int trailing; + hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(), + &shaping.m_logs[0], &shaping.m_visualAttributes[0], + shaping.effectiveAdvances(), &item.a, &charX, + &trailing); + + // The character offset is within the item. We need to add the + // item's offset to transform it into the space of the TextRun + return charX + item.iCharPos; + } + + // The offset is beyond this item, account for its length and move on. + x -= itemAdvance; + } + + // Error condition, we don't know what to do if we don't have that X + // position in any of our items. + return 0; +} + +void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to) +{ + HGDIOBJ oldFont = 0; + int curX = x; + bool firstRun = true; + + for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) { + int itemIndex = m_screenOrder[screenIndex]; + const SCRIPT_ITEM& item = m_runs[itemIndex]; + const Shaping& shaping = m_shapes[itemIndex]; + + // Character offsets within this run. THESE MAY NOT BE IN RANGE and may + // be negative, etc. The code below handles this. + int fromChar = from - item.iCharPos; + int toChar = to - item.iCharPos; + + // See if we need to draw any characters in this item. + if (shaping.charLength() == 0 || + fromChar >= shaping.charLength() || toChar <= 0) { + // No chars in this item to display. + curX += advanceForItem(itemIndex); + continue; + } + + // Compute the starting glyph within this span. |from| and |to| are + // global offsets that may intersect arbitrarily with our local run. + int fromGlyph, afterGlyph; + if (item.a.fRTL) { + // To compute the first glyph when going RTL, we use |to|. + if (toChar >= shaping.charLength()) + // The end of the text is after (to the left) of us. + fromGlyph = 0; + else { + // Since |to| is exclusive, the first character we draw on the + // left is actually the one right before (to the right) of + // |to|. + fromGlyph = shaping.m_logs[toChar - 1]; + } + + // The last glyph is actually the first character in the range. + if (fromChar <= 0) { + // The first character to draw is before (to the right) of this + // span, so draw all the way to the end. + afterGlyph = shaping.glyphLength(); + } else { + // We want to draw everything up until the character to the + // right of |from|. To the right is - 1, so we look that up + // (remember our character could be more than one glyph, so we + // can't look up our glyph and add one). + afterGlyph = shaping.m_logs[fromChar - 1]; + } + } else { + // Easy case, everybody agrees about directions. We only need to + // handle boundary conditions to get a range inclusive at the + // beginning, and exclusive at the ending. We have to do some + // computation to see the glyph one past the end. + fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar]; + if (toChar >= shaping.charLength()) + afterGlyph = shaping.glyphLength(); + else + afterGlyph = shaping.m_logs[toChar]; + } + + // Account for the characters that were skipped in this run. When + // WebKit asks us to draw a subset of the run, it actually tells us + // to draw at the X offset of the beginning of the run, since it + // doesn't know the internal position of any of our characters. + const int* effectiveAdvances = shaping.effectiveAdvances(); + int innerOffset = 0; + for (int i = 0; i < fromGlyph; i++) + innerOffset += effectiveAdvances[i]; + + // Actually draw the glyphs we found. + int glyphCount = afterGlyph - fromGlyph; + if (fromGlyph >= 0 && glyphCount > 0) { + // Account for the preceeding space we need to add to this run. We + // don't need to count for the following space because that will be + // counted in advanceForItem below when we move to the next run. + innerOffset += shaping.m_prePadding; + + // Pass 0 in when there is no justification. + const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph]; + + if (firstRun) { + oldFont = SelectObject(dc, shaping.m_hfont); + firstRun = false; + } else + SelectObject(dc, shaping.m_hfont); + + // Fonts with different ascents can be used to render different + // runs. 'Across-runs' y-coordinate correction needs to be + // adjusted for each font. + HRESULT hr = S_FALSE; + for (int executions = 0; executions < 2; ++executions) { + hr = ScriptTextOut(dc, shaping.m_scriptCache, + curX + innerOffset, + y - shaping.m_ascentOffset, + 0, 0, &item.a, 0, 0, + &shaping.m_glyphs[fromGlyph], + glyphCount, + &shaping.m_advance[fromGlyph], + justify, + &shaping.m_offsets[fromGlyph]); + if (S_OK != hr && 0 == executions) { + // If this ScriptTextOut is called from the renderer it + // might fail because the sandbox is preventing it from + // opening the font files. If we are running in the + // renderer, TryToPreloadFont is overridden to ask the + // browser to preload the font for us so we can access it. + tryToPreloadFont(shaping.m_hfont); + continue; + } + break; + } + + ASSERT(S_OK == hr); + } + + curX += advanceForItem(itemIndex); + } + + if (oldFont) + SelectObject(dc, oldFont); +} + +WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const +{ + // Find the run for the given character. + for (int i = 0; i < static_cast<int>(m_runs.size()); i++) { + int firstChar = m_runs[i].iCharPos; + const Shaping& shaping = m_shapes[i]; + int localOffset = charOffset - firstChar; + if (localOffset >= 0 && localOffset < shaping.charLength()) { + // The character is in this run, return the first glyph for it + // (should generally be the only glyph). It seems Uniscribe gives + // glyph 0 for empty, which is what we want to return in the + // "missing" case. + size_t glyphIndex = shaping.m_logs[localOffset]; + if (glyphIndex >= shaping.m_glyphs.size()) { + // The glyph should be in this run, but the run has too few + // actual characters. This can happen when shaping the run + // fails, in which case, we should have no data in the logs at + // all. + ASSERT(shaping.m_glyphs.size() == 0); + return 0; + } + return shaping.m_glyphs[glyphIndex]; + } + } + + return 0; +} + +void UniscribeHelper::fillRuns() +{ + HRESULT hr; + m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS); + + SCRIPT_STATE inputState; + inputState.uBidiLevel = m_isRtl; + inputState.fOverrideDirection = m_directionalOverride; + inputState.fInhibitSymSwap = false; + inputState.fCharShape = false; // Not implemented in Uniscribe + inputState.fDigitSubstitute = false; // Do we want this for Arabic? + inputState.fInhibitLigate = m_inhibitLigate; + inputState.fDisplayZWG = false; // Don't draw control characters. + inputState.fArabicNumContext = m_isRtl; // Do we want this for Arabic? + inputState.fGcpClusters = false; + inputState.fReserved = 0; + inputState.fEngineReserved = 0; + // The psControl argument to ScriptItemize should be non-0 for RTL text, + // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a + // SCRIPT_CONTROL that is set to all zeros. Zero as a locale ID means the + // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx + static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage :16; + 0, // fContextDigits :1; + 0, // fInvertPreBoundDir :1; + 0, // fInvertPostBoundDir :1; + 0, // fLinkStringBefore :1; + 0, // fLinkStringAfter :1; + 0, // fNeutralOverride :1; + 0, // fNumericOverride :1; + 0, // fLegacyBidiClass :1; + 0, // fMergeNeutralItems :1; + 0};// fReserved :7; + // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState) + // here would be appropriate if we wanted to set the language ID, and get + // local digit substitution behavior. For now, don't do it. + + while (true) { + int numberOfItems = 0; + + // Ideally, we would have a way to know the runs before and after this + // one, and put them into the control parameter of ScriptItemize. This + // would allow us to shape characters properly that cross style + // boundaries (WebKit bug 6148). + // + // We tell ScriptItemize that the output list of items is one smaller + // than it actually is. According to Mozilla bug 366643, if there is + // not enough room in the array on pre-SP2 systems, ScriptItemize will + // write one past the end of the buffer. + // + // ScriptItemize is very strange. It will often require a much larger + // ITEM buffer internally than it will give us as output. For example, + // it will say a 16-item buffer is not big enough, and will write + // interesting numbers into all those items. But when we give it a 32 + // item buffer and it succeeds, it only has one item output. + // + // It seems to be doing at least two passes, the first where it puts a + // lot of intermediate data into our items, and the second where it + // collates them. + hr = ScriptItemize(m_input, m_inputLength, + static_cast<int>(m_runs.size()) - 1, &inputControl, + &inputState, + &m_runs[0], &numberOfItems); + if (SUCCEEDED(hr)) { + m_runs.resize(numberOfItems); + break; + } + if (hr != E_OUTOFMEMORY) { + // Some kind of unexpected error. + m_runs.resize(0); + break; + } + // There was not enough items for it to write into, expand. + m_runs.resize(m_runs.size() * 2); + } +} + +bool UniscribeHelper::shape(const UChar* input, + int itemLength, + int numGlyphs, + SCRIPT_ITEM& run, + Shaping& shaping) +{ + HFONT hfont = m_hfont; + SCRIPT_CACHE* scriptCache = m_scriptCache; + SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; + int ascent = m_ascent; + HDC tempDC = 0; + HGDIOBJ oldFont = 0; + HRESULT hr; + bool lastFallbackTried = false; + bool result; + + int generatedGlyphs = 0; + + // In case HFONT passed in ctor cannot render this run, we have to scan + // other fonts from the beginning of the font list. + resetFontIndex(); + + // Compute shapes. + while (true) { + shaping.m_logs.resize(itemLength); + shaping.m_glyphs.resize(numGlyphs); + shaping.m_visualAttributes.resize(numGlyphs); + +#ifdef PURIFY + // http://code.google.com/p/chromium/issues/detail?id=5309 + // Purify isn't able to track the assignments that ScriptShape makes to + // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it + // writes, will be considered un-initialized data. + // + // This hack avoid the false-positive UMRs by marking the buffer as + // initialized. + // + // FIXME: A better solution would be to use Purify's API and mark only + // the populated range as initialized: + // + // PurifyMarkAsInitialized( + // &shaping.m_glyphs[0], + // sizeof(shaping.m_glyphs[0] * generatedGlyphs); + + ZeroMemory(&shaping.m_glyphs[0], + sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size()); +#endif + + // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true + // here. Is that what we want? It will display control characters. + hr = ScriptShape(tempDC, scriptCache, input, itemLength, + numGlyphs, &run.a, + &shaping.m_glyphs[0], &shaping.m_logs[0], + &shaping.m_visualAttributes[0], &generatedGlyphs); + if (hr == E_PENDING) { + // Allocate the DC. + tempDC = GetDC(0); + oldFont = SelectObject(tempDC, hfont); + continue; + } else if (hr == E_OUTOFMEMORY) { + numGlyphs *= 2; + continue; + } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties))) + break; + + // The current font can't render this run. clear DC and try + // next font. + if (tempDC) { + SelectObject(tempDC, oldFont); + ReleaseDC(0, tempDC); + tempDC = 0; + } + + if (nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) { + // The primary font does not support this run. Try next font. + // In case of web page rendering, they come from fonts specified in + // CSS stylesheets. + continue; + } else if (!lastFallbackTried) { + lastFallbackTried = true; + + // Generate a last fallback font based on the script of + // a character to draw while inheriting size and styles + // from the primary font + if (!m_logfont.lfFaceName[0]) + setLogFontAndStyle(m_hfont, &m_logfont, &m_style); + + // TODO(jungshik): generic type should come from webkit for + // UniscribeHelperTextRun (a derived class used in webkit). + const UChar *family = getFallbackFamily(input, itemLength, + FontDescription::StandardFamily, 0, 0); + bool fontOk = getDerivedFontData(family, m_style, &m_logfont, + &ascent, &hfont, &scriptCache); + + if (!fontOk) { + // If this GetDerivedFontData is called from the renderer it + // might fail because the sandbox is preventing it from opening + // the font files. If we are running in the renderer, + // TryToPreloadFont is overridden to ask the browser to preload + // the font for us so we can access it. + tryToPreloadFont(hfont); + + // Try again. + fontOk = getDerivedFontData(family, m_style, &m_logfont, + &ascent, &hfont, &scriptCache); + ASSERT(fontOk); + } + + // TODO(jungshik) : Currently GetDerivedHFont always returns a + // a valid HFONT, but in the future, I may change it to return 0. + ASSERT(hfont); + + // We don't need a font_properties for the last resort fallback font + // because we don't have anything more to try and are forced to + // accept empty glyph boxes. If we tried a series of fonts as + // 'last-resort fallback', we'd need it, but currently, we don't. + continue; + } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { + run.a.eScript = SCRIPT_UNDEFINED; + continue; + } else if (FAILED(hr)) { + // Error shaping. + generatedGlyphs = 0; + result = false; + goto cleanup; + } + } + + // Sets Windows font data for this run to those corresponding to + // a font supporting this run. we don't need to store font_properties + // because it's not used elsewhere. + shaping.m_hfont = hfont; + shaping.m_scriptCache = scriptCache; + + // The ascent of a font for this run can be different from + // that of the primary font so that we need to keep track of + // the difference per run and take that into account when calling + // ScriptTextOut in |draw|. Otherwise, different runs rendered by + // different fonts would not be aligned vertically. + shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0; + result = true; + + cleanup: + shaping.m_glyphs.resize(generatedGlyphs); + shaping.m_visualAttributes.resize(generatedGlyphs); + shaping.m_advance.resize(generatedGlyphs); + shaping.m_offsets.resize(generatedGlyphs); + if (tempDC) { + SelectObject(tempDC, oldFont); + ReleaseDC(0, tempDC); + } + // On failure, our logs don't mean anything, so zero those out. + if (!result) + shaping.m_logs.clear(); + + return result; +} + +void UniscribeHelper::fillShapes() +{ + m_shapes.resize(m_runs.size()); + for (size_t i = 0; i < m_runs.size(); i++) { + int startItem = m_runs[i].iCharPos; + int itemLength = m_inputLength - startItem; + if (i < m_runs.size() - 1) + itemLength = m_runs[i + 1].iCharPos - startItem; + + int numGlyphs; + if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) { + // We'll start our buffer sizes with the current stack space + // available in our buffers if the current input fits. As long as + // it doesn't expand past that we'll save a lot of time mallocing. + numGlyphs = UNISCRIBE_HELPER_STACK_CHARS; + } else { + // When the input doesn't fit, give up with the stack since it will + // almost surely not be enough room (unless the input actually + // shrinks, which is unlikely) and just start with the length + // recommended by the Uniscribe documentation as a "usually fits" + // size. + numGlyphs = itemLength * 3 / 2 + 16; + } + + // Convert a string to a glyph string trying the primary font, fonts in + // the fallback list and then script-specific last resort font. + Shaping& shaping = m_shapes[i]; + if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping)) + continue; + + // Compute placements. Note that offsets is documented incorrectly + // and is actually an array. + + // DC that we lazily create if Uniscribe commands us to. + // (this does not happen often because scriptCache is already + // updated when calling ScriptShape). + HDC tempDC = 0; + HGDIOBJ oldFont = 0; + HRESULT hr; + while (true) { + shaping.m_prePadding = 0; + hr = ScriptPlace(tempDC, shaping.m_scriptCache, + &shaping.m_glyphs[0], + static_cast<int>(shaping.m_glyphs.size()), + &shaping.m_visualAttributes[0], &m_runs[i].a, + &shaping.m_advance[0], &shaping.m_offsets[0], + &shaping.m_abc); + if (hr != E_PENDING) + break; + + // Allocate the DC and run the loop again. + tempDC = GetDC(0); + oldFont = SelectObject(tempDC, shaping.m_hfont); + } + + if (FAILED(hr)) { + // Some error we don't know how to handle. Nuke all of our data + // since we can't deal with partially valid data later. + m_runs.clear(); + m_shapes.clear(); + m_screenOrder.clear(); + } + + if (tempDC) { + SelectObject(tempDC, oldFont); + ReleaseDC(0, tempDC); + } + } + + adjustSpaceAdvances(); + + if (m_letterSpacing != 0 || m_wordSpacing != 0) + applySpacing(); +} + +void UniscribeHelper::fillScreenOrder() +{ + m_screenOrder.resize(m_runs.size()); + + // We assume that the input has only one text direction in it. + // TODO(brettw) are we sure we want to keep this restriction? + if (m_isRtl) { + for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) + m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i; + } else { + for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) + m_screenOrder[i] = i; + } +} + +void UniscribeHelper::adjustSpaceAdvances() +{ + if (m_spaceWidth == 0) + return; + + int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing; + + // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem. + for (size_t run = 0; run < m_runs.size(); run++) { + Shaping& shaping = m_shapes[run]; + + for (int i = 0; i < shaping.charLength(); i++) { + if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + continue; + + int glyphIndex = shaping.m_logs[i]; + int currentAdvance = shaping.m_advance[glyphIndex]; + // Don't give zero-width spaces a width. + if (!currentAdvance) + continue; + + // currentAdvance does not include additional letter-spacing, but + // space_width does. Here we find out how off we are from the + // correct width for the space not including letter-spacing, then + // just subtract that diff. + int diff = currentAdvance - spaceWidthWithoutLetterSpacing; + // The shaping can consist of a run of text, so only subtract the + // difference in the width of the glyph. + shaping.m_advance[glyphIndex] -= diff; + shaping.m_abc.abcB -= diff; + } + } +} + +void UniscribeHelper::applySpacing() +{ + for (size_t run = 0; run < m_runs.size(); run++) { + Shaping& shaping = m_shapes[run]; + bool isRtl = m_runs[run].a.fRTL; + + if (m_letterSpacing != 0) { + // RTL text gets padded to the left of each character. We increment + // the run's advance to make this happen. This will be balanced out + // by NOT adding additional advance to the last glyph in the run. + if (isRtl) + shaping.m_prePadding += m_letterSpacing; + + // Go through all the glyphs in this run and increase the "advance" + // to account for letter spacing. We adjust letter spacing only on + // cluster boundaries. + // + // This works for most scripts, but may have problems with some + // indic scripts. This behavior is better than Firefox or IE for + // Hebrew. + for (int i = 0; i < shaping.glyphLength(); i++) { + if (shaping.m_visualAttributes[i].fClusterStart) { + // Ick, we need to assign the extra space so that the glyph + // comes first, then is followed by the space. This is + // opposite for RTL. + if (isRtl) { + if (i != shaping.glyphLength() - 1) { + // All but the last character just get the spacing + // applied to their advance. The last character + // doesn't get anything, + shaping.m_advance[i] += m_letterSpacing; + shaping.m_abc.abcB += m_letterSpacing; + } + } else { + // LTR case is easier, we just add to the advance. + shaping.m_advance[i] += m_letterSpacing; + shaping.m_abc.abcB += m_letterSpacing; + } + } + } + } + + // Go through all the characters to find whitespace and insert the + // extra wordspacing amount for the glyphs they correspond to. + if (m_wordSpacing != 0) { + for (int i = 0; i < shaping.charLength(); i++) { + if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + continue; + + // The char in question is a word separator... + int glyphIndex = shaping.m_logs[i]; + + // Spaces will not have a glyph in Uniscribe, it will just add + // additional advance to the character to the left of the + // space. The space's corresponding glyph will be the character + // following it in reading order. + if (isRtl) { + // In RTL, the glyph to the left of the space is the same + // as the first glyph of the following character, so we can + // just increment it. + shaping.m_advance[glyphIndex] += m_wordSpacing; + shaping.m_abc.abcB += m_wordSpacing; + } else { + // LTR is actually more complex here, we apply it to the + // previous character if there is one, otherwise we have to + // apply it to the leading space of the run. + if (glyphIndex == 0) + shaping.m_prePadding += m_wordSpacing; + else { + shaping.m_advance[glyphIndex - 1] += m_wordSpacing; + shaping.m_abc.abcB += m_wordSpacing; + } + } + } + } // m_wordSpacing != 0 + + // Loop for next run... + } +} + +// The advance is the ABC width of the run +int UniscribeHelper::advanceForItem(int itemIndex) const +{ + int accum = 0; + const Shaping& shaping = m_shapes[itemIndex]; + + if (shaping.m_justify.size() == 0) { + // Easy case with no justification, the width is just the ABC width of + // the run. (The ABC width is the sum of the advances). + return shaping.m_abc.abcA + shaping.m_abc.abcB + + shaping.m_abc.abcC + shaping.m_prePadding; + } + + // With justification, we use the justified amounts instead. The + // justification array contains both the advance and the extra space + // added for justification, so is the width we want. + int justification = 0; + for (size_t i = 0; i < shaping.m_justify.size(); i++) + justification += shaping.m_justify[i]; + + return shaping.m_prePadding + justification; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.h b/WebCore/platform/graphics/chromium/UniscribeHelper.h new file mode 100644 index 0000000..d291105 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelper.h @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// A wrapper around Uniscribe that provides a reasonable API. + +#ifndef UniscribeHelper_h +#define UniscribeHelper_h + +#include <windows.h> +#include <usp10.h> +#include <map> + +#include <unicode/uchar.h> +#include <wtf/Vector.h> + +class UniscribeTest_TooBig_Test; // A gunit test for UniscribeHelper. + +namespace WebCore { + +#define UNISCRIBE_HELPER_STACK_RUNS 8 +#define UNISCRIBE_HELPER_STACK_CHARS 32 + +// This object should be safe to create & destroy frequently, as long as the +// caller preserves the script_cache when possible (this data may be slow to +// compute). +// +// This object is "kind of large" (~1K) because it reserves a lot of space for +// working with to avoid expensive heap operations. Therefore, not only should +// you not worry about creating and destroying it, you should try to not keep +// them around. +class UniscribeHelper { +public: + // Initializes this Uniscribe run with the text pointed to by |run| with + // |length|. The input is NOT null terminated. + // + // The is_rtl flag should be set if the input script is RTL. It is assumed + // that the caller has already divided up the input text (using ICU, for + // example) into runs of the same direction of script. This avoids + // disagreements between the caller and Uniscribe later (see FillItems). + // + // A script cache should be provided by the caller that is initialized to + // NULL. When the caller is done with the cache (it may be stored between + // runs as long as it is used consistently with the same HFONT), it should + // call ScriptFreeCache(). + UniscribeHelper(const UChar* input, + int inputLength, + bool isRtl, + HFONT, + SCRIPT_CACHE*, + SCRIPT_FONTPROPERTIES*); + + virtual ~UniscribeHelper(); + + // Sets Uniscribe's directional override flag. False by default. + bool directionalOverride() const + { + return m_directionalOverride; + } + void setDirectionalOverride(bool override) + { + m_directionalOverride = override; + } + + // Set's Uniscribe's no-ligate override flag. False by default. + bool inhibitLigate() const + { + return m_inhibitLigate; + } + void setInhibitLigate(bool inhibit) + { + m_inhibitLigate = inhibit; + } + + // Set letter spacing. We will try to insert this much space between + // graphemes (one or more glyphs perceived as a single unit by ordinary + // users of a script). Positive values increase letter spacing, negative + // values decrease it. 0 by default. + int letterSpacing() const + { + return m_letterSpacing; + } + void setLetterSpacing(int letterSpacing) + { + m_letterSpacing = letterSpacing; + } + + // Set the width of a standard space character. We use this to normalize + // space widths. Windows will make spaces after Hindi characters larger than + // other spaces. A space_width of 0 means to use the default space width. + // + // Must be set before Init() is called. + int spaceWidth() const + { + return m_spaceWidth; + } + void setSpaceWidth(int spaceWidth) + { + m_spaceWidth = spaceWidth; + } + + // Set word spacing. We will try to insert this much extra space between + // each word in the input (beyond whatever whitespace character separates + // words). Positive values lead to increased letter spacing, negative values + // decrease it. 0 by default. + // + // Must be set before Init() is called. + int wordSpacing() const + { + return m_wordSpacing; + } + void setWordSpacing(int wordSpacing) + { + m_wordSpacing = wordSpacing; + } + + void setAscent(int ascent) + { + m_ascent = ascent; + } + + // You must call this after setting any options but before doing any + // other calls like asking for widths or drawing. + void init() + { + initWithOptionalLengthProtection(true); + } + + // Returns the total width in pixels of the text run. + int width() const; + + // Call to justify the text, with the amount of space that should be ADDED + // to get the desired width that the column should be justified to. + // Normally, spaces are inserted, but for Arabic there will be kashidas + // (extra strokes) inserted instead. + // + // This function MUST be called AFTER Init(). + void justify(int additionalSpace); + + // Computes the given character offset into a pixel offset of the beginning + // of that character. + int characterToX(int offset) const; + + // Converts the given pixel X position into a logical character offset into + // the run. For positions appearing before the first character, this will + // return -1. + int xToCharacter(int x) const; + + // Draws the given characters to (x, y) in the given DC. The font will be + // handled by this function, but the font color and other attributes should + // be pre-set. + // + // The y position is the upper left corner, NOT the baseline. + void draw(HDC, int x, int y, int from, int to); + + // Returns the first glyph assigned to the character at the given offset. + // This function is used to retrieve glyph information when Uniscribe is + // being used to generate glyphs for non-complex, non-BMP (above U+FFFF) + // characters. These characters are not otherwise special and have no + // complex shaping rules, so we don't otherwise need Uniscribe, except + // Uniscribe is the only way to get glyphs for non-BMP characters. + // + // Returns 0 if there is no glyph for the given character. + WORD firstGlyphForCharacter(int charOffset) const; + +protected: + // Backend for init. The flag allows the unit test to specify whether we + // should fail early for very long strings like normal, or try to pass the + // long string to Uniscribe. The latter provides a way to force failure of + // shaping. + void initWithOptionalLengthProtection(bool lengthProtection); + + // Tries to preload the font when the it is not accessible. + // This is the default implementation and it does not do anything. + virtual void tryToPreloadFont(HFONT) {} + +private: + friend class UniscribeTest_TooBig_Test; + + // An array corresponding to each item in runs_ containing information + // on each of the glyphs that were generated. Like runs_, this is in + // reading order. However, for rtl text, the characters within each + // item will be reversed. + struct Shaping { + Shaping() + : m_prePadding(0) + , m_hfont(NULL) + , m_scriptCache(NULL) + , m_ascentOffset(0) { + m_abc.abcA = 0; + m_abc.abcB = 0; + m_abc.abcC = 0; + } + + // Returns the number of glyphs (which will be drawn to the screen) + // in this run. + int glyphLength() const + { + return static_cast<int>(m_glyphs.size()); + } + + // Returns the number of characters (that we started with) in this run. + int charLength() const + { + return static_cast<int>(m_logs.size()); + } + + // Returns the advance array that should be used when measuring glyphs. + // The returned pointer will indicate an array with glyph_length() + // elements and the advance that should be used for each one. This is + // either the real advance, or the justified advances if there is one, + // and is the array we want to use for measurement. + const int* effectiveAdvances() const + { + if (m_advance.size() == 0) + return 0; + if (m_justify.size() == 0) + return &m_advance[0]; + return &m_justify[0]; + } + + // This is the advance amount of space that we have added to the + // beginning of the run. It is like the ABC's |A| advance but one that + // we create and must handle internally whenever computing with pixel + // offsets. + int m_prePadding; + + // Glyph indices in the font used to display this item. These indices + // are in screen order. + Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_glyphs; + + // For each input character, this tells us the first glyph index it + // generated. This is the only array with size of the input chars. + // + // All offsets are from the beginning of this run. Multiple characters + // can generate one glyph, in which case there will be adjacent + // duplicates in this list. One character can also generate multiple + // glyphs, in which case there will be skipped indices in this list. + Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_logs; + + // Flags and such for each glyph. + Vector<SCRIPT_VISATTR, UNISCRIBE_HELPER_STACK_CHARS> m_visualAttributes; + + // Horizontal advances for each glyph listed above, this is basically + // how wide each glyph is. + Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_advance; + + // This contains glyph offsets, from the nominal position of a glyph. + // It is used to adjust the positions of multiple combining characters + // around/above/below base characters in a context-sensitive manner so + // that they don't bump against each other and the base character. + Vector<GOFFSET, UNISCRIBE_HELPER_STACK_CHARS> m_offsets; + + // Filled by a call to Justify, this is empty for nonjustified text. + // If nonempty, this contains the array of justify characters for each + // character as returned by ScriptJustify. + // + // This is the same as the advance array, but with extra space added + // for some characters. The difference between a glyph's |justify| + // width and it's |advance| width is the extra space added. + Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_justify; + + // Sizing information for this run. This treats the entire run as a + // character with a preceeding advance, width, and ending advance. The + // B width is the sum of the |advance| array, and the A and C widths + // are any extra spacing applied to each end. + // + // It is unclear from the documentation what this actually means. From + // experimentation, it seems that the sum of the character advances is + // always the sum of the ABC values, and I'm not sure what you're + // supposed to do with the ABC values. + ABC m_abc; + + // Pointers to windows font data used to render this run. + HFONT m_hfont; + SCRIPT_CACHE* m_scriptCache; + + // Ascent offset between the ascent of the primary font + // and that of the fallback font. The offset needs to be applied, + // when drawing a string, to align multiple runs rendered with + // different fonts. + int m_ascentOffset; + }; + + // Computes the runs_ array from the text run. + void fillRuns(); + + // Computes the shapes_ array given an runs_ array already filled in. + void fillShapes(); + + // Fills in the screen_order_ array (see below). + void fillScreenOrder(); + + // Called to update the glyph positions based on the current spacing + // options that are set. + void applySpacing(); + + // Normalizes all advances for spaces to the same width. This keeps windows + // from making spaces after Hindi characters larger, which is then + // inconsistent with our meaure of the width since WebKit doesn't include + // spaces in text-runs sent to uniscribe unless white-space:pre. + void adjustSpaceAdvances(); + + // Returns the total width of a single item. + int advanceForItem(int) const; + + // Shapes a run (pointed to by |input|) using |hfont| first. + // Tries a series of fonts specified retrieved with NextWinFontData + // and finally a font covering characters in |*input|. A string pointed + // by |input| comes from ScriptItemize and is supposed to contain + // characters belonging to a single script aside from characters common to + // all scripts (e.g. space). + bool shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, Shaping&); + + // Gets Windows font data for the next best font to try in the list + // of fonts. When there's no more font available, returns false + // without touching any of out params. Need to call ResetFontIndex + // to start scanning of the font list from the beginning. + virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent) + { + return false; + } + + // Resets the font index to the first in the list of fonts to try after the + // primaryFont turns out not to work. With fontIndex reset, + // NextWinFontData scans fallback fonts from the beginning. + virtual void resetFontIndex() {} + + // The input data for this run of Uniscribe. See the constructor. + const UChar* m_input; + const int m_inputLength; + const bool m_isRtl; + + // Windows font data for the primary font. In a sense, m_logfont and m_style + // are redundant because m_hfont contains all the information. However, + // invoking GetObject, everytime we need the height and the style, is rather + // expensive so that we cache them. Would it be better to add getter and + // (virtual) setter for the height and the style of the primary font, + // instead of m_logfont? Then, a derived class ctor can set m_ascent, + // m_height and m_style if they're known. Getters for them would have to + // 'infer' their values from m_hfont ONLY when they're not set. + HFONT m_hfont; + SCRIPT_CACHE* m_scriptCache; + SCRIPT_FONTPROPERTIES* m_fontProperties; + int m_ascent; + LOGFONT m_logfont; + int m_style; + + // Options, see the getters/setters above. + bool m_directionalOverride; + bool m_inhibitLigate; + int m_letterSpacing; + int m_spaceWidth; + int m_wordSpacing; + + // Uniscribe breaks the text into Runs. These are one length of text that is + // in one script and one direction. This array is in reading order. + Vector<SCRIPT_ITEM, UNISCRIBE_HELPER_STACK_RUNS> m_runs; + + Vector<Shaping, UNISCRIBE_HELPER_STACK_RUNS> m_shapes; + + // This is a mapping between reading order and screen order for the items. + // Uniscribe's items array are in reading order. For right-to-left text, + // or mixed (although WebKit's |TextRun| should really be only one + // direction), this makes it very difficult to compute character offsets + // and positions. This list is in screen order from left to right, and + // gives the index into the |m_runs| and |m_shapes| arrays of each + // subsequent item. + Vector<int, UNISCRIBE_HELPER_STACK_RUNS> m_screenOrder; +}; + +} // namespace WebCore + +#endif // UniscribeHelper_h diff --git a/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp new file mode 100644 index 0000000..f801c13 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "UniscribeHelperTextRun.h" + +#include "ChromiumBridge.h" +#include "Font.h" +#include "SimpleFontData.h" + +namespace WebCore { + +UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run, + const Font& font) + : UniscribeHelper(run.characters(), run.length(), run.rtl(), + font.primaryFont()->platformData().hfont(), + font.primaryFont()->platformData().scriptCache(), + font.primaryFont()->platformData().scriptFontProperties()) + , m_font(&font) + , m_fontIndex(0) +{ + setDirectionalOverride(run.directionalOverride()); + setLetterSpacing(font.letterSpacing()); + setSpaceWidth(font.spaceWidth()); + setWordSpacing(font.wordSpacing()); + setAscent(font.primaryFont()->ascent()); + + init(); + + // Padding is the amount to add to make justification happen. This + // should be done after Init() so all the runs are already measured. + if (run.padding() > 0) + justify(run.padding()); +} + +UniscribeHelperTextRun::UniscribeHelperTextRun( + const wchar_t* input, + int inputLength, + bool isRtl, + HFONT hfont, + SCRIPT_CACHE* scriptCache, + SCRIPT_FONTPROPERTIES* fontProperties) + : UniscribeHelper(input, inputLength, isRtl, hfont, + scriptCache, fontProperties) + , m_font(0) + , m_fontIndex(-1) +{ +} + +void UniscribeHelperTextRun::tryToPreloadFont(HFONT font) +{ + // Ask the browser to get the font metrics for this font. + // That will preload the font and it should now be accessible + // from the renderer. + ChromiumBridge::ensureFontLoaded(font); +} + +bool UniscribeHelperTextRun::nextWinFontData( + HFONT* hfont, + SCRIPT_CACHE** scriptCache, + SCRIPT_FONTPROPERTIES** fontProperties, + int* ascent) +{ + // This check is necessary because NextWinFontData can be called again + // after we already ran out of fonts. fontDataAt behaves in a strange + // manner when the difference between param passed and # of fonts stored in + // WebKit::Font is larger than one. We can avoid this check by setting + // font_index_ to # of elements in hfonts_ when we run out of font. In that + // case, we'd have to go through a couple of more checks before returning + // false. + if (m_fontIndex == -1 || !m_font) + return false; + + // If the font data for a fallback font requested is not yet retrieved, add + // them to our vectors. Note that '>' rather than '>=' is used to test that + // condition. primaryFont is not stored in hfonts_, and friends so that + // indices for fontDataAt and our vectors for font data are 1 off from each + // other. That is, when fully populated, hfonts_ and friends have one font + // fewer than what's contained in font_. + if (static_cast<size_t>(++m_fontIndex) > m_hfonts.size()) { + const FontData *fontData = m_font->fontDataAt(m_fontIndex); + if (!fontData) { + // Ran out of fonts. + m_fontIndex = -1; + return false; + } + + // FIXME: this won't work for SegmentedFontData + // http://crbug.com/6425 + const SimpleFontData* simpleFontData = + fontData->fontDataForCharacter(' '); + + m_hfonts.append(simpleFontData->platformData().hfont()); + m_scriptCaches.append(simpleFontData->platformData().scriptCache()); + m_fontProperties.append(simpleFontData->platformData().scriptFontProperties()); + m_ascents.append(simpleFontData->ascent()); + } + + *hfont = m_hfonts[m_fontIndex - 1]; + *scriptCache = m_scriptCaches[m_fontIndex - 1]; + *fontProperties = m_fontProperties[m_fontIndex - 1]; + *ascent = m_ascents[m_fontIndex - 1]; + return true; +} + +void UniscribeHelperTextRun::resetFontIndex() +{ + m_fontIndex = 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h new file mode 100644 index 0000000..b5c54a0 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UniscribeHelperTextRun_h +#define UniscribeHelperTextRun_h + +#include "UniscribeHelper.h" + +namespace WebCore { + +class Font; +class TextRun; + +// Wrapper around the Uniscribe helper that automatically sets it up with the +// WebKit types we supply. +class UniscribeHelperTextRun : public UniscribeHelper { +public: + // Regular constructor used for WebCore text run processing. + UniscribeHelperTextRun(const TextRun&, const Font&); + + // Constructor with the same interface as the gfx::UniscribeState. Using + // this constructor will not give you font fallback, but it will provide + // the ability to load fonts that may not be in the OS cache + // ("TryToPreloadFont") if the caller does not have a TextRun/Font. + UniscribeHelperTextRun(const wchar_t* input, + int inputLength, + bool isRtl, + HFONT hfont, + SCRIPT_CACHE*, + SCRIPT_FONTPROPERTIES*); + +protected: + virtual void tryToPreloadFont(HFONT); + +private: + // This function retrieves the Windows font data (HFONT, etc) for the next + // WebKit font in the list. If the font data corresponding to font_index_ + // has been obtained before, returns the values stored in our internal + // vectors (hfonts_, etc). Otherwise, it gets next SimpleFontData from + // WebKit and adds them to in hfonts_ and friends so that font data can be + // returned quickly next time they're requested. + virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent); + virtual void resetFontIndex(); + + // Reference to WebKit::Font that contains all the information about fonts + // we can use to render this input run of text. It is used in + // NextWinFontData to retrieve Windows font data for a series of + // non-primary fonts. + // + // This pointer can be NULL for no font fallback handling. + const Font* m_font; + + // It's rare that many fonts are listed in stylesheets. + // Four would be large enough in most cases. + const static size_t kNumberOfFonts = 4; + + // These vectors are used to store Windows font data for non-primary fonts. + Vector<HFONT, kNumberOfFonts> m_hfonts; + Vector<SCRIPT_CACHE*, kNumberOfFonts> m_scriptCaches; + Vector<SCRIPT_FONTPROPERTIES*, kNumberOfFonts> m_fontProperties; + Vector<int, kNumberOfFonts> m_ascents; + + // Index of the fallback font we're currently using for NextWinFontData. + int m_fontIndex; +}; + +} // namespace WebCore + +#endif // UniscribeHelperTextRun_h |