diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/third_party/WebKit/Source/platform/fonts | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/third_party/WebKit/Source/platform/fonts')
84 files changed, 3655 insertions, 6975 deletions
diff --git a/chromium/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h b/chromium/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h index f2648d2208c..2ff2121c02d 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/AlternateFontFamily.h @@ -36,10 +36,9 @@ namespace WebCore { -// We currently do not support bitmap fonts on windows (with GDI_FONTS_ON_WINDOWS enabled). +// We currently do not support bitmap fonts on windows. // Instead of trying to construct a bitmap font and then going down the fallback path map -// certain common bitmap fonts to their truetype equivalent up front. This also allows the -// GDI_FONTS_ON_WINDOWS disabled code path to match our current behavior. +// certain common bitmap fonts to their truetype equivalent up front. inline const AtomicString& adjustFamilyNameToAvoidUnsupportedFonts(const AtomicString& familyName) { #if OS(WIN) @@ -60,10 +59,12 @@ inline const AtomicString& adjustFamilyNameToAvoidUnsupportedFonts(const AtomicS return microsoftSans; // Alias 'MS Serif' (bitmap) -> 'Times New Roman' (truetype font). + // Alias 'Times' -> 'Times New Roman' (truetype font). // There's no 'Microsoft Sans Serif-equivalent' for Serif. DEFINE_STATIC_LOCAL(AtomicString, msSerif, ("MS Serif", AtomicString::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(AtomicString, times, ("Times", AtomicString::ConstructFromLiteral)); DEFINE_STATIC_LOCAL(AtomicString, timesNewRoman, ("Times New Roman", AtomicString::ConstructFromLiteral)); - if (equalIgnoringCase(familyName, msSerif)) + if (equalIgnoringCase(familyName, msSerif) || equalIgnoringCase(familyName, times)) return timesNewRoman; #endif @@ -107,18 +108,26 @@ inline const AtomicString& alternateFamilyName(const AtomicString& familyName) inline const AtomicString getFallbackFontFamily(const FontDescription& description) { - DEFINE_STATIC_LOCAL(const AtomicString, sansStr, ("Sans", AtomicString::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const AtomicString, serifStr, ("Serif", AtomicString::ConstructFromLiteral)); - DEFINE_STATIC_LOCAL(const AtomicString, monospaceStr, ("Monospace", AtomicString::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const AtomicString, sansStr, ("sans-serif", AtomicString::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const AtomicString, serifStr, ("serif", AtomicString::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const AtomicString, monospaceStr, ("monospace", AtomicString::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const AtomicString, cursiveStr, ("cursive", AtomicString::ConstructFromLiteral)); + DEFINE_STATIC_LOCAL(const AtomicString, fantasyStr, ("fantasy", AtomicString::ConstructFromLiteral)); switch (description.genericFamily()) { + case FontDescription::SansSerifFamily: + return sansStr; case FontDescription::SerifFamily: return serifStr; case FontDescription::MonospaceFamily: return monospaceStr; - case FontDescription::SansSerifFamily: + case FontDescription::CursiveFamily: + return cursiveStr; + case FontDescription::FantasyFamily: + return fantasyStr; default: - return sansStr; + // Let the caller use the system default font. + return emptyAtom; } } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/Character.cpp b/chromium/third_party/WebKit/Source/platform/fonts/Character.cpp new file mode 100644 index 00000000000..a9898c953b1 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/Character.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2014 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 "platform/fonts/Character.h" + +#include "platform/fonts/FontPlatformFeatures.h" +#include "wtf/StdLibExtras.h" +#include "wtf/text/StringBuilder.h" + +using namespace WTF; +using namespace Unicode; + +namespace WebCore { + +const uint8_t Character::s_roundingHackCharacterTable[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const UChar32 cjkIsolatedSymbolsArray[] = { + // 0x2C7 Caron, Mandarin Chinese 3rd Tone + 0x2C7, + // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone + 0x2CA, + // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone + 0x2CB, + // 0x2D9 Dot Above, Mandarin Chinese 5th Tone + 0x2D9, + 0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x2051, + 0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x2121, + 0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23CE, + 0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25B6, + 0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25CC, + 0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26BD, + 0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE12, + 0xFE19, 0xFF1D, + // Emoji. + 0x1F100 +}; + +// Takes a flattened list of closed intervals +template <class T, size_t size> +bool valueInIntervalList(const T (&intervalList)[size], const T& value) +{ + const T* bound = std::upper_bound(&intervalList[0], &intervalList[size], value); + if ((bound - intervalList) % 2 == 1) + return true; + return bound > intervalList && *(bound - 1) == value; +} + +CodePath Character::characterRangeCodePath(const UChar* characters, unsigned len) +{ + static const UChar complexCodePathRanges[] = { + // U+02E5 through U+02E9 (Modifier Letters : Tone letters) + 0x2E5, 0x2E9, + // U+0300 through U+036F Combining diacritical marks + 0x300, 0x36F, + // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, ... + 0x0591, 0x05BD, + // ... Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha + 0x05BF, 0x05CF, + // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic, + // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, + // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar + 0x0600, 0x109F, + // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left + // here if you precompose; Modern Korean will be precomposed as a result of step A) + 0x1100, 0x11FF, + // U+135D through U+135F Ethiopic combining marks + 0x135D, 0x135F, + // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian + 0x1700, 0x18AF, + // U+1900 through U+194F Limbu (Unicode 4.0) + 0x1900, 0x194F, + // U+1980 through U+19DF New Tai Lue + 0x1980, 0x19DF, + // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic + 0x1A00, 0x1CFF, + // U+1DC0 through U+1DFF Comining diacritical mark supplement + 0x1DC0, 0x1DFF, + // RIGHT-TO-LEFT MARK + 0x200B, 0x200F, + // RIGHT-TO-LEFT OVERRIDE + 0x202A, 0x202E, + // Nominal Digit Shape + 0x2060, 0x206F, + // U+20D0 through U+20FF Combining marks for symbols + 0x20D0, 0x20FF, + // U+2CEF through U+2CF1 Combining marks for Coptic + 0x2CEF, 0x2CF1, + // U+302A through U+302F Ideographic and Hangul Tone marks + 0x302A, 0x302F, + // U+A67C through U+A67D Combining marks for old Cyrillic + 0xA67C, 0xA67D, + // U+A6F0 through U+A6F1 Combining mark for Bamum + 0xA6F0, 0xA6F1, + // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended, + // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek + 0xA800, 0xABFF, + // U+D7B0 through U+D7FF Hangul Jamo Ext. B + 0xD7B0, 0xD7FF, + // U+FE00 through U+FE0F Unicode variation selectors + 0xFE00, 0xFE0F, + // U+FE20 through U+FE2F Combining half marks + 0xFE20, 0xFE2F + }; + + CodePath result = SimplePath; + for (unsigned i = 0; i < len; i++) { + const UChar c = characters[i]; + + // Shortcut for common case + if (c < 0x2E5) + continue; + + // U+1E00 through U+2000 characters with diacritics and stacked diacritics + if (c >= 0x1E00 && c <= 0x2000) { + result = SimpleWithGlyphOverflowPath; + continue; + } + + // Surrogate pairs + if (c > 0xD7FF && c <= 0xDBFF) { + if (i == len - 1) + continue; + + UChar next = characters[++i]; + if (!U16_IS_TRAIL(next)) + continue; + + UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next); + + if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols + continue; + if (supplementaryCharacter <= 0x1F1FF) + return ComplexPath; + + if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors. + continue; + if (supplementaryCharacter <= 0xE01EF) + return ComplexPath; + + // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts + // in plane 1 or higher. + + continue; + } + + // Search for other Complex cases + if (valueInIntervalList(complexCodePathRanges, c)) + return ComplexPath; + } + + return result; +} + +bool Character::isCJKIdeograph(UChar32 c) +{ + static const UChar32 cjkIdeographRanges[] = { + // CJK Radicals Supplement and Kangxi Radicals. + 0x2E80, 0x2FDF, + // CJK Strokes. + 0x31C0, 0x31EF, + // CJK Unified Ideographs Extension A. + 0x3400, 0x4DBF, + // The basic CJK Unified Ideographs block. + 0x4E00, 0x9FFF, + // CJK Compatibility Ideographs. + 0xF900, 0xFAFF, + // CJK Unified Ideographs Extension B. + 0x20000, 0x2A6DF, + // CJK Unified Ideographs Extension C. + // CJK Unified Ideographs Extension D. + 0x2A700, 0x2B81F, + // CJK Compatibility Ideographs Supplement. + 0x2F800, 0x2FA1F + }; + static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges); + + // Early out + if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCount - 1]) + return false; + + return valueInIntervalList(cjkIdeographRanges, c); +} + +bool Character::isCJKIdeographOrSymbol(UChar32 c) +{ + // Likely common case + if (c < 0x2C7) + return false; + + // Hash lookup for isolated symbols (those not part of a contiguous range) + static HashSet<UChar32>* cjkIsolatedSymbols = 0; + if (!cjkIsolatedSymbols) { + cjkIsolatedSymbols = new HashSet<UChar32>(); + for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i) + cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]); + } + if (cjkIsolatedSymbols->contains(c)) + return true; + + if (isCJKIdeograph(c)) + return true; + + static const UChar32 cjkSymbolRanges[] = { + 0x2156, 0x215A, + 0x2160, 0x216B, + 0x2170, 0x217B, + 0x23BE, 0x23CC, + 0x2460, 0x2492, + 0x249C, 0x24FF, + 0x25CE, 0x25D3, + 0x25E2, 0x25E6, + 0x2600, 0x2603, + 0x2660, 0x266F, + 0x2672, 0x267D, + 0x2776, 0x277F, + // Ideographic Description Characters, with CJK Symbols and Punctuation, excluding 0x3030. + // Then Hiragana 0x3040 .. 0x309F, Katakana 0x30A0 .. 0x30FF, Bopomofo 0x3100 .. 0x312F + 0x2FF0, 0x302F, + 0x3031, 0x312F, + // More Bopomofo and Bopomofo Extended 0x31A0 .. 0x31BF + 0x3190, 0x31BF, + // Enclosed CJK Letters and Months (0x3200 .. 0x32FF). + // CJK Compatibility (0x3300 .. 0x33FF). + 0x3200, 0x33FF, + 0xF860, 0xF862, + // CJK Compatibility Forms. + 0xFE30, 0xFE4F, + // Halfwidth and Fullwidth Forms + // Usually only used in CJK + 0xFF00, 0xFF0C, + 0xFF0E, 0xFF1A, + 0xFF1F, 0xFFEF, + // Emoji. + 0x1F110, 0x1F129, + 0x1F130, 0x1F149, + 0x1F150, 0x1F169, + 0x1F170, 0x1F189, + 0x1F200, 0x1F6FF + }; + + return valueInIntervalList(cjkSymbolRanges, c); +} + +unsigned Character::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion) +{ + unsigned count = 0; + if (direction == LTR) { + for (size_t i = 0; i < length; ++i) { + if (treatAsSpace(characters[i])) { + count++; + isAfterExpansion = true; + } else { + isAfterExpansion = false; + } + } + } else { + for (size_t i = length; i > 0; --i) { + if (treatAsSpace(characters[i - 1])) { + count++; + isAfterExpansion = true; + } else { + isAfterExpansion = false; + } + } + } + return count; +} + +unsigned Character::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion) +{ + static bool expandAroundIdeographs = FontPlatformFeatures::canExpandAroundIdeographsInComplexText(); + unsigned count = 0; + if (direction == LTR) { + for (size_t i = 0; i < length; ++i) { + UChar32 character = characters[i]; + if (treatAsSpace(character)) { + count++; + isAfterExpansion = true; + continue; + } + if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) { + character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]); + i++; + } + if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { + if (!isAfterExpansion) + count++; + count++; + isAfterExpansion = true; + continue; + } + isAfterExpansion = false; + } + } else { + for (size_t i = length; i > 0; --i) { + UChar32 character = characters[i - 1]; + if (treatAsSpace(character)) { + count++; + isAfterExpansion = true; + continue; + } + if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) { + character = U16_GET_SUPPLEMENTARY(characters[i - 2], character); + i--; + } + if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { + if (!isAfterExpansion) + count++; + count++; + isAfterExpansion = true; + continue; + } + isAfterExpansion = false; + } + } + return count; +} + +bool Character::canReceiveTextEmphasis(UChar32 c) +{ + CharCategory category = Unicode::category(c); + if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format)) + return false; + + // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010. + if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot + || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar) + return false; + + return true; +} + +template <typename CharacterType> +static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length) +{ + StringBuilder normalized; + normalized.reserveCapacity(length); + + for (unsigned i = 0; i < length; ++i) + normalized.append(Character::normalizeSpaces(characters[i])); + + return normalized.toString(); +} + +String Character::normalizeSpaces(const LChar* characters, unsigned length) +{ + return normalizeSpacesInternal(characters, length); +} + +String Character::normalizeSpaces(const UChar* characters, unsigned length) +{ + return normalizeSpacesInternal(characters, length); +} + +} diff --git a/chromium/third_party/WebKit/Source/platform/fonts/Character.h b/chromium/third_party/WebKit/Source/platform/fonts/Character.h new file mode 100644 index 00000000000..bbe0433f369 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/Character.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014 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 Character_h +#define Character_h + +#include "platform/PlatformExport.h" +#include "platform/text/TextDirection.h" +#include "platform/text/TextPath.h" +#include "wtf/HashSet.h" +#include "wtf/text/WTFString.h" +#include "wtf/unicode/CharacterNames.h" + +namespace WebCore { + +class PLATFORM_EXPORT Character { +public: + static CodePath characterRangeCodePath(const LChar*, unsigned) { return SimplePath; } + static CodePath characterRangeCodePath(const UChar*, unsigned len); + + static bool isCJKIdeograph(UChar32); + static bool isCJKIdeographOrSymbol(UChar32); + + static unsigned expansionOpportunityCount(const LChar*, size_t length, TextDirection, bool& isAfterExpansion); + static unsigned expansionOpportunityCount(const UChar*, size_t length, TextDirection, bool& isAfterExpansion); + + static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; } + static bool treatAsZeroWidthSpace(UChar c) { return treatAsZeroWidthSpaceInComplexScript(c) || c == 0x200c || c == 0x200d; } + static bool treatAsZeroWidthSpaceInComplexScript(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || c == zeroWidthSpace || (c >= 0x200e && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == zeroWidthNoBreakSpace || c == objectReplacementCharacter; } + static bool canReceiveTextEmphasis(UChar32); + + static inline UChar normalizeSpaces(UChar character) + { + if (treatAsSpace(character)) + return space; + + if (treatAsZeroWidthSpace(character)) + return zeroWidthSpace; + + return character; + } + + static String normalizeSpaces(const LChar*, unsigned length); + static String normalizeSpaces(const UChar*, unsigned length); + + static bool isRoundingHackCharacter(UChar32 c) + { + return !(c & ~0xFF) && s_roundingHackCharacterTable[c]; + } + +private: + Character(); + + static const uint8_t s_roundingHackCharacterTable[256]; +}; + +} + +#endif diff --git a/chromium/third_party/WebKit/Source/platform/fonts/CustomFontData.h b/chromium/third_party/WebKit/Source/platform/fonts/CustomFontData.h index cb69f5a0c41..f1b5ddaae8d 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/CustomFontData.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/CustomFontData.h @@ -29,7 +29,6 @@ namespace WebCore { -class CSSFontFaceSource; struct GlyphData; class GlyphPage; class SimpleFontData; @@ -37,16 +36,15 @@ struct WidthIterator; class PLATFORM_EXPORT CustomFontData : public RefCounted<CustomFontData> { public: - static PassRefPtr<CustomFontData> create(bool isLoadingFallback = false) - { - return adoptRef(new CustomFontData(isLoadingFallback)); - } + static PassRefPtr<CustomFontData> create() { return adoptRef(new CustomFontData()); } virtual ~CustomFontData() { } virtual void beginLoadIfNeeded() const { }; - bool isLoading() const { return m_isLoadingFallback && m_isUsed; } - bool isLoadingFallback() const { return m_isLoadingFallback; } + virtual bool isLoading() const { return false; } + virtual bool isLoadingFallback() const { return false; } + virtual bool shouldSkipDrawing() const { return false; } + virtual void clearFontFaceSource() { } virtual bool isSVGFont() const { return false; } virtual void initializeFontData(SimpleFontData*, float) { } @@ -54,18 +52,8 @@ public: virtual bool fillSVGGlyphPage(GlyphPage*, unsigned, unsigned, UChar*, unsigned, const SimpleFontData*) const { return false; } virtual bool applySVGGlyphSelection(WidthIterator&, GlyphData&, bool, int, unsigned&) const { return false; } - virtual void setCSSFontFaceSource(CSSFontFaceSource* source) { ASSERT_NOT_REACHED(); } - virtual void clearCSSFontFaceSource() { } - protected: - CustomFontData(bool isLoadingFallback) - : m_isLoadingFallback(isLoadingFallback) - , m_isUsed(false) - { - } - - bool m_isLoadingFallback; // Whether or not this is a temporary font data for a custom font which is not yet loaded. - mutable bool m_isUsed; + CustomFontData() { } }; } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp b/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp index e0dfa3d0383..73a7d878c71 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/Font.cpp @@ -24,104 +24,46 @@ #include "config.h" #include "platform/fonts/Font.h" +#include "platform/LayoutUnit.h" +#include "platform/fonts/Character.h" +#include "platform/fonts/FontCache.h" +#include "platform/fonts/FontFallbackList.h" +#include "platform/fonts/FontPlatformFeatures.h" +#include "platform/fonts/GlyphBuffer.h" +#include "platform/fonts/GlyphPageTreeNode.h" +#include "platform/fonts/SimpleFontData.h" #include "platform/fonts/WidthIterator.h" #include "platform/geometry/FloatRect.h" #include "platform/text/TextRun.h" #include "wtf/MainThread.h" #include "wtf/StdLibExtras.h" -#include "wtf/text/StringBuilder.h" +#include "wtf/unicode/CharacterNames.h" +#include "wtf/unicode/Unicode.h" using namespace WTF; using namespace Unicode; - -namespace WTF { - -// allow compilation of OwnPtr<TextLayout> in source files that don't have access to the TextLayout class definition -void OwnedPtrDeleter<WebCore::TextLayout>::deletePtr(WebCore::TextLayout* ptr) -{ - WebCore::Font::deleteLayout(ptr); -} - -} +using namespace std; namespace WebCore { -const uint8_t Font::s_roundingHackCharacterTable[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const UChar32 cjkIsolatedSymbolsArray[] = { - // 0x2C7 Caron, Mandarin Chinese 3rd Tone - 0x2C7, - // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone - 0x2CA, - // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone - 0x2CB, - // 0x2D9 Dot Above, Mandarin Chinese 5th Tone - 0x2D9, - 0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x2051, - 0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x2121, - 0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23CE, - 0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25B6, - 0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25CC, - 0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26BD, - 0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE12, - 0xFE19, 0xFF1D, - // Emoji. - 0x1F100 -}; - -Font::CodePath Font::s_codePath = Auto; - -TypesettingFeatures Font::s_defaultTypesettingFeatures = 0; +CodePath Font::s_codePath = AutoPath; // ============================================================================================ // Font Implementation (Cross-Platform Portion) // ============================================================================================ Font::Font() - : m_letterSpacing(0) - , m_wordSpacing(0) - , m_isPlatformFont(false) - , m_typesettingFeatures(0) { } -Font::Font(const FontDescription& fd, float letterSpacing, float wordSpacing) +Font::Font(const FontDescription& fd) : m_fontDescription(fd) - , m_letterSpacing(letterSpacing) - , m_wordSpacing(wordSpacing) - , m_isPlatformFont(false) - , m_typesettingFeatures(computeTypesettingFeatures()) -{ -} - -Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode) - : m_fontFallbackList(FontFallbackList::create()) - , m_letterSpacing(0) - , m_wordSpacing(0) - , m_isPlatformFont(true) - , m_typesettingFeatures(computeTypesettingFeatures()) { - m_fontDescription.setUsePrinterFont(isPrinterFont); - m_fontDescription.setFontSmoothing(fontSmoothingMode); - m_fontFallbackList->setPlatformFont(fontData); } Font::Font(const Font& other) : m_fontDescription(other.m_fontDescription) , m_fontFallbackList(other.m_fontFallbackList) - , m_letterSpacing(other.m_letterSpacing) - , m_wordSpacing(other.m_wordSpacing) - , m_isPlatformFont(other.m_isPlatformFont) - , m_typesettingFeatures(computeTypesettingFeatures()) { } @@ -129,10 +71,6 @@ Font& Font::operator=(const Font& other) { m_fontDescription = other.m_fontDescription; m_fontFallbackList = other.m_fontFallbackList; - m_letterSpacing = other.m_letterSpacing; - m_wordSpacing = other.m_wordSpacing; - m_isPlatformFont = other.m_isPlatformFont; - m_typesettingFeatures = other.m_typesettingFeatures; return *this; } @@ -148,13 +86,11 @@ bool Font::operator==(const Font& other) const return first == second && m_fontDescription == other.m_fontDescription - && m_letterSpacing == other.m_letterSpacing - && m_wordSpacing == other.m_wordSpacing && (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() : 0) && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0); } -void Font::update(PassRefPtr<FontSelector> fontSelector) const +void Font::update(PassRefPtrWillBeRawPtr<FontSelector> fontSelector) const { // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up // being reasonably safe (because inherited fonts in the render tree pick up the new @@ -164,7 +100,6 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const if (!m_fontFallbackList) m_fontFallbackList = FontFallbackList::create(); m_fontFallbackList->invalidate(fontSelector); - m_typesettingFeatures = computeTypesettingFeatures(); } void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const @@ -172,15 +107,15 @@ void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, c // Don't draw anything while we are using custom fonts that are in the process of loading, // except if the 'force' argument is set to true (in which case it will use a fallback // font). - if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady) + if (shouldSkipDrawing() && customFontNotReadyAction == DoNotPaintIfFontNotReady) return; CodePath codePathToUse = codePath(runInfo.run); // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050 - if (codePathToUse != Complex && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length())) - codePathToUse = Complex; + if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length())) + codePathToUse = ComplexPath; - if (codePathToUse != Complex) + if (codePathToUse != ComplexPath) return drawSimpleText(context, runInfo, point); return drawComplexText(context, runInfo, point); @@ -188,92 +123,100 @@ void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, c void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const { - if (loadingCustomFonts()) + if (shouldSkipDrawing()) return; CodePath codePathToUse = codePath(runInfo.run); // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050 - if (codePathToUse != Complex && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length())) - codePathToUse = Complex; + if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length())) + codePathToUse = ComplexPath; - if (codePathToUse != Complex) + if (codePathToUse != ComplexPath) drawEmphasisMarksForSimpleText(context, runInfo, mark, point); else drawEmphasisMarksForComplexText(context, runInfo, mark, point); } +static inline void updateGlyphOverflowFromBounds(const IntRectExtent& glyphBounds, + const FontMetrics& fontMetrics, GlyphOverflow* glyphOverflow) +{ + glyphOverflow->top = max<int>(glyphOverflow->top, + glyphBounds.top() - (glyphOverflow->computeBounds ? 0 : fontMetrics.ascent())); + glyphOverflow->bottom = max<int>(glyphOverflow->bottom, + glyphBounds.bottom() - (glyphOverflow->computeBounds ? 0 : fontMetrics.descent())); + glyphOverflow->left = glyphBounds.left(); + glyphOverflow->right = glyphBounds.right(); +} + float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const { CodePath codePathToUse = codePath(run); - if (codePathToUse != Complex) { + if (codePathToUse != ComplexPath) { // The complex path is more restrictive about returning fallback fonts than the simple path, so we need an explicit test to make their behaviors match. - if (!canReturnFallbackFontsForComplexText()) + if (!FontPlatformFeatures::canReturnFallbackFontsForComplexText()) fallbackFonts = 0; // The simple path can optimize the case where glyph overflow is not observable. - if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds)) + if (codePathToUse != SimpleWithGlyphOverflowPath && (glyphOverflow && !glyphOverflow->computeBounds)) glyphOverflow = 0; } - bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures); - bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing(); - float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow); - if (cacheEntry && !std::isnan(*cacheEntry)) - return *cacheEntry; + bool hasKerningOrLigatures = fontDescription().typesettingFeatures() & (Kerning | Ligatures); + bool hasWordSpacingOrLetterSpacing = fontDescription().wordSpacing() || fontDescription().letterSpacing(); + bool isCacheable = (codePathToUse == ComplexPath || hasKerningOrLigatures) + && !hasWordSpacingOrLetterSpacing // Word spacing and letter spacing can change the width of a word. + && !run.allowTabs(); // If we allow tabs and a tab occurs inside a word, the width of the word varies based on its position on the line. + + WidthCacheEntry* cacheEntry = isCacheable + ? m_fontFallbackList->widthCache().add(run, WidthCacheEntry()) + : 0; + if (cacheEntry && cacheEntry->isValid()) { + if (glyphOverflow) + updateGlyphOverflowFromBounds(cacheEntry->glyphBounds, fontMetrics(), glyphOverflow); + return cacheEntry->width; + } float result; - if (codePathToUse == Complex) - result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow); - else - result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow); + IntRectExtent glyphBounds; + if (codePathToUse == ComplexPath) { + result = floatWidthForComplexText(run, fallbackFonts, &glyphBounds); + } else { + result = floatWidthForSimpleText(run, fallbackFonts, + glyphOverflow || isCacheable ? &glyphBounds : 0); + } + + if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) { + cacheEntry->glyphBounds = glyphBounds; + cacheEntry->width = result; + } - if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) - *cacheEntry = result; + if (glyphOverflow) + updateGlyphOverflowFromBounds(glyphBounds, fontMetrics(), glyphOverflow); return result; } -float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const +float Font::width(const TextRun& run, int& charsConsumed, Glyph& glyphId) const { #if ENABLE(SVG_FONTS) if (TextRun::RenderingContext* renderingContext = run.renderingContext()) - return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName); + return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphId); #endif charsConsumed = run.length(); - glyphName = ""; + glyphId = 0; return width(run); } -#if !OS(MACOSX) - -PassOwnPtr<TextLayout> Font::createLayoutForMacComplexText(const TextRun&, unsigned, float, bool) const -{ - ASSERT_NOT_REACHED(); - return nullptr; -} - -void Font::deleteLayout(TextLayout*) -{ -} - -float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*>*) -{ - ASSERT_NOT_REACHED(); - return 0; -} - -#endif - -FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const +FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to, bool accountForGlyphBounds) const { to = (to == -1 ? run.length() : to); CodePath codePathToUse = codePath(run); // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050 - if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.length())) - codePathToUse = Complex; + if (codePathToUse != ComplexPath && fontDescription().typesettingFeatures() && (from || to != run.length())) + codePathToUse = ComplexPath; - if (codePathToUse != Complex) - return selectionRectForSimpleText(run, point, h, from, to); + if (codePathToUse != ComplexPath) + return selectionRectForSimpleText(run, point, h, from, to, accountForGlyphBounds); return selectionRectForComplexText(run, point, h, from, to); } @@ -281,417 +224,637 @@ FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const { // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050 - if (codePath(run) != Complex && !typesettingFeatures()) + if (codePath(run) != ComplexPath && !fontDescription().typesettingFeatures()) return offsetForPositionForSimpleText(run, x, includePartialGlyphs); return offsetForPositionForComplexText(run, x, includePartialGlyphs); } -template <typename CharacterType> -static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length) +void Font::setCodePath(CodePath p) +{ + s_codePath = p; +} + +CodePath Font::codePath() { - StringBuilder normalized; - normalized.reserveCapacity(length); + return s_codePath; +} - for (unsigned i = 0; i < length; ++i) - normalized.append(Font::normalizeSpaces(characters[i])); +CodePath Font::codePath(const TextRun& run) const +{ + if (s_codePath != AutoPath) + return s_codePath; - return normalized.toString(); +#if ENABLE(SVG_FONTS) + if (run.renderingContext()) + return SimplePath; +#endif + + if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0 && m_fontDescription.letterSpacing() == 0) + return ComplexPath; + + if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this)) + return ComplexPath; + + if (!run.characterScanForCodePath()) + return SimplePath; + + if (run.is8Bit()) + return SimplePath; + + // Start from 0 since drawing and highlighting also measure the characters before run->from. + return Character::characterRangeCodePath(run.characters16(), run.length()); } -String Font::normalizeSpaces(const LChar* characters, unsigned length) +void Font::willUseFontData(UChar32 character) const { - return normalizeSpacesInternal(characters, length); + const FontFamily& family = fontDescription().family(); + if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty()) + m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family(), character); } -String Font::normalizeSpaces(const UChar* characters, unsigned length) +static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound) { - return normalizeSpacesInternal(characters, length); + return character >= lowerBound && character <= upperBound; } -static bool shouldUseFontSmoothing = true; +static bool shouldIgnoreRotation(UChar32 character) +{ + if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE) + return true; -void Font::setShouldUseSmoothing(bool shouldUseSmoothing) + if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE) + return true; + + if (isInRange(character, 0x002E5, 0x002EB)) + return true; + + if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF)) + return true; + + if (character == 0x02016 || character == 0x02018 || character == 0x02019 || character == 0x02020 || character == 0x02021 + || character == 0x2030 || character == 0x02031) + return true; + + if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047 + || character == 0x02048 || character == 0x02049 || character == 0x2051) + return true; + + if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0) + || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117) + || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F)) + return true; + + if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D + || isInRange(character, 0x0214F, 0x0218F)) + return true; + + if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F) + || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A) + || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF) + || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF)) + return true; + + if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767) + || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F) + || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007)) + return true; + + if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F) + || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB) + || isInRange(character, 0x030FD, 0x0A4CF)) + return true; + + if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F) + || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF)) + return true; + + if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48) + || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62) + || isInRange(character, 0x0FE67, 0x0FE6F)) + return true; + + if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C) + || isInRange(character, 0x0FF0E, 0x0FF19) || isInRange(character, 0x0FF1F, 0x0FF3A)) + return true; + + if (character == 0x0FF3C || character == 0x0FF3E) + return true; + + if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2) + || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8) + || character == 0x0FFFD) + return true; + + if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF) + || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F) + || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F)) + return true; + + if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD)) + return true; + + return false; +} + +static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, GlyphData& data, GlyphPage* page, unsigned pageNumber) +{ + if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) { + RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientationFontData(); + GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData.get(), pageNumber); + GlyphPage* uprightPage = uprightNode->page(); + if (uprightPage) { + GlyphData uprightData = uprightPage->glyphDataForCharacter(character); + // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright. + if (data.glyph == uprightData.glyph) + return make_pair(data, page); + // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that + // glyph, so we fall back to the upright data and use the horizontal glyph. + if (uprightData.fontData) + return make_pair(uprightData, uprightPage); + } + } else if (orientation == NonCJKGlyphOrientationVerticalRight) { + RefPtr<SimpleFontData> verticalRightFontData = data.fontData->verticalRightOrientationFontData(); + GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData.get(), pageNumber); + GlyphPage* verticalRightPage = verticalRightNode->page(); + if (verticalRightPage) { + GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(character); + // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked + // into it. + if (data.glyph != verticalRightData.glyph) + return make_pair(data, page); + // The glyphs are identical, meaning that we should just use the horizontal glyph. + if (verticalRightData.fontData) + return make_pair(verticalRightData, verticalRightPage); + } + } + return make_pair(data, page); +} + +std::pair<GlyphData, GlyphPage*> Font::glyphDataAndPageForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const { ASSERT(isMainThread()); - shouldUseFontSmoothing = shouldUseSmoothing; + + if (variant == AutoVariant) { + if (m_fontDescription.variant() == FontVariantSmallCaps && !primaryFont()->isSVGFont()) { + UChar32 upperC = toUpper(c); + if (upperC != c) { + c = upperC; + variant = SmallCapsVariant; + } else { + variant = NormalVariant; + } + } else { + variant = NormalVariant; + } + } + + if (mirror) + c = mirroredChar(c); + + unsigned pageNumber = (c / GlyphPage::size); + + GlyphPageTreeNode* node = pageNumber ? m_fontFallbackList->m_pages.get(pageNumber) : m_fontFallbackList->m_pageZero; + if (!node) { + node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); + if (pageNumber) + m_fontFallbackList->m_pages.set(pageNumber, node); + else + m_fontFallbackList->m_pageZero = node; + } + + GlyphPage* page = 0; + if (variant == NormalVariant) { + // Fastest loop, for the common case (normal variant). + while (true) { + page = node->page(); + if (page) { + GlyphData data = page->glyphDataForCharacter(c); + if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback())) + return make_pair(data, page); + + if (data.fontData) { + if (Character::isCJKIdeographOrSymbol(c)) { + if (!data.fontData->hasVerticalGlyphs()) { + // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs + // to make sure you get a square (even for broken glyphs like symbols used for punctuation). + variant = BrokenIdeographVariant; + break; + } + } else { + return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, page, pageNumber); + } + + return make_pair(data, page); + } + + if (node->isSystemFallback()) + break; + } + + // Proceed with the fallback list. + node = node->getChild(fontDataAt(node->level()), pageNumber); + if (pageNumber) + m_fontFallbackList->m_pages.set(pageNumber, node); + else + m_fontFallbackList->m_pageZero = node; + } + } + if (variant != NormalVariant) { + while (true) { + page = node->page(); + if (page) { + GlyphData data = page->glyphDataForCharacter(c); + if (data.fontData) { + // The variantFontData function should not normally return 0. + // But if it does, we will just render the capital letter big. + RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(m_fontDescription, variant); + if (!variantFontData) + return make_pair(data, page); + + GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData.get(), pageNumber); + GlyphPage* variantPage = variantNode->page(); + if (variantPage) { + GlyphData data = variantPage->glyphDataForCharacter(c); + if (data.fontData) + return make_pair(data, variantPage); + } + + // Do not attempt system fallback off the variantFontData. This is the very unlikely case that + // a font has the lowercase character but the small caps font does not have its uppercase version. + return make_pair(variantFontData->missingGlyphData(), page); + } + + if (node->isSystemFallback()) + break; + } + + // Proceed with the fallback list. + node = node->getChild(fontDataAt(node->level()), pageNumber); + if (pageNumber) + m_fontFallbackList->m_pages.set(pageNumber, node); + else + m_fontFallbackList->m_pageZero = node; + } + } + + ASSERT(page); + ASSERT(node->isSystemFallback()); + + // System fallback is character-dependent. When we get here, we + // know that the character in question isn't in the system fallback + // font's glyph page. Try to lazily create it here. + + // FIXME: Unclear if this should normalizeSpaces above 0xFFFF. + // Doing so changes fast/text/international/plane2-diffs.html + UChar32 characterToRender = c; + if (characterToRender <= 0xFFFF) + characterToRender = Character::normalizeSpaces(characterToRender); + const SimpleFontData* fontDataToSubstitute = fontDataAt(0)->fontDataForCharacter(characterToRender); + RefPtr<SimpleFontData> characterFontData = FontCache::fontCache()->fallbackFontForCharacter(m_fontDescription, characterToRender, fontDataToSubstitute); + if (characterFontData) { + if (characterFontData->platformData().orientation() == Vertical && !characterFontData->hasVerticalGlyphs() && Character::isCJKIdeographOrSymbol(c)) + variant = BrokenIdeographVariant; + if (variant != NormalVariant) + characterFontData = characterFontData->variantFontData(m_fontDescription, variant); + } + if (characterFontData) { + // Got the fallback glyph and font. + GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData.get(), pageNumber)->page(); + GlyphData data = fallbackPage && fallbackPage->glyphForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); + // Cache it so we don't have to do system fallback again next time. + if (variant == NormalVariant) { + page->setGlyphDataForCharacter(c, data.glyph, data.fontData); + data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level())); + if (!Character::isCJKIdeographOrSymbol(c) && data.fontData->platformData().orientation() != Horizontal && !data.fontData->isTextOrientationFallback()) + return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, page, pageNumber); + } + return make_pair(data, page); + } + + // Even system fallback can fail; use the missing glyph in that case. + // FIXME: It would be nicer to use the missing glyph from the last resort font instead. + GlyphData data = primaryFont()->missingGlyphData(); + if (variant == NormalVariant) { + page->setGlyphDataForCharacter(c, data.glyph, data.fontData); + data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level())); + } + return make_pair(data, page); } -bool Font::shouldUseSmoothing() +bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const { - return shouldUseFontSmoothing; + unsigned pageNumber = (character / GlyphPage::size); + + GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber); + GlyphPage* page = node->page(); + + return page && page->glyphForCharacter(character); } -void Font::setCodePath(CodePath p) +// FIXME: This function may not work if the emphasis mark uses a complex script, but none of the +// standard emphasis marks do so. +bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const { - s_codePath = p; + if (mark.isEmpty()) + return false; + + UChar32 character = mark[0]; + + if (U16_IS_SURROGATE(character)) { + if (!U16_IS_SURROGATE_LEAD(character)) + return false; + + if (mark.length() < 2) + return false; + + UChar low = mark[1]; + if (!U16_IS_TRAIL(low)) + return false; + + character = U16_GET_SUPPLEMENTARY(character, low); + } + + glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant); + return true; } -Font::CodePath Font::codePath() +int Font::emphasisMarkAscent(const AtomicString& mark) const { - return s_codePath; + FontCachePurgePreventer purgePreventer; + + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return 0; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return 0; + + return markFontData->fontMetrics().ascent(); } -void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures) +int Font::emphasisMarkDescent(const AtomicString& mark) const { - s_defaultTypesettingFeatures = typesettingFeatures; + FontCachePurgePreventer purgePreventer; + + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return 0; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return 0; + + return markFontData->fontMetrics().descent(); } -TypesettingFeatures Font::defaultTypesettingFeatures() +int Font::emphasisMarkHeight(const AtomicString& mark) const { - return s_defaultTypesettingFeatures; + FontCachePurgePreventer purgePreventer; + + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return 0; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return 0; + + return markFontData->fontMetrics().height(); } -Font::CodePath Font::codePath(const TextRun& run) const +float Font::getGlyphsAndAdvancesForSimpleText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { - if (s_codePath != Auto) - return s_codePath; + float initialAdvance; -#if ENABLE(SVG_FONTS) - if (run.renderingContext()) - return Simple; -#endif + WidthIterator it(this, runInfo.run, 0, false, forTextEmphasis); + // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or + // ligatures are enabled. + GlyphBuffer localGlyphBuffer; + it.advance(runInfo.from, &localGlyphBuffer); + float beforeWidth = it.m_runWidthSoFar; + it.advance(runInfo.to, &glyphBuffer); - if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0) - return Complex; + if (glyphBuffer.isEmpty()) + return 0; - if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this)) - return Complex; + float afterWidth = it.m_runWidthSoFar; - if (!run.characterScanForCodePath()) - return Simple; + if (runInfo.run.rtl()) { + float finalRoundingWidth = it.m_finalRoundingWidth; + it.advance(runInfo.run.length(), &localGlyphBuffer); + initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth; + glyphBuffer.reverse(); + } else { + initialAdvance = beforeWidth; + } - if (run.is8Bit()) - return Simple; + return initialAdvance; +} - // Start from 0 since drawing and highlighting also measure the characters before run->from. - return characterRangeCodePath(run.characters16(), run.length()); -} - -static inline UChar keyExtractorUChar(const UChar* value) -{ - return *value; -} - -static inline UChar32 keyExtractorUChar32(const UChar32* value) -{ - return *value; -} - -Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len) -{ - static const UChar complexCodePathRanges[] = { - // U+02E5 through U+02E9 (Modifier Letters : Tone letters) - 0x2E5, 0x2E9, - // U+0300 through U+036F Combining diacritical marks - 0x300, 0x36F, - // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, ... - 0x0591, 0x05BD, - // ... Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha - 0x05BF, 0x05CF, - // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic, - // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, - // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar - 0x0600, 0x109F, - // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left - // here if you precompose; Modern Korean will be precomposed as a result of step A) - 0x1100, 0x11FF, - // U+135D through U+135F Ethiopic combining marks - 0x135D, 0x135F, - // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian - 0x1700, 0x18AF, - // U+1900 through U+194F Limbu (Unicode 4.0) - 0x1900, 0x194F, - // U+1980 through U+19DF New Tai Lue - 0x1980, 0x19DF, - // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic - 0x1A00, 0x1CFF, - // U+1DC0 through U+1DFF Comining diacritical mark supplement - 0x1DC0, 0x1DFF, - // U+20D0 through U+20FF Combining marks for symbols - 0x20D0, 0x20FF, - // U+2CEF through U+2CF1 Combining marks for Coptic - 0x2CEF, 0x2CF1, - // U+302A through U+302F Ideographic and Hangul Tone marks - 0x302A, 0x302F, - // U+A67C through U+A67D Combining marks for old Cyrillic - 0xA67C, 0xA67D, - // U+A6F0 through U+A6F1 Combining mark for Bamum - 0xA6F0, 0xA6F1, - // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended, - // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek - 0xA800, 0xABFF, - // U+D7B0 through U+D7FF Hangul Jamo Ext. B - 0xD7B0, 0xD7FF, - // U+FE00 through U+FE0F Unicode variation selectors - 0xFE00, 0xFE0F, - // U+FE20 through U+FE2F Combining half marks - 0xFE20, 0xFE2F - }; - static size_t complexCodePathRangesCount = WTF_ARRAY_LENGTH(complexCodePathRanges); - - CodePath result = Simple; - for (unsigned i = 0; i < len; i++) { - const UChar c = characters[i]; - - // Shortcut for common case - if (c < 0x2E5) - continue; - - // U+1E00 through U+2000 characters with diacritics and stacked diacritics - if (c >= 0x1E00 && c <= 0x2000) { - result = SimpleWithGlyphOverflow; - continue; - } +void Font::drawSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point) const +{ + // This glyph buffer holds our glyphs+advances+font data for each glyph. + GlyphBuffer glyphBuffer; - // Surrogate pairs - if (c > 0xD7FF && c <= 0xDBFF) { - if (i == len - 1) - continue; + float startX = point.x() + getGlyphsAndAdvancesForSimpleText(runInfo, glyphBuffer); - UChar next = characters[++i]; - if (!U16_IS_TRAIL(next)) - continue; + if (glyphBuffer.isEmpty()) + return; - UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next); + FloatPoint startPoint(startX, point.y()); + drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint); +} - if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols - continue; - if (supplementaryCharacter <= 0x1F1FF) - return Complex; +void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const +{ + GlyphBuffer glyphBuffer; + float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo, glyphBuffer, ForTextEmphasis); - if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors. - continue; - if (supplementaryCharacter <= 0xE01EF) - return Complex; + if (glyphBuffer.isEmpty()) + return; - // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts - // in plane 1 or higher. + drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); +} - continue; - } +void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const +{ + // Draw each contiguous run of glyphs that use the same font data. + const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); + FloatPoint startPoint(point); + FloatPoint nextPoint = startPoint + glyphBuffer.advanceAt(0); + unsigned lastFrom = 0; + unsigned nextGlyph = 1; +#if ENABLE(SVG_FONTS) + TextRun::RenderingContext* renderingContext = runInfo.run.renderingContext(); +#endif + while (nextGlyph < glyphBuffer.size()) { + const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); - // Search for other Complex cases - UChar* boundingCharacter = approximateBinarySearch<UChar, UChar>( - (UChar*)complexCodePathRanges, complexCodePathRangesCount, c, keyExtractorUChar); - // Exact matches are complex - if (*boundingCharacter == c) - return Complex; - bool isEndOfRange = ((boundingCharacter - complexCodePathRanges) % 2); - if (*boundingCharacter < c) { - // Determine if we are in a range or out - if (!isEndOfRange) - return Complex; - continue; + if (nextFontData != fontData) { +#if ENABLE(SVG_FONTS) + if (renderingContext && fontData->isSVGFont()) + renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); + else +#endif + drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); + + lastFrom = nextGlyph; + fontData = nextFontData; + startPoint = nextPoint; } - ASSERT(*boundingCharacter > c); - // Determine if we are in a range or out - opposite condition to above - if (isEndOfRange) - return Complex; + nextPoint += glyphBuffer.advanceAt(nextGlyph); + nextGlyph++; } - return result; +#if ENABLE(SVG_FONTS) + if (renderingContext && fontData->isSVGFont()) + renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); + else +#endif + drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); } -bool Font::isCJKIdeograph(UChar32 c) -{ - static const UChar32 cjkIdeographRanges[] = { - // CJK Radicals Supplement and Kangxi Radicals. - 0x2E80, 0x2FDF, - // CJK Strokes. - 0x31C0, 0x31EF, - // CJK Unified Ideographs Extension A. - 0x3400, 0x4DBF, - // The basic CJK Unified Ideographs block. - 0x4E00, 0x9FFF, - // CJK Compatibility Ideographs. - 0xF900, 0xFAFF, - // CJK Unified Ideographs Extension B. - 0x20000, 0x2A6DF, - // CJK Unified Ideographs Extension C. - // CJK Unified Ideographs Extension D. - 0x2A700, 0x2B81F, - // CJK Compatibility Ideographs Supplement. - 0x2F800, 0x2FA1F - }; - static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges); - - // Early out - if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCount - 1]) - return false; +inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) +{ + if (fontData->platformData().orientation() == Horizontal) { + FloatRect bounds = fontData->boundsForGlyph(glyph); + return bounds.x() + bounds.width() / 2; + } + // FIXME: Use glyph bounds once they make sense for vertical fonts. + return fontData->widthForGlyph(glyph) / 2; +} - UChar32* boundingCharacter = approximateBinarySearch<UChar32, UChar32>( - (UChar32*)cjkIdeographRanges, cjkIdeographRangesCount, c, keyExtractorUChar32); - // Exact matches are CJK - if (*boundingCharacter == c) - return true; - bool isEndOfRange = ((boundingCharacter - cjkIdeographRanges) % 2); - if (*boundingCharacter < c) - return !isEndOfRange; - return isEndOfRange; +inline static float offsetToMiddleOfAdvanceAtIndex(const GlyphBuffer& glyphBuffer, size_t i) +{ + return glyphBuffer.advanceAt(i).width() / 2; } -bool Font::isCJKIdeographOrSymbol(UChar32 c) +void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const { - // Likely common case - if (c < 0x2C7) - return false; + FontCachePurgePreventer purgePreventer; + + GlyphData markGlyphData; + if (!getEmphasisMarkGlyphData(mark, markGlyphData)) + return; + + const SimpleFontData* markFontData = markGlyphData.fontData; + ASSERT(markFontData); + if (!markFontData) + return; + + Glyph markGlyph = markGlyphData.glyph; + Glyph spaceGlyph = markFontData->spaceGlyph(); - // Hash lookup for isolated symbols (those not part of a contiguous range) - static HashSet<UChar32>* cjkIsolatedSymbols = 0; - if (!cjkIsolatedSymbols) { - cjkIsolatedSymbols = new HashSet<UChar32>(); - for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i) - cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]); + float middleOfLastGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, 0); + FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y()); + + GlyphBuffer markBuffer; + for (unsigned i = 0; i + 1 < glyphBuffer.size(); ++i) { + float middleOfNextGlyph = offsetToMiddleOfAdvanceAtIndex(glyphBuffer, i + 1); + float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph; + markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance); + middleOfLastGlyph = middleOfNextGlyph; } - if (cjkIsolatedSymbols->contains(c)) - return true; + markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0); - if (isCJKIdeograph(c)) - return true; + drawGlyphBuffer(context, runInfo, markBuffer, startPoint); +} - static const UChar32 cjkSymbolRanges[] = { - 0x2156, 0x215A, - 0x2160, 0x216B, - 0x2170, 0x217B, - 0x23BE, 0x23CC, - 0x2460, 0x2492, - 0x249C, 0x24FF, - 0x25CE, 0x25D3, - 0x25E2, 0x25E6, - 0x2600, 0x2603, - 0x2660, 0x266F, - 0x2672, 0x267D, - 0x2776, 0x277F, - // Ideographic Description Characters, with CJK Symbols and Punctuation, excluding 0x3030. - // Then Hiragana 0x3040 .. 0x309F, Katakana 0x30A0 .. 0x30FF, Bopomofo 0x3100 .. 0x312F - 0x2FF0, 0x302F, - 0x3031, 0x312F, - // More Bopomofo and Bopomofo Extended 0x31A0 .. 0x31BF - 0x3190, 0x31BF, - // Enclosed CJK Letters and Months (0x3200 .. 0x32FF). - // CJK Compatibility (0x3300 .. 0x33FF). - 0x3200, 0x33FF, - 0xF860, 0xF862, - // CJK Compatibility Forms. - 0xFE30, 0xFE4F, - // Halfwidth and Fullwidth Forms - // Usually only used in CJK - 0xFF00, 0xFF0C, - 0xFF0E, 0xFF1A, - 0xFF1F, 0xFFEF, - // Emoji. - 0x1F110, 0x1F129, - 0x1F130, 0x1F149, - 0x1F150, 0x1F169, - 0x1F170, 0x1F189, - 0x1F200, 0x1F6FF - }; - static size_t cjkSymbolRangesCount = WTF_ARRAY_LENGTH(cjkSymbolRanges); - - UChar32* boundingCharacter = approximateBinarySearch<UChar32, UChar32>( - (UChar32*)cjkSymbolRanges, cjkSymbolRangesCount, c, keyExtractorUChar32); - // Exact matches are CJK Symbols - if (*boundingCharacter == c) - return true; - bool isEndOfRange = ((boundingCharacter - cjkSymbolRanges) % 2); - if (*boundingCharacter < c) - return !isEndOfRange; - return isEndOfRange; -} - -unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion) -{ - unsigned count = 0; - if (direction == LTR) { - for (size_t i = 0; i < length; ++i) { - if (treatAsSpace(characters[i])) { - count++; - isAfterExpansion = true; - } else - isAfterExpansion = false; - } - } else { - for (size_t i = length; i > 0; --i) { - if (treatAsSpace(characters[i - 1])) { - count++; - isAfterExpansion = true; - } else - isAfterExpansion = false; - } +float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, IntRectExtent* glyphBounds) const +{ + WidthIterator it(this, run, fallbackFonts, glyphBounds); + GlyphBuffer glyphBuffer; + it.advance(run.length(), (fontDescription().typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0); + + if (glyphBounds) { + glyphBounds->setTop(floorf(-it.minGlyphBoundingBoxY())); + glyphBounds->setBottom(ceilf(it.maxGlyphBoundingBoxY())); + glyphBounds->setLeft(floorf(it.firstGlyphOverflow())); + glyphBounds->setRight(ceilf(it.lastGlyphOverflow())); } - return count; + + return it.m_runWidthSoFar; } -unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion) +FloatRect Font::pixelSnappedSelectionRect(float fromX, float toX, float y, float height) { - static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText(); - unsigned count = 0; - if (direction == LTR) { - for (size_t i = 0; i < length; ++i) { - UChar32 character = characters[i]; - if (treatAsSpace(character)) { - count++; - isAfterExpansion = true; - continue; - } - if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) { - character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]); - i++; - } - if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { - if (!isAfterExpansion) - count++; - count++; - isAfterExpansion = true; - continue; + // Using roundf() rather than ceilf() for the right edge as a compromise to + // ensure correct caret positioning. + // Use LayoutUnit::epsilon() to ensure that values that cannot be stored as + // an integer are floored to n and not n-1 due to floating point imprecision. + float pixelAlignedX = floorf(fromX + LayoutUnit::epsilon()); + return FloatRect(pixelAlignedX, y, roundf(toX) - pixelAlignedX, height); +} + +FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to, bool accountForGlyphBounds) const +{ + GlyphBuffer glyphBuffer; + WidthIterator it(this, run, 0, accountForGlyphBounds); + it.advance(from, &glyphBuffer); + float fromX = it.m_runWidthSoFar; + it.advance(to, &glyphBuffer); + float toX = it.m_runWidthSoFar; + + if (run.rtl()) { + it.advance(run.length(), &glyphBuffer); + float totalWidth = it.m_runWidthSoFar; + float beforeWidth = fromX; + float afterWidth = toX; + fromX = totalWidth - afterWidth; + toX = totalWidth - beforeWidth; + } + + return pixelSnappedSelectionRect(point.x() + fromX, point.x() + toX, + accountForGlyphBounds ? it.minGlyphBoundingBoxY() : point.y(), + accountForGlyphBounds ? it.maxGlyphBoundingBoxY() - it.minGlyphBoundingBoxY() : h); +} + +int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const +{ + float delta = x; + + WidthIterator it(this, run); + GlyphBuffer localGlyphBuffer; + unsigned offset; + if (run.rtl()) { + delta -= floatWidthForSimpleText(run); + while (1) { + offset = it.m_currentCharacter; + float w; + if (!it.advanceOneCharacter(w, localGlyphBuffer)) + break; + delta += w; + if (includePartialGlyphs) { + if (delta - w / 2 >= 0) + break; + } else { + if (delta >= 0) + break; } - isAfterExpansion = false; } } else { - for (size_t i = length; i > 0; --i) { - UChar32 character = characters[i - 1]; - if (treatAsSpace(character)) { - count++; - isAfterExpansion = true; - continue; - } - if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) { - character = U16_GET_SUPPLEMENTARY(characters[i - 2], character); - i--; + while (1) { + offset = it.m_currentCharacter; + float w; + if (!it.advanceOneCharacter(w, localGlyphBuffer)) + break; + delta -= w; + if (includePartialGlyphs) { + if (delta + w / 2 <= 0) + break; + } else { + if (delta <= 0) + break; } - if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { - if (!isAfterExpansion) - count++; - count++; - isAfterExpansion = true; - continue; - } - isAfterExpansion = false; } } - return count; -} - -bool Font::canReceiveTextEmphasis(UChar32 c) -{ - CharCategory category = Unicode::category(c); - if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format)) - return false; - - // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010. - if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot - || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar) - return false; - return true; -} - -void Font::willUseFontData() const -{ - const FontFamily& family = fontDescription().family(); - if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty()) - m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family()); + return offset; } } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/Font.h b/chromium/third_party/WebKit/Source/platform/fonts/Font.h index 1e1e4961746..5396ffb6d59 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/Font.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/Font.h @@ -29,8 +29,8 @@ #include "platform/fonts/FontDescription.h" #include "platform/fonts/FontFallbackList.h" #include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/TypesettingFeatures.h" #include "platform/text/TextDirection.h" +#include "platform/text/TextPath.h" #include "wtf/HashMap.h" #include "wtf/HashSet.h" #include "wtf/MathExtras.h" @@ -52,7 +52,6 @@ class FontPlatformData; class FontSelector; class GlyphBuffer; class GraphicsContext; -class TextLayout; class TextRun; struct TextRunPaintInfo; @@ -79,9 +78,7 @@ struct GlyphOverflow { class PLATFORM_EXPORT Font { public: Font(); - Font(const FontDescription&, float letterSpacing, float wordSpacing); - // This constructor is only used if the platform wants to start with a native font. - Font(const FontPlatformData&, bool isPrinting, FontSmoothingMode = AutoSmoothing); + Font(const FontDescription&); ~Font(); Font(const Font&); @@ -92,48 +89,23 @@ public: const FontDescription& fontDescription() const { return m_fontDescription; } - int pixelSize() const { return fontDescription().computedPixelSize(); } - float size() const { return fontDescription().computedSize(); } - - void update(PassRefPtr<FontSelector>) const; + void update(PassRefPtrWillBeRawPtr<FontSelector>) const; enum CustomFontNotReadyAction { DoNotPaintIfFontNotReady, UseFallbackIfFontNotReady }; void drawText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&, CustomFontNotReadyAction = DoNotPaintIfFontNotReady) const; void drawEmphasisMarks(GraphicsContext*, const TextRunPaintInfo&, const AtomicString& mark, const FloatPoint&) const; float width(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; - float width(const TextRun&, int& charsConsumed, String& glyphName) const; - - PassOwnPtr<TextLayout> createLayoutForMacComplexText(const TextRun&, unsigned textLength, float xPos, bool collapseWhiteSpace) const; - static void deleteLayout(TextLayout*); - static float width(TextLayout&, unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts = 0); + float width(const TextRun&, int& charsConsumed, Glyph& glyphId) const; int offsetForPosition(const TextRun&, float position, bool includePartialGlyphs) const; - FloatRect selectionRectForText(const TextRun&, const FloatPoint&, int h, int from = 0, int to = -1) const; + FloatRect selectionRectForText(const TextRun&, const FloatPoint&, int h, int from = 0, int to = -1, bool accountForGlyphBounds = false) const; - bool isSmallCaps() const { return m_fontDescription.smallCaps(); } - - float wordSpacing() const { return m_wordSpacing; } - float letterSpacing() const { return m_letterSpacing; } - void setWordSpacing(float s) { m_wordSpacing = s; } - void setLetterSpacing(float s) { m_letterSpacing = s; } bool isFixedPitch() const; - bool isPrinterFont() const { return m_fontDescription.usePrinterFont(); } - - TypesettingFeatures typesettingFeatures() const { return static_cast<TypesettingFeatures>(m_typesettingFeatures); } - - FontFamily& firstFamily() { return m_fontDescription.firstFamily(); } - const FontFamily& family() const { return m_fontDescription.family(); } - - FontItalic italic() const { return m_fontDescription.italic(); } - FontWeight weight() const { return m_fontDescription.weight(); } - FontWidthVariant widthVariant() const { return m_fontDescription.widthVariant(); } - - bool isPlatformFont() const { return m_isPlatformFont; } // Metrics that we query the FontFallbackList for. const FontMetrics& fontMetrics() const { return primaryFont()->fontMetrics(); } - float spaceWidth() const { return primaryFont()->spaceWidth() + m_letterSpacing; } + float spaceWidth() const { return primaryFont()->spaceWidth() + fontDescription().letterSpacing(); } float tabWidth(const SimpleFontData&, unsigned tabSize, float position) const; float tabWidth(unsigned tabSize, float position) const { return tabWidth(*primaryFont(), tabSize, position); } @@ -153,44 +125,29 @@ public: std::pair<GlyphData, GlyphPage*> glyphDataAndPageForCharacter(UChar32, bool mirror, FontDataVariant = AutoVariant) const; bool primaryFontHasGlyphForCharacter(UChar32) const; - static bool isCJKIdeograph(UChar32); - static bool isCJKIdeographOrSymbol(UChar32); - - static unsigned expansionOpportunityCount(const LChar*, size_t length, TextDirection, bool& isAfterExpansion); - static unsigned expansionOpportunityCount(const UChar*, size_t length, TextDirection, bool& isAfterExpansion); - - static void setShouldUseSmoothing(bool); - static bool shouldUseSmoothing(); - - enum CodePath { Auto, Simple, Complex, SimpleWithGlyphOverflow }; CodePath codePath(const TextRun&) const; - static CodePath characterRangeCodePath(const LChar*, unsigned) { return Simple; } - static CodePath characterRangeCodePath(const UChar*, unsigned len); private: enum ForTextEmphasisOrNot { NotForTextEmphasis, ForTextEmphasis }; // Returns the initial in-stream advance. - float getGlyphsAndAdvancesForSimpleText(const TextRun&, int from, int to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const; + float getGlyphsAndAdvancesForSimpleText(const TextRunPaintInfo&, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const; void drawSimpleText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&) const; void drawEmphasisMarksForSimpleText(GraphicsContext*, const TextRunPaintInfo&, const AtomicString& mark, const FloatPoint&) const; void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, unsigned from, unsigned numGlyphs, const FloatPoint&, const FloatRect& textRect) const; void drawGlyphBuffer(GraphicsContext*, const TextRunPaintInfo&, const GlyphBuffer&, const FloatPoint&) const; void drawEmphasisMarks(GraphicsContext*, const TextRunPaintInfo&, const GlyphBuffer&, const AtomicString&, const FloatPoint&) const; - float floatWidthForSimpleText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; + float floatWidthForSimpleText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, IntRectExtent* glyphBounds = 0) const; int offsetForPositionForSimpleText(const TextRun&, float position, bool includePartialGlyphs) const; - FloatRect selectionRectForSimpleText(const TextRun&, const FloatPoint&, int h, int from, int to) const; + FloatRect selectionRectForSimpleText(const TextRun&, const FloatPoint&, int h, int from, int to, bool accountForGlyphBounds) const; bool getEmphasisMarkGlyphData(const AtomicString&, GlyphData&) const; - static bool canReturnFallbackFontsForComplexText(); - static bool canExpandAroundIdeographsInComplexText(); - // Returns the initial in-stream advance. - float getGlyphsAndAdvancesForComplexText(const TextRun&, int from, int to, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const; + float getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo&, GlyphBuffer&, ForTextEmphasisOrNot = NotForTextEmphasis) const; void drawComplexText(GraphicsContext*, const TextRunPaintInfo&, const FloatPoint&) const; void drawEmphasisMarksForComplexText(GraphicsContext*, const TextRunPaintInfo&, const AtomicString& mark, const FloatPoint&) const; - float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0, GlyphOverflow* = 0) const; + float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts, IntRectExtent* glyphBounds) const; int offsetForPositionForComplexText(const TextRun&, float position, bool includePartialGlyphs) const; FloatRect selectionRectForComplexText(const TextRun&, const FloatPoint&, int h, int from, int to) const; @@ -203,95 +160,26 @@ public: static CodePath codePath(); static CodePath s_codePath; - static void setDefaultTypesettingFeatures(TypesettingFeatures); - static TypesettingFeatures defaultTypesettingFeatures(); - - static const uint8_t s_roundingHackCharacterTable[256]; - static bool isRoundingHackCharacter(UChar32 c) - { - return !(c & ~0xFF) && s_roundingHackCharacterTable[c]; - } - FontSelector* fontSelector() const; - static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == noBreakSpace; } - static bool treatAsZeroWidthSpace(UChar c) { return treatAsZeroWidthSpaceInComplexScript(c) || c == 0x200c || c == 0x200d; } - static bool treatAsZeroWidthSpaceInComplexScript(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == softHyphen || c == zeroWidthSpace || (c >= 0x200e && c <= 0x200f) || (c >= 0x202a && c <= 0x202e) || c == zeroWidthNoBreakSpace || c == objectReplacementCharacter; } - static bool canReceiveTextEmphasis(UChar32 c); - - static inline UChar normalizeSpaces(UChar character) - { - if (treatAsSpace(character)) - return space; - - if (treatAsZeroWidthSpace(character)) - return zeroWidthSpace; - - return character; - } - - static String normalizeSpaces(const LChar*, unsigned length); - static String normalizeSpaces(const UChar*, unsigned length); FontFallbackList* fontList() const { return m_fontFallbackList.get(); } - void willUseFontData() const; + void willUseFontData(UChar32) const; + static FloatRect pixelSnappedSelectionRect(float fromX, float toX, float y, float height); private: bool loadingCustomFonts() const { return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts(); } - TypesettingFeatures computeTypesettingFeatures() const + bool shouldSkipDrawing() const { - TextRenderingMode textRenderingMode = m_fontDescription.textRenderingMode(); - TypesettingFeatures features = s_defaultTypesettingFeatures; - - switch (textRenderingMode) { - case AutoTextRendering: - break; - case OptimizeSpeed: - features &= ~(Kerning | Ligatures); - break; - case GeometricPrecision: - case OptimizeLegibility: - features |= Kerning | Ligatures; - break; - } - - switch (m_fontDescription.kerning()) { - case FontDescription::NoneKerning: - features &= ~Kerning; - break; - case FontDescription::NormalKerning: - features |= Kerning; - break; - case FontDescription::AutoKerning: - break; - } - - switch (m_fontDescription.commonLigaturesState()) { - case FontDescription::DisabledLigaturesState: - features &= ~Ligatures; - break; - case FontDescription::EnabledLigaturesState: - features |= Ligatures; - break; - case FontDescription::NormalLigaturesState: - break; - } - - return features; + return m_fontFallbackList && m_fontFallbackList->shouldSkipDrawing(); } - static TypesettingFeatures s_defaultTypesettingFeatures; - FontDescription m_fontDescription; mutable RefPtr<FontFallbackList> m_fontFallbackList; - float m_letterSpacing; - float m_wordSpacing; - bool m_isPlatformFont; - mutable unsigned m_typesettingFeatures : 2; // (TypesettingFeatures) Caches values computed from m_fontDescription. }; inline Font::~Font() @@ -324,19 +212,11 @@ inline FontSelector* Font::fontSelector() const inline float Font::tabWidth(const SimpleFontData& fontData, unsigned tabSize, float position) const { if (!tabSize) - return letterSpacing(); - float tabWidth = tabSize * fontData.spaceWidth() + letterSpacing(); + return fontDescription().letterSpacing(); + float tabWidth = tabSize * fontData.spaceWidth() + fontDescription().letterSpacing(); return tabWidth - fmodf(position, tabWidth); } } -namespace WTF { - -template <> struct PLATFORM_EXPORT OwnedPtrDeleter<WebCore::TextLayout> { - static void deletePtr(WebCore::TextLayout*); -}; - -} - #endif diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontCache.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontCache.cpp index 0e9b22a3b3f..f988027dd63 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontCache.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontCache.cpp @@ -30,16 +30,16 @@ #include "config.h" #include "platform/fonts/FontCache.h" -#include "FontFamilyNames.h" +#include "platform/FontFamilyNames.h" -#include "RuntimeEnabledFeatures.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/fonts/AlternateFontFamily.h" +#include "platform/fonts/FontCacheClient.h" #include "platform/fonts/FontCacheKey.h" #include "platform/fonts/FontDataCache.h" #include "platform/fonts/FontDescription.h" #include "platform/fonts/FontFallbackList.h" #include "platform/fonts/FontPlatformData.h" -#include "platform/fonts/FontSelector.h" #include "platform/fonts/FontSmoothingMode.h" #include "platform/fonts/TextRenderingMode.h" #include "platform/fonts/opentype/OpenTypeVerticalData.h" @@ -53,17 +53,23 @@ using namespace WTF; namespace WebCore { -#if !OS(WIN) || ENABLE(GDI_FONTS_ON_WINDOWS) +#if !OS(WIN) FontCache::FontCache() : m_purgePreventCount(0) { } -#endif // !OS(WIN) || ENABLE(GDI_FONTS_ON_WINDOWS) +#endif // !OS(WIN) typedef HashMap<FontCacheKey, OwnPtr<FontPlatformData>, FontCacheKeyHash, FontCacheKeyTraits> FontPlatformDataCache; static FontPlatformDataCache* gFontPlatformDataCache = 0; +#if OS(WIN) +bool FontCache::s_useDirectWrite = false; +IDWriteFactory* FontCache::s_directWriteFactory = 0; +bool FontCache::s_useSubpixelPositioning = false; +#endif // OS(WIN) + FontCache* FontCache::fontCache() { DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ()); @@ -145,7 +151,7 @@ PassRefPtr<SimpleFontData> FontCache::getFontData(const FontDescription& fontDes if (FontPlatformData* platformData = getFontPlatformData(fontDescription, adjustFamilyNameToAvoidUnsupportedFonts(family), checkingAlternateName)) return fontDataFromFontPlatformData(platformData, shouldRetain); - return 0; + return nullptr; } PassRefPtr<SimpleFontData> FontCache::fontDataFromFontPlatformData(const FontPlatformData* platformData, ShouldRetain shouldRetain) @@ -153,7 +159,7 @@ PassRefPtr<SimpleFontData> FontCache::fontDataFromFontPlatformData(const FontPla if (!gFontDataCache) gFontDataCache = new FontDataCache; -#if !ASSERT_DISABLED +#if ASSERT_ENABLED if (shouldRetain == DoNotRetain) ASSERT(m_purgePreventCount); #endif @@ -164,7 +170,7 @@ PassRefPtr<SimpleFontData> FontCache::fontDataFromFontPlatformData(const FontPla bool FontCache::isPlatformFontAvailable(const FontDescription& fontDescription, const AtomicString& family) { bool checkingAlternateName = true; - return getFontPlatformData(fontDescription, family, checkingAlternateName); + return getFontPlatformData(fontDescription, adjustFamilyNameToAvoidUnsupportedFonts(family), checkingAlternateName); } SimpleFontData* FontCache::getNonRetainedLastResortFallbackFont(const FontDescription& fontDescription) @@ -191,10 +197,7 @@ static inline void purgePlatformFontDataCache() if (platformData->value && !gFontDataCache->contains(platformData->value.get())) keysToRemove.append(platformData->key); } - - size_t keysToRemoveCount = keysToRemove.size(); - for (size_t i = 0; i < keysToRemoveCount; ++i) - gFontPlatformDataCache->remove(keysToRemove[i]); + gFontPlatformDataCache->removeAll(keysToRemove); } static inline void purgeFontVerticalDataCache() @@ -217,8 +220,7 @@ static inline void purgeFontVerticalDataCache() if (!verticalData->value || !verticalData->value->inFontCache()) keysToRemove.append(verticalData->key); } - for (size_t i = 0, count = keysToRemove.size(); i < count; ++i) - fontVerticalDataCache.take(keysToRemove[i]); + fontVerticalDataCache.removeAll(keysToRemove); } #endif } @@ -237,24 +239,32 @@ void FontCache::purge(PurgeSeverity PurgeSeverity) purgeFontVerticalDataCache(); } -static HashSet<FontSelector*>* gClients; +static bool invalidateFontCache = false; -void FontCache::addClient(FontSelector* client) +WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> >& fontCacheClients() { - if (!gClients) - gClients = new HashSet<FontSelector*>; - - ASSERT(!gClients->contains(client)); - gClients->add(client); +#if ENABLE(OILPAN) + DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<WeakMember<FontCacheClient> > >, clients, (new HeapHashSet<WeakMember<FontCacheClient> >())); +#else + DEFINE_STATIC_LOCAL(HashSet<RawPtr<FontCacheClient> >*, clients, (new HashSet<RawPtr<FontCacheClient> >())); +#endif + invalidateFontCache = true; + return *clients; } -void FontCache::removeClient(FontSelector* client) +void FontCache::addClient(FontCacheClient* client) { - ASSERT(gClients); - ASSERT(gClients->contains(client)); + ASSERT(!fontCacheClients().contains(client)); + fontCacheClients().add(client); +} - gClients->remove(client); +#if !ENABLE(OILPAN) +void FontCache::removeClient(FontCacheClient* client) +{ + ASSERT(fontCacheClients().contains(client)); + fontCacheClients().remove(client); } +#endif static unsigned short gGeneration = 0; @@ -265,7 +275,7 @@ unsigned short FontCache::generation() void FontCache::invalidate() { - if (!gClients) { + if (!invalidateFontCache) { ASSERT(!gFontPlatformDataCache); return; } @@ -277,11 +287,11 @@ void FontCache::invalidate() gGeneration++; - Vector<RefPtr<FontSelector> > clients; - size_t numClients = gClients->size(); + WillBeHeapVector<RefPtrWillBeMember<FontCacheClient> > clients; + size_t numClients = fontCacheClients().size(); clients.reserveInitialCapacity(numClients); - HashSet<FontSelector*>::iterator end = gClients->end(); - for (HashSet<FontSelector*>::iterator it = gClients->begin(); it != end; ++it) + WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> >::iterator end = fontCacheClients().end(); + for (WillBeHeapHashSet<RawPtrWillBeWeakMember<FontCacheClient> >::iterator it = fontCacheClients().begin(); it != end; ++it) clients.append(*it); ASSERT(numClients == clients.size()); diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontCache.h b/chromium/third_party/WebKit/Source/platform/fonts/FontCache.h index 4fcfb3fd234..0aef86a8dbc 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontCache.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontCache.h @@ -33,6 +33,7 @@ #include <limits.h> #include "platform/PlatformExport.h" #include "wtf/Forward.h" +#include "wtf/HashMap.h" #include "wtf/PassRefPtr.h" #include "wtf/RefPtr.h" #include "wtf/Vector.h" @@ -41,23 +42,25 @@ #include "wtf/unicode/Unicode.h" #if OS(WIN) +#include "SkFontMgr.h" #include <windows.h> #include <objidl.h> #include <mlang.h> +struct IDWriteFactory; #endif -#if OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS) -#include "SkFontMgr.h" +#if OS(ANDROID) +#include <unicode/uscript.h> #endif class SkTypeface; namespace WebCore { +class FontCacheClient; class FontPlatformData; class FontData; class FontDescription; -class FontSelector; class OpenTypeVerticalData; class SimpleFontData; @@ -75,7 +78,7 @@ public: // This method is implemented by the plaform and used by // FontFastPath to lookup the font for a given character. - PassRefPtr<SimpleFontData> platformFallbackForCharacter(const FontDescription&, UChar32, const SimpleFontData* fontDataToSubstitute, bool disallowSynthetics); + PassRefPtr<SimpleFontData> fallbackFontForCharacter(const FontDescription&, UChar32, const SimpleFontData* fontDataToSubstitute); // Also implemented by the platform. void platformInit(); @@ -85,8 +88,10 @@ public: SimpleFontData* getNonRetainedLastResortFallbackFont(const FontDescription&); bool isPlatformFontAvailable(const FontDescription&, const AtomicString&); - void addClient(FontSelector*); - void removeClient(FontSelector*); + void addClient(FontCacheClient*); +#if !ENABLE(OILPAN) + void removeClient(FontCacheClient*); +#endif unsigned short generation(); void invalidate(); @@ -95,9 +100,14 @@ public: PassRefPtr<SimpleFontData> fontDataFromDescriptionAndLogFont(const FontDescription&, ShouldRetain, const LOGFONT&, wchar_t* outFontFamilyName); #endif -#if OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS) - bool useSubpixelPositioning() const { return m_useSubpixelPositioning; } +#if OS(WIN) + bool useSubpixelPositioning() const { return s_useSubpixelPositioning; } SkFontMgr* fontManager() { return m_fontManager.get(); } + static bool useDirectWrite() { return s_useDirectWrite; } + static void setUseDirectWrite(bool useDirectWrite) { s_useDirectWrite = useDirectWrite; } + static void setDirectWriteFactory(IDWriteFactory* factory) { s_directWriteFactory = factory; } + static void setUseSubpixelPositioning(bool useSubpixelPositioning) { s_useSubpixelPositioning = useSubpixelPositioning; } + static void addSideloadedFontForTesting(SkTypeface*); #endif #if ENABLE(OPENTYPE_VERTICAL) @@ -108,12 +118,14 @@ public: #if OS(ANDROID) static AtomicString getGenericFamilyNameForScript(const AtomicString& familyName, UScriptCode); #else - struct SimpleFontFamily { + struct PlatformFallbackFont { String name; + CString filename; + int ttcIndex; bool isBold; bool isItalic; }; - static void getFontFamilyForCharacter(UChar32, const char* preferredLocale, SimpleFontFamily*); + static void getFontForCharacter(UChar32, const char* preferredLocale, PlatformFallbackFont*); #endif private: @@ -144,9 +156,12 @@ private: // Don't purge if this count is > 0; int m_purgePreventCount; -#if OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS) +#if OS(WIN) OwnPtr<SkFontMgr> m_fontManager; - bool m_useSubpixelPositioning; + static bool s_useDirectWrite; + static IDWriteFactory* s_directWriteFactory; + static bool s_useSubpixelPositioning; + static HashMap<String, SkTypeface*>* s_sideloadedFonts; #endif #if OS(MACOSX) || OS(ANDROID) diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/SkiaFontWin.h b/chromium/third_party/WebKit/Source/platform/fonts/FontCacheClient.h index 977e6c022f6..2ee8682fc93 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/SkiaFontWin.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontCacheClient.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Google Inc. All rights reserved. + * Copyright (C) 2014 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 @@ -28,47 +28,23 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SkiaFontWin_h -#define SkiaFontWin_h +#ifndef FontCacheClient_h +#define FontCacheClient_h -#include <windows.h> -#include <usp10.h> - -struct SkPoint; -struct SkRect; +#include "platform/PlatformExport.h" +#include "platform/heap/Handle.h" +#include "wtf/RefCounted.h" namespace WebCore { -class FontPlatformData; -class GraphicsContext; - -// Note that the offsets parameter is optional. If not null it represents a -// per glyph offset (such as returned by ScriptPlace Windows API function). -void paintSkiaText(GraphicsContext*, - const FontPlatformData&, - unsigned numGlyphs, - const WORD* glyphs, - const int* advances, - const GOFFSET* offsets, - const SkPoint& origin, - const SkRect& textRect); +class PLATFORM_EXPORT FontCacheClient : public RefCountedWillBeGarbageCollectedFinalized<FontCacheClient> { +public: + virtual ~FontCacheClient() { } -#if !USE(HARFBUZZ) -// Note that the offsets parameter is optional. If not null it represents a -// per glyph offset (such as returned by ScriptPlace Windows API function). -// Note: this is less efficient than calling the version with FontPlatformData, -// as that caches the SkTypeface object. -void paintSkiaText(GraphicsContext*, - const FontPlatformData&, - HFONT, - unsigned numGlyphs, - const WORD* glyphs, - const int* advances, - const GOFFSET* offsets, - const SkPoint& origin, - const SkRect& textRect); -#endif + virtual void fontCacheInvalidated() = 0; + virtual void trace(Visitor*) { } +}; -} // namespace WebCore +} // namespace WebCore -#endif // SkiaFontWin_h +#endif // FontCacheClient_h diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontCacheTest.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontCacheTest.cpp new file mode 100644 index 00000000000..27fb1487fb6 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontCacheTest.cpp @@ -0,0 +1,46 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "platform/fonts/FontCache.h" + +#include "platform/fonts/FontDescription.h" +#include "platform/fonts/SimpleFontData.h" +#include "public/platform/Platform.h" +#include <gtest/gtest.h> + +namespace WebCore { + +class EmptyPlatform : public blink::Platform { +public: + EmptyPlatform() { } + virtual ~EmptyPlatform() { } + virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length) OVERRIDE { } +}; + +TEST(FontCache, getLastResortFallbackFont) +{ + FontCache* fontCache = FontCache::fontCache(); + ASSERT_TRUE(fontCache); + + blink::Platform* oldPlatform = blink::Platform::current(); + OwnPtr<EmptyPlatform> platform = adoptPtr(new EmptyPlatform); + blink::Platform::initialize(platform.get()); + + if (emptyAtom.isNull()) + AtomicString::init(); + + FontDescription fontDescription; + fontDescription.setGenericFamily(FontDescription::StandardFamily); + RefPtr<SimpleFontData> fontData = fontCache->getLastResortFallbackFont(fontDescription, Retain); + EXPECT_TRUE(fontData); + + fontDescription.setGenericFamily(FontDescription::SansSerifFamily); + fontData = fontCache->getLastResortFallbackFont(fontDescription, Retain); + EXPECT_TRUE(fontData); + + blink::Platform::initialize(oldPlatform); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h b/chromium/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h index ae7d6b2ba9d..f11c2901261 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.h @@ -37,22 +37,16 @@ #include "platform/fonts/FontWidthVariant.h" #include "wtf/Forward.h" #include "wtf/Noncopyable.h" +#include "wtf/RefPtr.h" #include "wtf/text/WTFString.h" -#if OS(WIN) && ENABLE(GDI_FONTS_ON_WINDOWS) -#include <windows.h> -#endif - #if OS(MACOSX) #include "wtf/RetainPtr.h" #include <CoreFoundation/CFBase.h> typedef struct CGFont* CGFontRef; #endif -#if OS(MACOSX) || OS(POSIX) || (OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS)) -#include "wtf/RefPtr.h" class SkTypeface; -#endif namespace WebCore { @@ -70,18 +64,13 @@ public: static bool supportsFormat(const String&); private: -#if OS(WIN) && ENABLE(GDI_FONTS_ON_WINDOWS) - FontCustomPlatformData(HANDLE fontReference, const String& name); - HANDLE m_fontReference; - String m_name; -#elif OS(MACOSX) +#if OS(MACOSX) explicit FontCustomPlatformData(CGFontRef, PassRefPtr<SkTypeface>); RetainPtr<CGFontRef> m_cgFont; - RefPtr<SkTypeface> m_typeface; -#elif OS(POSIX) || (OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS)) +#else explicit FontCustomPlatformData(PassRefPtr<SkTypeface>); - RefPtr<SkTypeface> m_typeface; #endif + RefPtr<SkTypeface> m_typeface; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontData.h b/chromium/third_party/WebKit/Source/platform/fonts/FontData.h index 003100b3924..fb4a65441cb 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontData.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontData.h @@ -49,12 +49,12 @@ public: virtual ~FontData(); virtual const SimpleFontData* fontDataForCharacter(UChar32) const = 0; - virtual bool containsCharacters(const UChar*, int length) const = 0; virtual bool isCustomFont() const = 0; virtual bool isLoading() const = 0; // Returns whether this is a temporary font data for a custom font which is not yet loaded. virtual bool isLoadingFallback() const = 0; virtual bool isSegmented() const = 0; + virtual bool shouldSkipDrawing() const = 0; void setMaxGlyphPageTreeLevel(unsigned level) const { m_maxGlyphPageTreeLevel = level; } unsigned maxGlyphPageTreeLevel() const { return m_maxGlyphPageTreeLevel; } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontDataCache.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontDataCache.cpp index 0f5efe3d45e..5a1e933d380 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontDataCache.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontDataCache.cpp @@ -48,7 +48,7 @@ const unsigned cTargetInactiveFontData = 200; PassRefPtr<SimpleFontData> FontDataCache::get(const FontPlatformData* platformData, ShouldRetain shouldRetain) { if (!platformData) - return 0; + return nullptr; Cache::iterator result = m_cache.find(*platformData); if (result == m_cache.end()) { diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.cpp index 9f46bf339c2..4f84d9f0cc0 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.cpp @@ -30,7 +30,7 @@ #include "config.h" #include "platform/fonts/FontDescription.h" -#include "RuntimeEnabledFeatures.h" +#include "platform/RuntimeEnabledFeatures.h" #include "wtf/text/AtomicStringHash.h" #include "wtf/text/StringHash.h" @@ -39,14 +39,17 @@ namespace WebCore { struct SameSizeAsFontDescription { FontFamily familyList; RefPtr<FontFeatureSettings> m_featureSettings; - float sizes[2]; + String locale; + float sizes[4]; // FXIME: Make them fit into one word. uint32_t bitfields; - uint32_t bitfields2 : 8; + uint32_t bitfields2 : 7; }; COMPILE_ASSERT(sizeof(FontDescription) == sizeof(SameSizeAsFontDescription), FontDescription_should_stay_small); +TypesettingFeatures FontDescription::s_defaultTypesettingFeatures = 0; + bool FontDescription::s_useSubpixelTextPositioning = false; FontWeight FontDescription::lighterWeight(void) const @@ -93,55 +96,23 @@ FontWeight FontDescription::bolderWeight(void) const return FontWeightNormal; } -FontTraitsMask FontDescription::traitsMask() const +FontTraits FontDescription::traits() const { - return static_cast<FontTraitsMask>((m_italic ? FontStyleItalicMask : FontStyleNormalMask) - | (m_smallCaps ? FontVariantSmallCapsMask : FontVariantNormalMask) - | (FontWeight100Mask << (m_weight - FontWeight100))); - + return FontTraits(style(), variant(), weight(), stretch()); } -void FontDescription::setTraitsMask(FontTraitsMask traitsMask) +void FontDescription::setTraits(FontTraits traits) { - switch (traitsMask & FontWeightMask) { - case FontWeight100Mask: - setWeight(FontWeight100); - break; - case FontWeight200Mask: - setWeight(FontWeight200); - break; - case FontWeight300Mask: - setWeight(FontWeight300); - break; - case FontWeight400Mask: - setWeight(FontWeight400); - break; - case FontWeight500Mask: - setWeight(FontWeight500); - break; - case FontWeight600Mask: - setWeight(FontWeight600); - break; - case FontWeight700Mask: - setWeight(FontWeight700); - break; - case FontWeight800Mask: - setWeight(FontWeight800); - break; - case FontWeight900Mask: - setWeight(FontWeight900); - break; - default: - ASSERT_NOT_REACHED(); - } - setItalic((traitsMask & FontStyleItalicMask) ? FontItalicOn : FontItalicOff); - setSmallCaps((traitsMask & FontVariantSmallCapsMask) ? FontSmallCapsOn : FontSmallCapsOff); + setStyle(traits.style()); + setVariant(traits.variant()); + setWeight(traits.weight()); + setStretch(traits.stretch()); } FontDescription FontDescription::makeNormalFeatureSettings() const { FontDescription normalDescription(*this); - normalDescription.setFeatureSettings(0); + normalDescription.setFeatureSettings(nullptr); return normalDescription; } @@ -156,22 +127,83 @@ float FontDescription::effectiveFontSize() const return floorf(size * FontCacheKey::precisionMultiplier()) / FontCacheKey::precisionMultiplier(); } -FontCacheKey FontDescription::cacheKey(const AtomicString& familyName, FontTraitsMask desiredTraits) const +FontCacheKey FontDescription::cacheKey(const AtomicString& familyName, FontTraits desiredTraits) const { - FontTraitsMask traits = desiredTraits + FontTraits fontTraits = desiredTraits.mask() ? desiredTraits - : traitsMask(); + : traits(); unsigned options = - static_cast<unsigned>(m_syntheticItalic) << 8 | // bit 9 - static_cast<unsigned>(m_syntheticBold) << 7 | // bit 8 - static_cast<unsigned>(m_fontSmoothing) << 5 | // bits 6-7 - static_cast<unsigned>(m_textRendering) << 3 | // bits 4-5 - static_cast<unsigned>(m_orientation) << 2 | // bit 3 - static_cast<unsigned>(m_usePrinterFont) << 1 | // bit 2 + static_cast<unsigned>(m_syntheticItalic) << 7 | // bit 8 + static_cast<unsigned>(m_syntheticBold) << 6 | // bit 7 + static_cast<unsigned>(m_fontSmoothing) << 4 | // bits 5-6 + static_cast<unsigned>(m_textRendering) << 2 | // bits 3-4 + static_cast<unsigned>(m_orientation) << 1 | // bit 2 static_cast<unsigned>(m_subpixelTextPosition); // bit 1 - return FontCacheKey(familyName, effectiveFontSize(), options | traits << 9); + return FontCacheKey(familyName, effectiveFontSize(), options | fontTraits.mask() << 8); +} + + +void FontDescription::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures) +{ + s_defaultTypesettingFeatures = typesettingFeatures; +} + +TypesettingFeatures FontDescription::defaultTypesettingFeatures() +{ + return s_defaultTypesettingFeatures; +} + +void FontDescription::updateTypesettingFeatures() const +{ + m_typesettingFeatures = s_defaultTypesettingFeatures; + + switch (textRendering()) { + case AutoTextRendering: + break; + case OptimizeSpeed: + m_typesettingFeatures &= ~(WebCore::Kerning | Ligatures); + break; + case GeometricPrecision: + case OptimizeLegibility: + m_typesettingFeatures |= WebCore::Kerning | Ligatures; + break; + } + + switch (kerning()) { + case FontDescription::NoneKerning: + m_typesettingFeatures &= ~WebCore::Kerning; + break; + case FontDescription::NormalKerning: + m_typesettingFeatures |= WebCore::Kerning; + break; + case FontDescription::AutoKerning: + break; + } + + // As per CSS (http://dev.w3.org/csswg/css-text-3/#letter-spacing-property), + // When the effective letter-spacing between two characters is not zero (due to + // either justification or non-zero computed letter-spacing), user agents should + // not apply optional ligatures. + if (m_letterSpacing == 0) { + switch (commonLigaturesState()) { + case FontDescription::DisabledLigaturesState: + m_typesettingFeatures &= ~Ligatures; + break; + case FontDescription::EnabledLigaturesState: + m_typesettingFeatures |= Ligatures; + break; + case FontDescription::NormalLigaturesState: + break; + } + + if (discretionaryLigaturesState() == FontDescription::EnabledLigaturesState + || historicalLigaturesState() == FontDescription::EnabledLigaturesState + || contextualLigaturesState() == FontDescription::EnabledLigaturesState) { + m_typesettingFeatures |= WebCore::Ligatures; + } + } } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.h b/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.h index 642c95b85ab..9cefae0436a 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontDescription.h @@ -25,45 +25,24 @@ #ifndef FontDescription_h #define FontDescription_h -#include "FontFamilyNames.h" +#include "platform/FontFamilyNames.h" #include "platform/fonts/FontCacheKey.h" #include "platform/fonts/FontFamily.h" #include "platform/fonts/FontFeatureSettings.h" #include "platform/fonts/FontOrientation.h" #include "platform/fonts/FontSmoothingMode.h" -#include "platform/fonts/FontTraitsMask.h" +#include "platform/fonts/FontTraits.h" #include "platform/fonts/FontWidthVariant.h" #include "platform/fonts/TextRenderingMode.h" +#include "platform/fonts/TypesettingFeatures.h" #include "platform/text/NonCJKGlyphOrientation.h" #include "wtf/MathExtras.h" #include "wtf/RefPtr.h" -namespace WebCore { - -enum FontWeight { - FontWeight100, - FontWeight200, - FontWeight300, - FontWeight400, - FontWeight500, - FontWeight600, - FontWeight700, - FontWeight800, - FontWeight900, - FontWeightNormal = FontWeight400, - FontWeightBold = FontWeight700 -}; - -enum FontItalic { - FontItalicOff = 0, - FontItalicOn = 1 -}; +#include <unicode/uscript.h> -enum FontSmallCaps { - FontSmallCapsOff = 0, - FontSmallCapsOn = 1 -}; +namespace WebCore { class PLATFORM_EXPORT FontDescription { public: @@ -75,29 +54,33 @@ public: enum LigaturesState { NormalLigaturesState, DisabledLigaturesState, EnabledLigaturesState }; FontDescription() - : m_specifiedSize(0) + : m_locale("en") + , m_specifiedSize(0) , m_computedSize(0) + , m_letterSpacing(0) + , m_wordSpacing(0) , m_orientation(Horizontal) , m_nonCJKGlyphOrientation(NonCJKGlyphOrientationVerticalRight) , m_widthVariant(RegularWidth) - , m_italic(FontItalicOff) - , m_smallCaps(FontSmallCapsOff) + , m_style(FontStyleNormal) + , m_variant(FontVariantNormal) , m_isAbsoluteSize(false) , m_weight(FontWeightNormal) + , m_stretch(FontStretchNormal) , m_genericFamily(NoFamily) - , m_usePrinterFont(false) , m_kerning(AutoKerning) , m_commonLigaturesState(NormalLigaturesState) , m_discretionaryLigaturesState(NormalLigaturesState) , m_historicalLigaturesState(NormalLigaturesState) + , m_contextualLigaturesState(NormalLigaturesState) , m_keywordSize(0) , m_fontSmoothing(AutoSmoothing) , m_textRendering(AutoTextRendering) - , m_isSpecifiedFont(false) , m_script(USCRIPT_COMMON) , m_syntheticBold(false) , m_syntheticItalic(false) , m_subpixelTextPosition(s_useSubpixelTextPositioning) + , m_typesettingFeatures(s_defaultTypesettingFeatures) { } @@ -108,31 +91,35 @@ public: FontFamily& firstFamily() { return m_familyList; } float specifiedSize() const { return m_specifiedSize; } float computedSize() const { return m_computedSize; } - FontItalic italic() const { return static_cast<FontItalic>(m_italic); } + FontStyle style() const { return static_cast<FontStyle>(m_style); } int computedPixelSize() const { return int(m_computedSize + 0.5f); } - FontSmallCaps smallCaps() const { return static_cast<FontSmallCaps>(m_smallCaps); } + FontVariant variant() const { return static_cast<FontVariant>(m_variant); } bool isAbsoluteSize() const { return m_isAbsoluteSize; } FontWeight weight() const { return static_cast<FontWeight>(m_weight); } + FontStretch stretch() const { return static_cast<FontStretch>(m_stretch); } FontWeight lighterWeight() const; FontWeight bolderWeight() const; GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); } - bool usePrinterFont() const { return m_usePrinterFont; } + // only use fixed default size when there is only one font family, and that family is "monospace" bool useFixedDefaultSize() const { return genericFamily() == MonospaceFamily && !family().next() && family().family() == FontFamilyNames::webkit_monospace; } Kerning kerning() const { return static_cast<Kerning>(m_kerning); } LigaturesState commonLigaturesState() const { return static_cast<LigaturesState>(m_commonLigaturesState); } LigaturesState discretionaryLigaturesState() const { return static_cast<LigaturesState>(m_discretionaryLigaturesState); } LigaturesState historicalLigaturesState() const { return static_cast<LigaturesState>(m_historicalLigaturesState); } + LigaturesState contextualLigaturesState() const { return static_cast<LigaturesState>(m_contextualLigaturesState); } unsigned keywordSize() const { return m_keywordSize; } FontSmoothingMode fontSmoothing() const { return static_cast<FontSmoothingMode>(m_fontSmoothing); } - TextRenderingMode textRenderingMode() const { return static_cast<TextRenderingMode>(m_textRendering); } + TextRenderingMode textRendering() const { return static_cast<TextRenderingMode>(m_textRendering); } UScriptCode script() const { return static_cast<UScriptCode>(m_script); } + const String& locale() const { return m_locale; } bool isSyntheticBold() const { return m_syntheticBold; } bool isSyntheticItalic() const { return m_syntheticItalic; } bool useSubpixelPositioning() const { return m_subpixelTextPosition; } - FontTraitsMask traitsMask() const; - bool isSpecifiedFont() const { return m_isSpecifiedFont; } + FontTraits traits() const; + float wordSpacing() const { return m_wordSpacing; } + float letterSpacing() const { return m_letterSpacing; } FontOrientation orientation() const { return static_cast<FontOrientation>(m_orientation); } NonCJKGlyphOrientation nonCJKGlyphOrientation() const { return static_cast<NonCJKGlyphOrientation>(m_nonCJKGlyphOrientation); } FontWidthVariant widthVariant() const { return static_cast<FontWidthVariant>(m_widthVariant); } @@ -140,69 +127,78 @@ public: FontDescription makeNormalFeatureSettings() const; float effectiveFontSize() const; // Returns either the computedSize or the computedPixelSize - FontCacheKey cacheKey(const AtomicString& familyName, FontTraitsMask desiredTraits = static_cast<FontTraitsMask>(0)) const; + FontCacheKey cacheKey(const AtomicString& familyName, FontTraits desiredTraits = FontTraits(0)) const; void setFamily(const FontFamily& family) { m_familyList = family; } void setComputedSize(float s) { m_computedSize = clampToFloat(s); } void setSpecifiedSize(float s) { m_specifiedSize = clampToFloat(s); } - void setItalic(FontItalic i) { m_italic = i; } - void setItalic(bool i) { setItalic(i ? FontItalicOn : FontItalicOff); } - void setSmallCaps(FontSmallCaps c) { m_smallCaps = c; } - void setSmallCaps(bool c) { setSmallCaps(c ? FontSmallCapsOn : FontSmallCapsOff); } + void setStyle(FontStyle i) { m_style = i; } + void setVariant(FontVariant c) { m_variant = c; } void setIsAbsoluteSize(bool s) { m_isAbsoluteSize = s; } void setWeight(FontWeight w) { m_weight = w; } + void setStretch(FontStretch s) { m_stretch = s; } void setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; } -#if OS(MACOSX) - void setUsePrinterFont(bool) { } -#else - void setUsePrinterFont(bool p) { m_usePrinterFont = p; } -#endif - void setKerning(Kerning kerning) { m_kerning = kerning; } - void setCommonLigaturesState(LigaturesState commonLigaturesState) { m_commonLigaturesState = commonLigaturesState; } - void setDiscretionaryLigaturesState(LigaturesState discretionaryLigaturesState) { m_discretionaryLigaturesState = discretionaryLigaturesState; } - void setHistoricalLigaturesState(LigaturesState historicalLigaturesState) { m_historicalLigaturesState = historicalLigaturesState; } + void setKerning(Kerning kerning) { m_kerning = kerning; updateTypesettingFeatures(); } + void setCommonLigaturesState(LigaturesState commonLigaturesState) { m_commonLigaturesState = commonLigaturesState; updateTypesettingFeatures(); } + void setDiscretionaryLigaturesState(LigaturesState discretionaryLigaturesState) { m_discretionaryLigaturesState = discretionaryLigaturesState; updateTypesettingFeatures(); } + void setHistoricalLigaturesState(LigaturesState historicalLigaturesState) { m_historicalLigaturesState = historicalLigaturesState; updateTypesettingFeatures(); } + void setContextualLigaturesState(LigaturesState contextualLigaturesState) { m_contextualLigaturesState = contextualLigaturesState; updateTypesettingFeatures(); } void setKeywordSize(unsigned s) { m_keywordSize = s; } void setFontSmoothing(FontSmoothingMode smoothing) { m_fontSmoothing = smoothing; } - void setTextRenderingMode(TextRenderingMode rendering) { m_textRendering = rendering; } - void setIsSpecifiedFont(bool isSpecifiedFont) { m_isSpecifiedFont = isSpecifiedFont; } + void setTextRendering(TextRenderingMode rendering) { m_textRendering = rendering; updateTypesettingFeatures(); } void setOrientation(FontOrientation orientation) { m_orientation = orientation; } void setNonCJKGlyphOrientation(NonCJKGlyphOrientation orientation) { m_nonCJKGlyphOrientation = orientation; } void setWidthVariant(FontWidthVariant widthVariant) { m_widthVariant = widthVariant; } void setScript(UScriptCode s) { m_script = s; } + void setLocale(const String& locale) { m_locale = locale; } void setSyntheticBold(bool syntheticBold) { m_syntheticBold = syntheticBold; } void setSyntheticItalic(bool syntheticItalic) { m_syntheticItalic = syntheticItalic; } void setFeatureSettings(PassRefPtr<FontFeatureSettings> settings) { m_featureSettings = settings; } - void setTraitsMask(FontTraitsMask); + void setTraits(FontTraits); + void setWordSpacing(float s) { m_wordSpacing = s; } + void setLetterSpacing(float s) { m_letterSpacing = s; } + + TypesettingFeatures typesettingFeatures() const { return static_cast<TypesettingFeatures>(m_typesettingFeatures); } static void setSubpixelPositioning(bool b) { s_useSubpixelTextPositioning = b; } static bool subpixelPositioning() { return s_useSubpixelTextPositioning; } + static void setDefaultTypesettingFeatures(TypesettingFeatures); + static TypesettingFeatures defaultTypesettingFeatures(); + private: FontFamily m_familyList; // The list of font families to be used. RefPtr<FontFeatureSettings> m_featureSettings; + String m_locale; + + void updateTypesettingFeatures() const; float m_specifiedSize; // Specified CSS value. Independent of rendering issues such as integer // rounding, minimum font sizes, and zooming. float m_computedSize; // Computed size adjusted for the minimum font size and the zoom factor. + float m_letterSpacing; + float m_wordSpacing; + unsigned m_orientation : 1; // FontOrientation - Whether the font is rendering on a horizontal line or a vertical line. unsigned m_nonCJKGlyphOrientation : 1; // NonCJKGlyphOrientation - Only used by vertical text. Determines the default orientation for non-ideograph glyphs. unsigned m_widthVariant : 2; // FontWidthVariant - unsigned m_italic : 1; // FontItalic - unsigned m_smallCaps : 1; // FontSmallCaps + unsigned m_style : 1; // FontStyle + unsigned m_variant : 1; // FontVariant unsigned m_isAbsoluteSize : 1; // Whether or not CSS specified an explicit size // (logical sizes like "medium" don't count). - unsigned m_weight : 8; // FontWeight + unsigned m_weight : 4; // FontWeight + unsigned m_stretch : 4; // FontStretch unsigned m_genericFamily : 3; // GenericFamilyType - unsigned m_usePrinterFont : 1; unsigned m_kerning : 2; // Kerning unsigned m_commonLigaturesState : 2; unsigned m_discretionaryLigaturesState : 2; unsigned m_historicalLigaturesState : 2; + unsigned m_contextualLigaturesState : 2; unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, // then we can accurately translate across different generic families to adjust for different preference settings @@ -210,12 +206,15 @@ private: unsigned m_fontSmoothing : 2; // FontSmoothingMode unsigned m_textRendering : 2; // TextRenderingMode - unsigned m_isSpecifiedFont : 1; // True if a web page specifies a non-generic font family as the first font family. unsigned m_script : 7; // Used to help choose an appropriate font for generic font families. unsigned m_syntheticBold : 1; unsigned m_syntheticItalic : 1; unsigned m_subpixelTextPosition : 1; + mutable unsigned m_typesettingFeatures : 2; // TypesettingFeatures + + static TypesettingFeatures s_defaultTypesettingFeatures; + static bool s_useSubpixelTextPositioning; }; @@ -224,20 +223,22 @@ inline bool FontDescription::operator==(const FontDescription& other) const return m_familyList == other.m_familyList && m_specifiedSize == other.m_specifiedSize && m_computedSize == other.m_computedSize - && m_italic == other.m_italic - && m_smallCaps == other.m_smallCaps + && m_letterSpacing == other.m_letterSpacing + && m_wordSpacing == other.m_wordSpacing + && m_style == other.m_style + && m_variant == other.m_variant && m_isAbsoluteSize == other.m_isAbsoluteSize && m_weight == other.m_weight + && m_stretch == other.m_stretch && m_genericFamily == other.m_genericFamily - && m_usePrinterFont == other.m_usePrinterFont && m_kerning == other.m_kerning && m_commonLigaturesState == other.m_commonLigaturesState && m_discretionaryLigaturesState == other.m_discretionaryLigaturesState && m_historicalLigaturesState == other.m_historicalLigaturesState + && m_contextualLigaturesState == other.m_contextualLigaturesState && m_keywordSize == other.m_keywordSize && m_fontSmoothing == other.m_fontSmoothing && m_textRendering == other.m_textRendering - && m_isSpecifiedFont == other.m_isSpecifiedFont && m_orientation == other.m_orientation && m_nonCJKGlyphOrientation == other.m_nonCJKGlyphOrientation && m_widthVariant == other.m_widthVariant diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontDescriptionTest.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontDescriptionTest.cpp new file mode 100644 index 00000000000..c53c4ad2fe7 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontDescriptionTest.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2014 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 AND ITS 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 APPLE OR ITS 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 "platform/fonts/FontDescription.h" + +#include <gtest/gtest.h> + +namespace WebCore { + + +static inline void assertDescriptionMatchesMask(FontDescription& source, FontTraitsMask mask) +{ + FontDescription target; + target.setTraits(FontTraits(mask)); + EXPECT_EQ(source.style(), target.style()); + EXPECT_EQ(source.variant(), target.variant()); + EXPECT_EQ(source.weight(), target.weight()); + EXPECT_EQ(source.stretch(), target.stretch()); +} + +TEST(FontDescriptionTest, TestFontTraits) +{ + FontDescription source; + source.setStyle(FontStyleNormal); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeightNormal); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleNormal); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeightNormal); + source.setStretch(FontStretchExtraCondensed); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight900); + source.setStretch(FontStretchUltraExpanded); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantSmallCaps); + source.setWeight(FontWeight100); + source.setStretch(FontStretchExtraExpanded); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight900); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight800); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight700); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight600); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight500); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight400); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight300); + source.setStretch(FontStretchUltraExpanded); + assertDescriptionMatchesMask(source, source.traits().mask()); + + source.setStyle(FontStyleItalic); + source.setVariant(FontVariantNormal); + source.setWeight(FontWeight200); + source.setStretch(FontStretchNormal); + assertDescriptionMatchesMask(source, source.traits().mask()); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp index c2169de65ad..e7dfc6ef6f3 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.cpp @@ -29,7 +29,7 @@ #include "config.h" #include "platform/fonts/FontFallbackList.h" -#include "FontFamilyNames.h" +#include "platform/FontFamilyNames.h" #include "platform/fonts/FontCache.h" #include "platform/fonts/FontDescription.h" #include "platform/fonts/FontFamily.h" @@ -40,16 +40,16 @@ namespace WebCore { FontFallbackList::FontFallbackList() : m_pageZero(0) , m_cachedPrimarySimpleFontData(0) - , m_fontSelector(0) + , m_fontSelector(nullptr) , m_fontSelectorVersion(0) , m_familyIndex(0) , m_generation(FontCache::fontCache()->generation()) , m_pitch(UnknownPitch) - , m_loadingCustomFonts(false) + , m_hasLoadingFallback(false) { } -void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector) +void FontFallbackList::invalidate(PassRefPtrWillBeRawPtr<FontSelector> fontSelector) { releaseFontData(); m_fontList.clear(); @@ -58,7 +58,7 @@ void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector) m_cachedPrimarySimpleFontData = 0; m_familyIndex = 0; m_pitch = UnknownPitch; - m_loadingCustomFonts = false; + m_hasLoadingFallback = false; m_fontSelector = fontSelector; m_fontSelectorVersion = m_fontSelector ? m_fontSelector->version() : 0; m_generation = FontCache::fontCache()->generation(); @@ -93,39 +93,62 @@ void FontFallbackList::determinePitch(const FontDescription& fontDescription) co bool FontFallbackList::loadingCustomFonts() const { - if (m_loadingCustomFonts) - return true; + if (!m_hasLoadingFallback) + return false; unsigned numFonts = m_fontList.size(); for (unsigned i = 0; i < numFonts; ++i) { - if (m_fontList[i]->isCustomFont() && m_fontList[i]->isLoading()) { - m_loadingCustomFonts = true; + if (m_fontList[i]->isLoading()) + return true; + } + return false; +} + +bool FontFallbackList::shouldSkipDrawing() const +{ + if (!m_hasLoadingFallback) + return false; + + unsigned numFonts = m_fontList.size(); + for (unsigned i = 0; i < numFonts; ++i) { + if (m_fontList[i]->shouldSkipDrawing()) return true; - } } return false; } const FontData* FontFallbackList::primaryFontData(const FontDescription& fontDescription) const { + bool shouldLoadCustomFont = true; + for (unsigned fontIndex = 0; ; ++fontIndex) { const FontData* fontData = fontDataAt(fontDescription, fontIndex); if (!fontData) { // All fonts are custom fonts and are loading. Return the first FontData. - // FIXME: Correct fallback to the default font. - return fontDataAt(fontDescription, 0); + fontData = fontDataAt(fontDescription, 0); + if (fontData) + return fontData->fontDataForCharacter(' '); + + SimpleFontData* lastResortFallback = FontCache::fontCache()->getLastResortFallbackFont(fontDescription).get(); + ASSERT(lastResortFallback); + return lastResortFallback; } + if (fontData->isSegmented() && !toSegmentedFontData(fontData)->containsCharacter(' ')) + continue; + + const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(' '); + ASSERT(simpleFontData); + // When a custom font is loading, we should use the correct fallback font to layout the text. // Here skip the temporary font for the loading custom font which may not act as the correct fallback font. - if (!fontData->isLoadingFallback()) + if (!simpleFontData->isLoadingFallback()) return fontData; // Begin to load the first custom font if needed. - if (!fontIndex) { - const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(' '); - if (simpleFontData && simpleFontData->customFontData()) - simpleFontData->customFontData()->beginLoadIfNeeded(); + if (shouldLoadCustomFont) { + shouldLoadCustomFont = false; + simpleFontData->customFontData()->beginLoadIfNeeded(); } } } @@ -190,17 +213,10 @@ const FontData* FontFallbackList::fontDataAt(const FontDescription& fontDescript RefPtr<FontData> result = getFontData(fontDescription, m_familyIndex); if (result) { m_fontList.append(result); - if (result->isLoading()) - m_loadingCustomFonts = true; + if (result->isLoadingFallback()) + m_hasLoadingFallback = true; } return result.get(); } -void FontFallbackList::setPlatformFont(const FontPlatformData& platformData) -{ - m_familyIndex = cAllFamiliesScanned; - RefPtr<FontData> fontData = FontCache::fontCache()->fontDataFromFontPlatformData(&platformData); - m_fontList.append(fontData); -} - } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.h b/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.h index 71fb526cc3e..162972fd786 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontFallbackList.h @@ -67,7 +67,7 @@ public: static PassRefPtr<FontFallbackList> create() { return adoptRef(new FontFallbackList()); } ~FontFallbackList() { releaseFontData(); } - void invalidate(PassRefPtr<FontSelector>); + void invalidate(PassRefPtrWillBeRawPtr<FontSelector>); bool isFixedPitch(const FontDescription& fontDescription) const { @@ -78,6 +78,7 @@ public: void determinePitch(const FontDescription&) const; bool loadingCustomFonts() const; + bool shouldSkipDrawing() const; FontSelector* fontSelector() const { return m_fontSelector.get(); } // FIXME: It should be possible to combine fontSelectorVersion and generation. @@ -102,21 +103,19 @@ private: const FontData* primaryFontData(const FontDescription&) const; const FontData* fontDataAt(const FontDescription&, unsigned index) const; - void setPlatformFont(const FontPlatformData&); - void releaseFontData(); mutable Vector<RefPtr<FontData>, 1> m_fontList; mutable GlyphPages m_pages; mutable GlyphPageTreeNode* m_pageZero; mutable const SimpleFontData* m_cachedPrimarySimpleFontData; - RefPtr<FontSelector> m_fontSelector; + RefPtrWillBePersistent<FontSelector> m_fontSelector; mutable WidthCache m_widthCache; unsigned m_fontSelectorVersion; mutable int m_familyIndex; unsigned short m_generation; mutable unsigned m_pitch : 3; // Pitch - mutable bool m_loadingCustomFonts : 1; + mutable bool m_hasLoadingFallback : 1; friend class Font; }; diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontFastPath.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontFastPath.cpp deleted file mode 100644 index 2d5e8ee29b7..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontFastPath.cpp +++ /dev/null @@ -1,621 +0,0 @@ -/** - * Copyright (C) 2003, 2006, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2008 Holger Hans Peter Freyther - * Copyright (C) 2009 Torch Mobile, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "platform/fonts/Font.h" - -#include "platform/LayoutUnit.h" -#include "platform/fonts/FontCache.h" -#include "platform/fonts/FontFallbackList.h" -#include "platform/fonts/GlyphPageTreeNode.h" -#include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/WidthIterator.h" -#include "platform/fonts/GlyphBuffer.h" -#include "platform/geometry/FloatRect.h" -#include "platform/text/TextRun.h" -#include "wtf/MainThread.h" -#include "wtf/MathExtras.h" -#include "wtf/unicode/CharacterNames.h" -#include "wtf/unicode/Unicode.h" - -using namespace WTF; -using namespace Unicode; -using namespace std; - -namespace WebCore { - -static inline bool isInRange(UChar32 character, UChar32 lowerBound, UChar32 upperBound) -{ - return character >= lowerBound && character <= upperBound; -} - -static bool shouldIgnoreRotation(UChar32 character) -{ - if (character == 0x000A7 || character == 0x000A9 || character == 0x000AE) - return true; - - if (character == 0x000B6 || character == 0x000BC || character == 0x000BD || character == 0x000BE) - return true; - - if (isInRange(character, 0x002E5, 0x002EB)) - return true; - - if (isInRange(character, 0x01100, 0x011FF) || isInRange(character, 0x01401, 0x0167F) || isInRange(character, 0x01800, 0x018FF)) - return true; - - if (character == 0x02016 || character == 0x02018 || character == 0x02019 || character == 0x02020 || character == 0x02021 - || character == 0x2030 || character == 0x02031) - return true; - - if (isInRange(character, 0x0203B, 0x0203D) || character == 0x02042 || character == 0x02044 || character == 0x02047 - || character == 0x02048 || character == 0x02049 || character == 0x2051) - return true; - - if (isInRange(character, 0x02065, 0x02069) || isInRange(character, 0x020DD, 0x020E0) - || isInRange(character, 0x020E2, 0x020E4) || isInRange(character, 0x02100, 0x02117) - || isInRange(character, 0x02119, 0x02131) || isInRange(character, 0x02133, 0x0213F)) - return true; - - if (isInRange(character, 0x02145, 0x0214A) || character == 0x0214C || character == 0x0214D - || isInRange(character, 0x0214F, 0x0218F)) - return true; - - if (isInRange(character, 0x02300, 0x02307) || isInRange(character, 0x0230C, 0x0231F) - || isInRange(character, 0x02322, 0x0232B) || isInRange(character, 0x0237D, 0x0239A) - || isInRange(character, 0x023B4, 0x023B6) || isInRange(character, 0x023BA, 0x023CF) - || isInRange(character, 0x023D1, 0x023DB) || isInRange(character, 0x023E2, 0x024FF)) - return true; - - if (isInRange(character, 0x025A0, 0x02619) || isInRange(character, 0x02620, 0x02767) - || isInRange(character, 0x02776, 0x02793) || isInRange(character, 0x02B12, 0x02B2F) - || isInRange(character, 0x02B4D, 0x02BFF) || isInRange(character, 0x02E80, 0x03007)) - return true; - - if (character == 0x03012 || character == 0x03013 || isInRange(character, 0x03020, 0x0302F) - || isInRange(character, 0x03031, 0x0309F) || isInRange(character, 0x030A1, 0x030FB) - || isInRange(character, 0x030FD, 0x0A4CF)) - return true; - - if (isInRange(character, 0x0A840, 0x0A87F) || isInRange(character, 0x0A960, 0x0A97F) - || isInRange(character, 0x0AC00, 0x0D7FF) || isInRange(character, 0x0E000, 0x0FAFF)) - return true; - - if (isInRange(character, 0x0FE10, 0x0FE1F) || isInRange(character, 0x0FE30, 0x0FE48) - || isInRange(character, 0x0FE50, 0x0FE57) || isInRange(character, 0x0FE5F, 0x0FE62) - || isInRange(character, 0x0FE67, 0x0FE6F)) - return true; - - if (isInRange(character, 0x0FF01, 0x0FF07) || isInRange(character, 0x0FF0A, 0x0FF0C) - || isInRange(character, 0x0FF0E, 0x0FF19) ||isInRange (character, 0x0FF1F, 0x0FF3A)) - return true; - - if (character == 0x0FF3C || character == 0x0FF3E) - return true; - - if (isInRange(character, 0x0FF40, 0x0FF5A) || isInRange(character, 0x0FFE0, 0x0FFE2) - || isInRange(character, 0x0FFE4, 0x0FFE7) || isInRange(character, 0x0FFF0, 0x0FFF8) - || character == 0x0FFFD) - return true; - - if (isInRange(character, 0x13000, 0x1342F) || isInRange(character, 0x1B000, 0x1B0FF) - || isInRange(character, 0x1D000, 0x1D1FF) || isInRange(character, 0x1D300, 0x1D37F) - || isInRange(character, 0x1F000, 0x1F64F) || isInRange(character, 0x1F680, 0x1F77F)) - return true; - - if (isInRange(character, 0x20000, 0x2FFFD) || isInRange(character, 0x30000, 0x3FFFD)) - return true; - - return false; -} - -static inline std::pair<GlyphData, GlyphPage*> glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(UChar32 character, NonCJKGlyphOrientation orientation, GlyphData& data, GlyphPage* page, unsigned pageNumber) -{ - if (orientation == NonCJKGlyphOrientationUpright || shouldIgnoreRotation(character)) { - RefPtr<SimpleFontData> uprightFontData = data.fontData->uprightOrientationFontData(); - GlyphPageTreeNode* uprightNode = GlyphPageTreeNode::getRootChild(uprightFontData.get(), pageNumber); - GlyphPage* uprightPage = uprightNode->page(); - if (uprightPage) { - GlyphData uprightData = uprightPage->glyphDataForCharacter(character); - // If the glyphs are the same, then we know we can just use the horizontal glyph rotated vertically to be upright. - if (data.glyph == uprightData.glyph) - return make_pair(data, page); - // The glyphs are distinct, meaning that the font has a vertical-right glyph baked into it. We can't use that - // glyph, so we fall back to the upright data and use the horizontal glyph. - if (uprightData.fontData) - return make_pair(uprightData, uprightPage); - } - } else if (orientation == NonCJKGlyphOrientationVerticalRight) { - RefPtr<SimpleFontData> verticalRightFontData = data.fontData->verticalRightOrientationFontData(); - GlyphPageTreeNode* verticalRightNode = GlyphPageTreeNode::getRootChild(verticalRightFontData.get(), pageNumber); - GlyphPage* verticalRightPage = verticalRightNode->page(); - if (verticalRightPage) { - GlyphData verticalRightData = verticalRightPage->glyphDataForCharacter(character); - // If the glyphs are distinct, we will make the assumption that the font has a vertical-right glyph baked - // into it. - if (data.glyph != verticalRightData.glyph) - return make_pair(data, page); - // The glyphs are identical, meaning that we should just use the horizontal glyph. - if (verticalRightData.fontData) - return make_pair(verticalRightData, verticalRightPage); - } - } - return make_pair(data, page); -} - -std::pair<GlyphData, GlyphPage*> Font::glyphDataAndPageForCharacter(UChar32 c, bool mirror, FontDataVariant variant) const -{ - ASSERT(isMainThread()); - - if (variant == AutoVariant) { - if (m_fontDescription.smallCaps() && !primaryFont()->isSVGFont()) { - UChar32 upperC = toUpper(c); - if (upperC != c) { - c = upperC; - variant = SmallCapsVariant; - } else - variant = NormalVariant; - } else - variant = NormalVariant; - } - - if (mirror) - c = mirroredChar(c); - - unsigned pageNumber = (c / GlyphPage::size); - - GlyphPageTreeNode* node = pageNumber ? m_fontFallbackList->m_pages.get(pageNumber) : m_fontFallbackList->m_pageZero; - if (!node) { - node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); - if (pageNumber) - m_fontFallbackList->m_pages.set(pageNumber, node); - else - m_fontFallbackList->m_pageZero = node; - } - - GlyphPage* page = 0; - if (variant == NormalVariant) { - // Fastest loop, for the common case (normal variant). - while (true) { - page = node->page(); - if (page) { - GlyphData data = page->glyphDataForCharacter(c); - if (data.fontData && (data.fontData->platformData().orientation() == Horizontal || data.fontData->isTextOrientationFallback())) - return make_pair(data, page); - - if (data.fontData) { - if (isCJKIdeographOrSymbol(c)) { - if (!data.fontData->hasVerticalGlyphs()) { - // Use the broken ideograph font data. The broken ideograph font will use the horizontal width of glyphs - // to make sure you get a square (even for broken glyphs like symbols used for punctuation). - variant = BrokenIdeographVariant; - break; - } - } else - return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, page, pageNumber); - - return make_pair(data, page); - } - - if (node->isSystemFallback()) - break; - } - - // Proceed with the fallback list. - node = node->getChild(fontDataAt(node->level()), pageNumber); - if (pageNumber) - m_fontFallbackList->m_pages.set(pageNumber, node); - else - m_fontFallbackList->m_pageZero = node; - } - } - if (variant != NormalVariant) { - while (true) { - page = node->page(); - if (page) { - GlyphData data = page->glyphDataForCharacter(c); - if (data.fontData) { - // The variantFontData function should not normally return 0. - // But if it does, we will just render the capital letter big. - RefPtr<SimpleFontData> variantFontData = data.fontData->variantFontData(m_fontDescription, variant); - if (!variantFontData) - return make_pair(data, page); - - GlyphPageTreeNode* variantNode = GlyphPageTreeNode::getRootChild(variantFontData.get(), pageNumber); - GlyphPage* variantPage = variantNode->page(); - if (variantPage) { - GlyphData data = variantPage->glyphDataForCharacter(c); - if (data.fontData) - return make_pair(data, variantPage); - } - - // Do not attempt system fallback off the variantFontData. This is the very unlikely case that - // a font has the lowercase character but the small caps font does not have its uppercase version. - return make_pair(variantFontData->missingGlyphData(), page); - } - - if (node->isSystemFallback()) - break; - } - - // Proceed with the fallback list. - node = node->getChild(fontDataAt(node->level()), pageNumber); - if (pageNumber) - m_fontFallbackList->m_pages.set(pageNumber, node); - else - m_fontFallbackList->m_pageZero = node; - } - } - - ASSERT(page); - ASSERT(node->isSystemFallback()); - - // System fallback is character-dependent. When we get here, we - // know that the character in question isn't in the system fallback - // font's glyph page. Try to lazily create it here. - - // FIXME: Unclear if this should normalizeSpaces above 0xFFFF. - // Doing so changes fast/text/international/plane2-diffs.html - UChar32 characterToRender = c; - if (characterToRender <= 0xFFFF) - characterToRender = Font::normalizeSpaces(characterToRender); - const SimpleFontData* fontDataToSubstitute = fontDataAt(0)->fontDataForCharacter(characterToRender); - RefPtr<SimpleFontData> characterFontData = FontCache::fontCache()->platformFallbackForCharacter(m_fontDescription, characterToRender, fontDataToSubstitute, isPlatformFont()); - if (characterFontData) { - if (characterFontData->platformData().orientation() == Vertical && !characterFontData->hasVerticalGlyphs() && isCJKIdeographOrSymbol(c)) - variant = BrokenIdeographVariant; - if (variant != NormalVariant) - characterFontData = characterFontData->variantFontData(m_fontDescription, variant); - } - if (characterFontData) { - // Got the fallback glyph and font. - GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData.get(), pageNumber)->page(); - GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); - // Cache it so we don't have to do system fallback again next time. - if (variant == NormalVariant) { - page->setGlyphDataForCharacter(c, data.glyph, data.fontData); - data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level())); - if (!isCJKIdeographOrSymbol(c) && data.fontData->platformData().orientation() != Horizontal && !data.fontData->isTextOrientationFallback()) - return glyphDataAndPageForNonCJKCharacterWithGlyphOrientation(c, m_fontDescription.nonCJKGlyphOrientation(), data, fallbackPage, pageNumber); - } - return make_pair(data, page); - } - - // Even system fallback can fail; use the missing glyph in that case. - // FIXME: It would be nicer to use the missing glyph from the last resort font instead. - GlyphData data = primaryFont()->missingGlyphData(); - if (variant == NormalVariant) { - page->setGlyphDataForCharacter(c, data.glyph, data.fontData); - data.fontData->setMaxGlyphPageTreeLevel(max(data.fontData->maxGlyphPageTreeLevel(), node->level())); - } - return make_pair(data, page); -} - -bool Font::primaryFontHasGlyphForCharacter(UChar32 character) const -{ - unsigned pageNumber = (character / GlyphPage::size); - - GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(primaryFont(), pageNumber); - GlyphPage* page = node->page(); - - return page && page->fontDataForCharacter(character); -} - -// FIXME: This function may not work if the emphasis mark uses a complex script, but none of the -// standard emphasis marks do so. -bool Font::getEmphasisMarkGlyphData(const AtomicString& mark, GlyphData& glyphData) const -{ - if (mark.isEmpty()) - return false; - - UChar32 character = mark[0]; - - if (U16_IS_SURROGATE(character)) { - if (!U16_IS_SURROGATE_LEAD(character)) - return false; - - if (mark.length() < 2) - return false; - - UChar low = mark[1]; - if (!U16_IS_TRAIL(low)) - return false; - - character = U16_GET_SUPPLEMENTARY(character, low); - } - - glyphData = glyphDataForCharacter(character, false, EmphasisMarkVariant); - return true; -} - -int Font::emphasisMarkAscent(const AtomicString& mark) const -{ - FontCachePurgePreventer purgePreventer; - - GlyphData markGlyphData; - if (!getEmphasisMarkGlyphData(mark, markGlyphData)) - return 0; - - const SimpleFontData* markFontData = markGlyphData.fontData; - ASSERT(markFontData); - if (!markFontData) - return 0; - - return markFontData->fontMetrics().ascent(); -} - -int Font::emphasisMarkDescent(const AtomicString& mark) const -{ - FontCachePurgePreventer purgePreventer; - - GlyphData markGlyphData; - if (!getEmphasisMarkGlyphData(mark, markGlyphData)) - return 0; - - const SimpleFontData* markFontData = markGlyphData.fontData; - ASSERT(markFontData); - if (!markFontData) - return 0; - - return markFontData->fontMetrics().descent(); -} - -int Font::emphasisMarkHeight(const AtomicString& mark) const -{ - FontCachePurgePreventer purgePreventer; - - GlyphData markGlyphData; - if (!getEmphasisMarkGlyphData(mark, markGlyphData)) - return 0; - - const SimpleFontData* markFontData = markGlyphData.fontData; - ASSERT(markFontData); - if (!markFontData) - return 0; - - return markFontData->fontMetrics().height(); -} - -float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const -{ - float initialAdvance; - - WidthIterator it(this, run, 0, false, forTextEmphasis); - // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or - // ligatures are enabled. - GlyphBuffer localGlyphBuffer; - it.advance(from, &localGlyphBuffer); - float beforeWidth = it.m_runWidthSoFar; - it.advance(to, &glyphBuffer); - - if (glyphBuffer.isEmpty()) - return 0; - - float afterWidth = it.m_runWidthSoFar; - - if (run.rtl()) { - float finalRoundingWidth = it.m_finalRoundingWidth; - it.advance(run.length(), &localGlyphBuffer); - initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth; - } else - initialAdvance = beforeWidth; - - if (run.rtl()) - glyphBuffer.reverse(0, glyphBuffer.size()); - - return initialAdvance; -} - -void Font::drawSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point) const -{ - // This glyph buffer holds our glyphs+advances+font data for each glyph. - GlyphBuffer glyphBuffer; - - float startX = point.x() + getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer); - - if (glyphBuffer.isEmpty()) - return; - - FloatPoint startPoint(startX, point.y()); - drawGlyphBuffer(context, runInfo, glyphBuffer, startPoint); -} - -void Font::drawEmphasisMarksForSimpleText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const -{ - GlyphBuffer glyphBuffer; - float initialAdvance = getGlyphsAndAdvancesForSimpleText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer, ForTextEmphasis); - - if (glyphBuffer.isEmpty()) - return; - - drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); -} - -void Font::drawGlyphBuffer(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const FloatPoint& point) const -{ - // Draw each contiguous run of glyphs that use the same font data. - const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); - FloatPoint startPoint(point); - float nextX = startPoint.x() + glyphBuffer.advanceAt(0); - unsigned lastFrom = 0; - unsigned nextGlyph = 1; -#if ENABLE(SVG_FONTS) - TextRun::RenderingContext* renderingContext = runInfo.run.renderingContext(); -#endif - while (nextGlyph < glyphBuffer.size()) { - const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); - - if (nextFontData != fontData) { -#if ENABLE(SVG_FONTS) - if (renderingContext && fontData->isSVGFont()) - renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); - else -#endif - drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); - - lastFrom = nextGlyph; - fontData = nextFontData; - startPoint.setX(nextX); - } - nextX += glyphBuffer.advanceAt(nextGlyph); - nextGlyph++; - } - -#if ENABLE(SVG_FONTS) - if (renderingContext && fontData->isSVGFont()) - renderingContext->drawSVGGlyphs(context, runInfo.run, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); - else -#endif - drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint, runInfo.bounds); -} - -inline static float offsetToMiddleOfGlyph(const SimpleFontData* fontData, Glyph glyph) -{ - if (fontData->platformData().orientation() == Horizontal) { - FloatRect bounds = fontData->boundsForGlyph(glyph); - return bounds.x() + bounds.width() / 2; - } - // FIXME: Use glyph bounds once they make sense for vertical fonts. - return fontData->widthForGlyph(glyph) / 2; -} - -inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i) -{ - return offsetToMiddleOfGlyph(glyphBuffer.fontDataAt(i), glyphBuffer.glyphAt(i)); -} - -void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const -{ - FontCachePurgePreventer purgePreventer; - - GlyphData markGlyphData; - if (!getEmphasisMarkGlyphData(mark, markGlyphData)) - return; - - const SimpleFontData* markFontData = markGlyphData.fontData; - ASSERT(markFontData); - if (!markFontData) - return; - - Glyph markGlyph = markGlyphData.glyph; - Glyph spaceGlyph = markFontData->spaceGlyph(); - - float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0); - FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y()); - - GlyphBuffer markBuffer; - for (unsigned i = 0; i + 1 < glyphBuffer.size(); ++i) { - float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1); - float advance = glyphBuffer.advanceAt(i) - middleOfLastGlyph + middleOfNextGlyph; - markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance); - middleOfLastGlyph = middleOfNextGlyph; - } - markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0); - - drawGlyphBuffer(context, runInfo, markBuffer, startPoint); -} - -float Font::floatWidthForSimpleText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const -{ - WidthIterator it(this, run, fallbackFonts, glyphOverflow); - GlyphBuffer glyphBuffer; - it.advance(run.length(), (typesettingFeatures() & (Kerning | Ligatures)) ? &glyphBuffer : 0); - - if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); - glyphOverflow->left = ceilf(it.firstGlyphOverflow()); - glyphOverflow->right = ceilf(it.lastGlyphOverflow()); - } - - return it.m_runWidthSoFar; -} - -FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const -{ - GlyphBuffer glyphBuffer; - WidthIterator it(this, run); - it.advance(from, &glyphBuffer); - float beforeWidth = it.m_runWidthSoFar; - it.advance(to, &glyphBuffer); - float afterWidth = it.m_runWidthSoFar; - - // Using roundf() rather than ceilf() for the right edge as a compromise to - // ensure correct caret positioning. - // Use LayoutUnit::epsilon() to ensure that values that cannot be stored as - // an integer are floored to n and not n-1 due to floating point imprecision. - if (run.rtl()) { - it.advance(run.length(), &glyphBuffer); - float totalWidth = it.m_runWidthSoFar; - float pixelAlignedX = floorf(point.x() + totalWidth - afterWidth + LayoutUnit::epsilon()); - return FloatRect(pixelAlignedX, point.y(), - roundf(point.x() + totalWidth - beforeWidth) - pixelAlignedX, h); - } - - float pixelAlignedX = floorf(point.x() + beforeWidth + LayoutUnit::epsilon()); - return FloatRect(pixelAlignedX, point.y(), - roundf(point.x() + afterWidth) - pixelAlignedX, h); -} - -int Font::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const -{ - float delta = x; - - WidthIterator it(this, run); - GlyphBuffer localGlyphBuffer; - unsigned offset; - if (run.rtl()) { - delta -= floatWidthForSimpleText(run); - while (1) { - offset = it.m_currentCharacter; - float w; - if (!it.advanceOneCharacter(w, localGlyphBuffer)) - break; - delta += w; - if (includePartialGlyphs) { - if (delta - w / 2 >= 0) - break; - } else { - if (delta >= 0) - break; - } - } - } else { - while (1) { - offset = it.m_currentCharacter; - float w; - if (!it.advanceOneCharacter(w, localGlyphBuffer)) - break; - delta -= w; - if (includePartialGlyphs) { - if (delta + w / 2 <= 0) - break; - } else { - if (delta <= 0) - break; - } - } - } - - return offset; -} - -} diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontMetrics.h b/chromium/third_party/WebKit/Source/platform/fonts/FontMetrics.h index dafed6a476f..1d4ff32593f 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontMetrics.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontMetrics.h @@ -37,6 +37,8 @@ public: , m_lineSpacing(0) , m_xHeight(0) , m_zeroWidth(0) + , m_underlinethickness(0) + , m_underlinePosition(0) , m_hasXHeight(false) , m_hasZeroWidth(false) { @@ -122,6 +124,12 @@ public: bool hasZeroWidth() const { return m_hasZeroWidth; } void setHasZeroWidth(bool hasZeroWidth) { m_hasZeroWidth = hasZeroWidth; } + float underlineThickness() const { return m_underlinethickness; } + void setUnderlineThickness(float underlineThickness) { m_underlinethickness = underlineThickness; } + + float underlinePosition() const { return m_underlinePosition; } + void setUnderlinePosition(float underlinePosition) { m_underlinePosition = underlinePosition; } + private: friend class SimpleFontData; @@ -134,6 +142,8 @@ private: m_lineSpacing = 0; m_xHeight = 0; m_hasXHeight = false; + m_underlinethickness = 0; + m_underlinePosition = 0; } unsigned m_unitsPerEm; @@ -143,6 +153,8 @@ private: float m_lineSpacing; float m_xHeight; float m_zeroWidth; + float m_underlinethickness; + float m_underlinePosition; bool m_hasXHeight; bool m_hasZeroWidth; }; diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp index 85667d93cb1..ab891966e16 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.cpp @@ -45,9 +45,6 @@ FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType) #endif , m_isColorBitmapFont(false) , m_isCompositeFontReference(false) -#if OS(MACOSX) - , m_isPrinterFont(false) -#endif { } @@ -62,9 +59,6 @@ FontPlatformData::FontPlatformData() #endif , m_isColorBitmapFont(false) , m_isCompositeFontReference(false) -#if OS(MACOSX) - , m_isPrinterFont(false) -#endif { } @@ -79,9 +73,6 @@ FontPlatformData::FontPlatformData(float size, bool syntheticBold, bool syntheti #endif , m_isColorBitmapFont(false) , m_isCompositeFontReference(false) -#if OS(MACOSX) - , m_isPrinterFont(false) -#endif { } @@ -96,7 +87,6 @@ FontPlatformData::FontPlatformData(CGFontRef cgFont, float size, bool syntheticB , m_cgFont(cgFont) , m_isColorBitmapFont(false) , m_isCompositeFontReference(false) - , m_isPrinterFont(false) { } #endif @@ -109,9 +99,6 @@ FontPlatformData::FontPlatformData(const FontPlatformData& source) , m_widthVariant(source.m_widthVariant) , m_isColorBitmapFont(source.m_isColorBitmapFont) , m_isCompositeFontReference(source.m_isCompositeFontReference) -#if OS(MACOSX) - , m_isPrinterFont(source.m_isPrinterFont) -#endif { platformDataInit(source); } @@ -129,9 +116,6 @@ const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& othe m_widthVariant = other.m_widthVariant; m_isColorBitmapFont = other.m_isColorBitmapFont; m_isCompositeFontReference = other.m_isCompositeFontReference; -#if OS(MACOSX) - m_isPrinterFont = other.m_isPrinterFont; -#endif return platformDataAssign(other); } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.h b/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.h index 062a67f85b3..f45b6bb0f87 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformData.h @@ -22,10 +22,8 @@ * */ -// FIXME: This is temporary until all ports switch to using this file. -#if OS(WIN) -#include "platform/fonts/win/FontPlatformDataWin.h" -#elif !OS(MACOSX) +// FIXME: This is temporary until mac switch to using FontPlatformDataHarfBuzz.h and we merge it with this file. +#if !OS(MACOSX) #include "platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h" #else @@ -56,6 +54,7 @@ typedef const struct __CTFont* CTFontRef; #if OS(MACOSX) #include "platform/fonts/mac/MemoryActivatedFont.h" +#include "third_party/skia/include/core/SkTypeface.h" #endif #if OS(MACOSX) @@ -88,7 +87,7 @@ public: FontPlatformData(float size, bool syntheticBold, bool syntheticOblique, FontOrientation = Horizontal, FontWidthVariant = RegularWidth); #if OS(MACOSX) - FontPlatformData(NSFont*, float size, bool isPrinterFont = false, bool syntheticBold = false, bool syntheticOblique = false, + FontPlatformData(NSFont*, float size, bool syntheticBold = false, bool syntheticOblique = false, FontOrientation = Horizontal, FontWidthVariant = RegularWidth); FontPlatformData(CGFontRef, float size, bool syntheticBold, bool syntheticOblique, FontOrientation, FontWidthVariant); #endif @@ -103,6 +102,7 @@ public: #if OS(MACOSX) CGFontRef cgFont() const { return m_cgFont.get(); } CTFontRef ctFont() const; + SkTypeface* typeface() const; bool roundsGlyphAdvances() const; bool allowsLigatures() const; @@ -116,9 +116,7 @@ public: bool syntheticOblique() const { return m_syntheticOblique; } bool isColorBitmapFont() const { return m_isColorBitmapFont; } bool isCompositeFontReference() const { return m_isCompositeFontReference; } -#if OS(MACOSX) - bool isPrinterFont() const { return m_isPrinterFont; } -#endif + FontOrientation orientation() const { return m_orientation; } FontWidthVariant widthVariant() const { return m_widthVariant; } @@ -132,7 +130,7 @@ public: { #if OS(MACOSX) ASSERT(m_font || !m_cgFont); - uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, static_cast<uintptr_t>(m_isPrinterFont << 3 | m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique) }; + uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, static_cast<uintptr_t>(m_orientation << 2 | m_syntheticBold << 1 | m_syntheticOblique) }; return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); #endif } @@ -147,9 +145,6 @@ public: && m_syntheticOblique == other.m_syntheticOblique && m_isColorBitmapFont == other.m_isColorBitmapFont && m_isCompositeFontReference == other.m_isCompositeFontReference -#if OS(MACOSX) - && m_isPrinterFont == other.m_isPrinterFont -#endif && m_orientation == other.m_orientation && m_widthVariant == other.m_widthVariant; } @@ -198,13 +193,11 @@ private: RefPtr<MemoryActivatedFont> m_inMemoryFont; RefPtr<HarfBuzzFace> m_harfBuzzFace; + mutable RefPtr<SkTypeface> m_typeface; #endif bool m_isColorBitmapFont; bool m_isCompositeFontReference; -#if OS(MACOSX) - bool m_isPrinterFont; -#endif }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/GlyphPageTreeNodeSkia.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformFeatures.h index 72c20972fc9..da59bc740fe 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/GlyphPageTreeNodeSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontPlatformFeatures.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Google Inc. All rights reserved. + * Copyright (C) 2014 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 @@ -28,38 +28,22 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "platform/fonts/GlyphPageTreeNode.h" +#ifndef FontPlatformFeatures_h +#define FontPlatformFeatures_h -#include "platform/fonts/SimpleFontData.h" - -#include "SkPaint.h" -#include "SkTemplates.h" -#include "SkTypeface.h" -#include "SkUtils.h" +#include "platform/PlatformExport.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; - } - - SkAutoSTMalloc<GlyphPage::size, uint16_t> glyphStorage(length); - - uint16_t* glyphs = glyphStorage.get(); - SkTypeface* typeface = fontData->platformData().typeface(); - typeface->charsToGlyphs(buffer, SkTypeface::kUTF16_Encoding, glyphs, length); +class FontPlatformFeatures { +public: + static bool canReturnFallbackFontsForComplexText(); + static bool canExpandAroundIdeographsInComplexText(); - 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]; - } +private: + FontPlatformFeatures(); +}; - return allGlyphs != 0; } -} // namespace WebCore +#endif diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontSelector.h b/chromium/third_party/WebKit/Source/platform/fonts/FontSelector.h index 1225ffc783c..5c0db42ad1d 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontSelector.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontSelector.h @@ -26,37 +26,25 @@ #ifndef FontSelector_h #define FontSelector_h +#include "platform/fonts/FontCacheClient.h" #include "wtf/Forward.h" #include "wtf/PassRefPtr.h" -#include "wtf/RefCounted.h" +#include "wtf/text/AtomicString.h" namespace WebCore { class FontData; class FontDescription; -class FontSelectorClient; -class FontSelector : public RefCounted<FontSelector> { +class FontSelector : public FontCacheClient { public: virtual ~FontSelector() { } virtual PassRefPtr<FontData> getFontData(const FontDescription&, const AtomicString& familyName) = 0; - virtual void willUseFontData(const FontDescription&, const AtomicString& familyName) = 0; - - virtual void fontCacheInvalidated() { } - - virtual void registerForInvalidationCallbacks(FontSelectorClient*) = 0; - virtual void unregisterForInvalidationCallbacks(FontSelectorClient*) = 0; + virtual void willUseFontData(const FontDescription&, const AtomicString& familyName, UChar32) = 0; virtual unsigned version() const = 0; }; -class FontSelectorClient { -public: - virtual ~FontSelectorClient() { } - - virtual void fontsNeedUpdate(FontSelector*) = 0; -}; - } // namespace WebCore #endif // FontSelector_h diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontTest.cpp b/chromium/third_party/WebKit/Source/platform/fonts/FontTest.cpp index e4b6e14c91e..e54c19fa6f4 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontTest.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontTest.cpp @@ -27,6 +27,7 @@ #include "config.h" +#include "platform/fonts/Character.h" #include "platform/fonts/Font.h" #include <gtest/gtest.h> @@ -47,17 +48,17 @@ static void TestSpecificUCharRange(UChar rangeStart, UChar rangeEnd) end[0] = rangeEnd; above[0] = rangeEnd + 1; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(below, 1)); - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(start, 1)); - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(midway, 1)); - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(end, 1)); - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(above, 1)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(below, 1)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(start, 1)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(midway, 1)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(end, 1)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(above, 1)); } TEST(FontTest, TestCharacterRangeCodePath) { static UChar c1[] = { 0x0 }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c1, 1)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c1, 1)); TestSpecificUCharRange(0x2E5, 0x2E9); TestSpecificUCharRange(0x300, 0x36F); @@ -72,19 +73,19 @@ TEST(FontTest, TestCharacterRangeCodePath) TestSpecificUCharRange(0x1A00, 0x1CFF); static UChar c2[] = { 0x1DBF }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c2, 1)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c2, 1)); static UChar c3[] = { 0x1DC0 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c3, 1)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c3, 1)); static UChar c4[] = { 0x1DD0 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c4, 1)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c4, 1)); static UChar c5[] = { 0x1DFF }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c5, 1)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c5, 1)); static UChar c6[] = { 0x1E00 }; - EXPECT_EQ(Font::SimpleWithGlyphOverflow, Font::characterRangeCodePath(c6, 1)); + EXPECT_EQ(SimpleWithGlyphOverflowPath, Character::characterRangeCodePath(c6, 1)); static UChar c7[] = { 0x2000 }; - EXPECT_EQ(Font::SimpleWithGlyphOverflow, Font::characterRangeCodePath(c7, 1)); + EXPECT_EQ(SimpleWithGlyphOverflowPath, Character::characterRangeCodePath(c7, 1)); static UChar c8[] = { 0x2001 }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c8, 1)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c8, 1)); TestSpecificUCharRange(0x20D0, 0x20FF); TestSpecificUCharRange(0x2CEF, 0x2CF1); @@ -107,84 +108,84 @@ TEST(FontTest, TestCharacterRangeCodePathSurrogate1) /* The following 5 should all be Simple because they are not surrogate. */ static UChar c1[] = { 0xD800, 0xDBFE }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c1, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c1, 2)); static UChar c2[] = { 0xD800, 0xE000 }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c2, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c2, 2)); static UChar c3[] = { 0xDBFF, 0xDBFE }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c3, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c3, 2)); static UChar c4[] = { 0xDBFF, 0xE000 }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c4, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c4, 2)); static UChar c5[] = { 0xDC00, 0xDBFF }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c5, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c5, 2)); /* To be Complex, the Supplementary Character must be in either */ /* U+1F1E6 through U+1F1FF or U+E0100 through U+E01EF. */ /* That is, a lead of 0xD83C with trail 0xDDE6 .. 0xDDFF or */ /* a lead of 0xDB40 with trail 0xDD00 .. 0xDDEF. */ static UChar c6[] = { 0xD83C, 0xDDE5 }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c6, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c6, 2)); static UChar c7[] = { 0xD83C, 0xDDE6 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c7, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c7, 2)); static UChar c8[] = { 0xD83C, 0xDDF0 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c8, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c8, 2)); static UChar c9[] = { 0xD83C, 0xDDFF }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c9, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c9, 2)); static UChar c10[] = { 0xD83C, 0xDE00 }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c10, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c10, 2)); static UChar c11[] = { 0xDB40, 0xDCFF }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c11, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c11, 2)); static UChar c12[] = { 0xDB40, 0xDD00 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c12, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c12, 2)); static UChar c13[] = { 0xDB40, 0xDDED }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c13, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c13, 2)); static UChar c14[] = { 0xDB40, 0xDDEF }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c14, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c14, 2)); static UChar c15[] = { 0xDB40, 0xDDF0 }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c15, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c15, 2)); } TEST(FontTest, TestCharacterRangeCodePathString) { // Simple-Simple is still simple static UChar c1[] = { 0x2FF, 0x2FF }; - EXPECT_EQ(Font::Simple, Font::characterRangeCodePath(c1, 2)); + EXPECT_EQ(SimplePath, Character::characterRangeCodePath(c1, 2)); // Complex-Simple is Complex static UChar c2[] = { 0x300, 0x2FF }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c2, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c2, 2)); // Simple-Complex is Complex static UChar c3[] = { 0x2FF, 0x330 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c3, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c3, 2)); // Complex-Complex is Complex static UChar c4[] = { 0x36F, 0x330 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c4, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c4, 2)); // SimpleWithGlyphOverflow-Simple is SimpleWithGlyphOverflow static UChar c5[] = { 0x1E00, 0x2FF }; - EXPECT_EQ(Font::SimpleWithGlyphOverflow, Font::characterRangeCodePath(c5, 2)); + EXPECT_EQ(SimpleWithGlyphOverflowPath, Character::characterRangeCodePath(c5, 2)); // Simple-SimpleWithGlyphOverflow is SimpleWithGlyphOverflow static UChar c6[] = { 0x2FF, 0x2000 }; - EXPECT_EQ(Font::SimpleWithGlyphOverflow, Font::characterRangeCodePath(c6, 2)); + EXPECT_EQ(SimpleWithGlyphOverflowPath, Character::characterRangeCodePath(c6, 2)); // SimpleWithGlyphOverflow-Complex is Complex static UChar c7[] = { 0x1E00, 0x330 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c7, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c7, 2)); // Complex-SimpleWithGlyphOverflow is Complex static UChar c8[] = { 0x330, 0x2000 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c8, 2)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c8, 2)); // Surrogate-Complex is Complex static UChar c9[] = { 0xD83C, 0xDDE5, 0x330 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c9, 3)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c9, 3)); // Complex-Surrogate is Complex static UChar c10[] = { 0x330, 0xD83C, 0xDDE5 }; - EXPECT_EQ(Font::Complex, Font::characterRangeCodePath(c10, 3)); + EXPECT_EQ(ComplexPath, Character::characterRangeCodePath(c10, 3)); } static void TestSpecificUChar32RangeIdeograph(UChar32 rangeStart, UChar32 rangeEnd) { - EXPECT_FALSE(Font::isCJKIdeograph(rangeStart - 1)); - EXPECT_TRUE(Font::isCJKIdeograph(rangeStart)); - EXPECT_TRUE(Font::isCJKIdeograph((UChar32)((uint64_t)rangeStart + (uint64_t)rangeEnd) / 2)); - EXPECT_TRUE(Font::isCJKIdeograph(rangeEnd)); - EXPECT_FALSE(Font::isCJKIdeograph(rangeEnd + 1)); + EXPECT_FALSE(Character::isCJKIdeograph(rangeStart - 1)); + EXPECT_TRUE(Character::isCJKIdeograph(rangeStart)); + EXPECT_TRUE(Character::isCJKIdeograph((UChar32)((uint64_t)rangeStart + (uint64_t)rangeEnd) / 2)); + EXPECT_TRUE(Character::isCJKIdeograph(rangeEnd)); + EXPECT_FALSE(Character::isCJKIdeograph(rangeEnd + 1)); } TEST(FontTest, TestIsCJKIdeograph) @@ -210,149 +211,149 @@ TEST(FontTest, TestIsCJKIdeograph) static void TestSpecificUChar32RangeIdeographSymbol(UChar32 rangeStart, UChar32 rangeEnd) { - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(rangeStart - 1)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(rangeStart)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol((UChar32)((uint64_t)rangeStart + (uint64_t)rangeEnd) / 2)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(rangeEnd)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(rangeEnd + 1)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(rangeStart - 1)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(rangeStart)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol((UChar32)((uint64_t)rangeStart + (uint64_t)rangeEnd) / 2)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(rangeEnd)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(rangeEnd + 1)); } TEST(FontTest, TestIsCJKIdeographOrSymbol) { // CJK Compatibility Ideographs Supplement. - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2C7)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2CA)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2CB)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2D9)); - - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2020)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2021)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2030)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x203B)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x203C)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2042)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2047)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2048)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2049)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2051)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x20DD)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x20DE)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2100)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2103)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2105)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2109)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x210A)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2113)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2116)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2121)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x212B)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x213B)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2150)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2151)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2152)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2C7)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2CA)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2CB)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2D9)); + + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2020)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2021)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2030)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x203B)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x203C)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2042)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2047)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2048)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2049)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2051)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x20DD)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x20DE)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2100)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2103)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2105)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2109)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x210A)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2113)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2116)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2121)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x212B)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x213B)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2150)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2151)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2152)); TestSpecificUChar32RangeIdeographSymbol(0x2156, 0x215A); TestSpecificUChar32RangeIdeographSymbol(0x2160, 0x216B); TestSpecificUChar32RangeIdeographSymbol(0x2170, 0x217B); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x217F)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2189)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2307)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2312)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x217F)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2189)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2307)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2312)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0x23BD)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x23BE)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x23C4)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x23CC)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0x23CD)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x23CE)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2423)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0x23BD)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x23BE)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x23C4)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x23CC)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0x23CD)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x23CE)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2423)); TestSpecificUChar32RangeIdeographSymbol(0x2460, 0x2492); TestSpecificUChar32RangeIdeographSymbol(0x249C, 0x24FF); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25A0)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25A1)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25A2)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25AA)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25AB)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25B1)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25B2)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25B3)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25B6)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25B7)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25BC)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25BD)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25C0)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25C1)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25C6)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25C7)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25C9)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25CB)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25CC)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25A0)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25A1)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25A2)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25AA)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25AB)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25B1)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25B2)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25B3)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25B6)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25B7)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25BC)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25BD)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25C0)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25C1)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25C6)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25C7)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25C9)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25CB)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25CC)); TestSpecificUChar32RangeIdeographSymbol(0x25CE, 0x25D3); TestSpecificUChar32RangeIdeographSymbol(0x25E2, 0x25E6); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x25EF)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x25EF)); TestSpecificUChar32RangeIdeographSymbol(0x2600, 0x2603); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2605)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2606)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x260E)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2616)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2617)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2640)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2642)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2605)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2606)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x260E)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2616)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2617)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2640)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2642)); TestSpecificUChar32RangeIdeographSymbol(0x2660, 0x266F); TestSpecificUChar32RangeIdeographSymbol(0x2672, 0x267D); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x26A0)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x26BD)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x26BE)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2713)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x271A)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x273F)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2740)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2756)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x26A0)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x26BD)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x26BE)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2713)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x271A)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x273F)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2740)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2756)); TestSpecificUChar32RangeIdeographSymbol(0x2776, 0x277F); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x2B1A)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x2B1A)); TestSpecificUChar32RangeIdeographSymbol(0x2FF0, 0x302F); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x3031)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x312F)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0x3130)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x3031)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x312F)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0x3130)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0x318F)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x3190)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x319F)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x31BF)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0x318F)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x3190)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x319F)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x31BF)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0x31FF)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x3200)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x3300)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x33FF)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0x31FF)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x3200)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x3300)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x33FF)); TestSpecificUChar32RangeIdeographSymbol(0xF860, 0xF862); TestSpecificUChar32RangeIdeographSymbol(0xFE30, 0xFE4F); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0xFE10)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0xFE11)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0xFE12)); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0xFE19)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0xFE10)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0xFE11)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0xFE12)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0xFE19)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0xFF0D)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0xFF1B)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0xFF1C)); - EXPECT_FALSE(Font::isCJKIdeographOrSymbol(0xFF1E)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0xFF0D)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0xFF1B)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0xFF1C)); + EXPECT_FALSE(Character::isCJKIdeographOrSymbol(0xFF1E)); TestSpecificUChar32RangeIdeographSymbol(0xFF00, 0xFFEF); - EXPECT_TRUE(Font::isCJKIdeographOrSymbol(0x1F100)); + EXPECT_TRUE(Character::isCJKIdeographOrSymbol(0x1F100)); TestSpecificUChar32RangeIdeographSymbol(0x1F110, 0x1F129); TestSpecificUChar32RangeIdeographSymbol(0x1F130, 0x1F149); diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontTraits.h b/chromium/third_party/WebKit/Source/platform/fonts/FontTraits.h new file mode 100644 index 00000000000..9f2e2f13f84 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/FontTraits.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2014 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 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 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. + */ + +#ifndef FontTraits_h +#define FontTraits_h + +#include "wtf/Assertions.h" + +namespace WebCore { + +enum FontWeight { + FontWeight100, + FontWeight200, + FontWeight300, + FontWeight400, + FontWeight500, + FontWeight600, + FontWeight700, + FontWeight800, + FontWeight900, + FontWeightNormal = FontWeight400, + FontWeightBold = FontWeight700 +}; + +// Numeric values matching OS/2 & Windows Metrics usWidthClass table. +// https://www.microsoft.com/typography/otspec/os2.htm +enum FontStretch { + FontStretchUltraCondensed = 1, + FontStretchExtraCondensed = 2, + FontStretchCondensed = 3, + FontStretchSemiCondensed = 4, + FontStretchNormal = 5, + FontStretchSemiExpanded = 6, + FontStretchExpanded = 7, + FontStretchExtraExpanded = 8, + FontStretchUltraExpanded = 9 +}; + +enum FontStyle { + FontStyleNormal = 0, + FontStyleItalic = 1 +}; + +enum FontVariant { + FontVariantNormal = 0, + FontVariantSmallCaps = 1 +}; + +typedef unsigned FontTraitsMask; + +struct FontTraits { + FontTraits(FontStyle style, FontVariant variant, FontWeight weight, FontStretch stretch) + : m_style(style), m_variant(variant), m_weight(weight), m_stretch(stretch), m_filler(0) + { + ASSERT(!m_filler); + ASSERT(!(m_mask >> 10)); + } + FontTraits(FontTraitsMask mask) + : m_mask(mask) + { + ASSERT(!m_filler); + ASSERT(!(m_mask >> 10)); + } + FontStyle style() const { return static_cast<FontStyle>(m_style); } + FontVariant variant() const { return static_cast<FontVariant>(m_variant); } + FontWeight weight() const { return static_cast<FontWeight>(m_weight); } + FontStretch stretch() const { return static_cast<FontStretch>(m_stretch); } + FontTraitsMask mask() const { return m_mask; } + + union { + struct { + unsigned m_style : 1; + unsigned m_variant : 1; + unsigned m_weight : 4; + unsigned m_stretch : 4; + unsigned m_filler : 22; + }; + unsigned m_mask; + }; +}; + +} // namespace WebCore +#endif // FontTraits_h diff --git a/chromium/third_party/WebKit/Source/platform/fonts/FontTraitsMask.h b/chromium/third_party/WebKit/Source/platform/fonts/FontTraitsMask.h deleted file mode 100644 index b95d131ff5d..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/FontTraitsMask.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2008 Apple 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 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 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. - */ - -#ifndef FontTraitsMask_h -#define FontTraitsMask_h - -namespace WebCore { - -enum { - FontStyleNormalBit = 0, - FontStyleItalicBit, - FontVariantNormalBit, - FontVariantSmallCapsBit, - FontWeight100Bit, - FontWeight200Bit, - FontWeight300Bit, - FontWeight400Bit, - FontWeight500Bit, - FontWeight600Bit, - FontWeight700Bit, - FontWeight800Bit, - FontWeight900Bit, - FontTraitsMaskWidth -}; - -enum FontTraitsMask { - FontStyleNormalMask = 1 << FontStyleNormalBit, - FontStyleItalicMask = 1 << FontStyleItalicBit, - FontStyleMask = FontStyleNormalMask | FontStyleItalicMask, - - FontVariantNormalMask = 1 << FontVariantNormalBit, - FontVariantSmallCapsMask = 1 << FontVariantSmallCapsBit, - FontVariantMask = FontVariantNormalMask | FontVariantSmallCapsMask, - - FontWeight100Mask = 1 << FontWeight100Bit, - FontWeight200Mask = 1 << FontWeight200Bit, - FontWeight300Mask = 1 << FontWeight300Bit, - FontWeight400Mask = 1 << FontWeight400Bit, - FontWeight500Mask = 1 << FontWeight500Bit, - FontWeight600Mask = 1 << FontWeight600Bit, - FontWeight700Mask = 1 << FontWeight700Bit, - FontWeight800Mask = 1 << FontWeight800Bit, - FontWeight900Mask = 1 << FontWeight900Bit, - FontWeightMask = FontWeight100Mask | FontWeight200Mask | FontWeight300Mask | FontWeight400Mask | FontWeight500Mask | FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask -}; - -} // namespace WebCore -#endif // FontTraitsMask_h diff --git a/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.cpp b/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.cpp index 7f436745e7a..27916d24ed6 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.cpp @@ -44,6 +44,18 @@ GenericFontFamilySettings::GenericFontFamilySettings(const GenericFontFamilySett { } +GenericFontFamilySettings& GenericFontFamilySettings::operator=(const GenericFontFamilySettings& other) +{ + m_standardFontFamilyMap = other.m_standardFontFamilyMap; + m_serifFontFamilyMap = other.m_serifFontFamilyMap; + m_fixedFontFamilyMap = other.m_fixedFontFamilyMap; + m_sansSerifFontFamilyMap = other.m_sansSerifFontFamilyMap; + m_cursiveFontFamilyMap = other.m_cursiveFontFamilyMap; + m_fantasyFontFamilyMap = other.m_fantasyFontFamilyMap; + m_pictographFontFamilyMap = other.m_pictographFontFamilyMap; + return *this; +} + // Sets the entry in the font map for the given script. If family is the empty string, removes the entry instead. void GenericFontFamilySettings::setGenericFontFamilyMap(ScriptFontFamilyMap& fontMap, const AtomicString& family, UScriptCode script) { diff --git a/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h b/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h index ac10e1f79d2..cb019ed8e9c 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/GenericFontFamilySettings.h @@ -36,6 +36,7 @@ #include "wtf/text/AtomicString.h" #include "wtf/text/AtomicStringHash.h" +#include <unicode/uscript.h> namespace WebCore { @@ -73,9 +74,9 @@ public: // Only called by InternalSettings to clear font family maps. void reset(); -private: - GenericFontFamilySettings& operator=(const GenericFontFamilySettings&) WTF_DELETED_FUNCTION; + GenericFontFamilySettings& operator=(const GenericFontFamilySettings&); +private: // UScriptCode uses -1 and 0 for UScriptInvalidCode and UScriptCommon. // We need to use -2 and -3 for empty value and deleted value. struct UScriptCodeHashTraits : WTF::GenericHashTraits<int> { diff --git a/chromium/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h b/chromium/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h index 18bcd57ca9e..358ca5e80bc 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/GlyphBuffer.h @@ -31,37 +31,13 @@ #define GlyphBuffer_h #include "platform/fonts/Glyph.h" -#include "platform/fonts/GlyphBuffer.h" #include "platform/geometry/FloatSize.h" #include "wtf/Vector.h" -#if OS(MACOSX) -#include <ApplicationServices/ApplicationServices.h> -#endif - namespace WebCore { class SimpleFontData; -typedef Glyph GlyphBufferGlyph; - -// CG uses CGSize instead of FloatSize so that the result of advances() -// can be passed directly to CGContextShowGlyphsWithAdvances in FontMac.mm -#if OS(MACOSX) -struct GlyphBufferAdvance : CGSize { -public: - GlyphBufferAdvance(CGSize size) : CGSize(size) - { - } - - void setWidth(CGFloat width) { this->CGSize::width = width; } - CGFloat width() const { return this->CGSize::width; } - CGFloat height() const { return this->CGSize::height; } -}; -#else -typedef FloatSize GlyphBufferAdvance; -#endif - class GlyphBuffer { public: bool isEmpty() const { return m_fontData.isEmpty(); } @@ -74,10 +50,10 @@ public: m_advances.clear(); } - GlyphBufferGlyph* glyphs(unsigned from) { return m_glyphs.data() + from; } - GlyphBufferAdvance* advances(unsigned from) { return m_advances.data() + from; } - const GlyphBufferGlyph* glyphs(unsigned from) const { return m_glyphs.data() + from; } - const GlyphBufferAdvance* advances(unsigned from) const { return m_advances.data() + from; } + Glyph* glyphs(unsigned from) { return m_glyphs.data() + from; } + FloatSize* advances(unsigned from) { return m_advances.data() + from; } + const Glyph* glyphs(unsigned from) const { return m_glyphs.data() + from; } + const FloatSize* advances(unsigned from) const { return m_advances.data() + from; } const SimpleFontData* fontDataAt(unsigned index) const { return m_fontData[index]; } @@ -86,63 +62,41 @@ public: return m_glyphs[index]; } - float advanceAt(unsigned index) const + FloatSize advanceAt(unsigned index) const { - return m_advances[index].width(); + return m_advances[index]; } void add(Glyph glyph, const SimpleFontData* font, float width) { - m_fontData.append(font); - m_glyphs.append(glyph); - -#if OS(MACOSX) - CGSize advance = { width, 0 }; - m_advances.append(advance); -#else - m_advances.append(FloatSize(width, 0)); -#endif + add(glyph, font, FloatSize(width, 0)); } - void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance) + void add(Glyph glyph, const SimpleFontData* font, const FloatSize& advance) { m_fontData.append(font); m_glyphs.append(glyph); m_advances.append(advance); } - void reverse(unsigned from, unsigned length) + void reverse() { - for (unsigned i = from, end = from + length - 1; i < end; ++i, --end) - swap(i, end); + m_fontData.reverse(); + m_glyphs.reverse(); + m_advances.reverse(); } void expandLastAdvance(float width) { ASSERT(!isEmpty()); - GlyphBufferAdvance& lastAdvance = m_advances.last(); + FloatSize& lastAdvance = m_advances.last(); lastAdvance.setWidth(lastAdvance.width() + width); } private: - void swap(unsigned index1, unsigned index2) - { - const SimpleFontData* f = m_fontData[index1]; - m_fontData[index1] = m_fontData[index2]; - m_fontData[index2] = f; - - GlyphBufferGlyph g = m_glyphs[index1]; - m_glyphs[index1] = m_glyphs[index2]; - m_glyphs[index2] = g; - - GlyphBufferAdvance s = m_advances[index1]; - m_advances[index1] = m_advances[index2]; - m_advances[index2] = s; - } - Vector<const SimpleFontData*, 2048> m_fontData; - Vector<GlyphBufferGlyph, 2048> m_glyphs; - Vector<GlyphBufferAdvance, 2048> m_advances; + Vector<Glyph, 2048> m_glyphs; + Vector<FloatSize, 2048> m_advances; }; } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/GlyphPage.h b/chromium/third_party/WebKit/Source/platform/fonts/GlyphPage.h index 98812862bef..c32bf148d5a 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/GlyphPage.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/GlyphPage.h @@ -31,6 +31,7 @@ #define GlyphPage_h #include "platform/PlatformExport.h" +#include "platform/fonts/CustomFontData.h" #include "platform/fonts/Glyph.h" #include <string.h> #include "wtf/PassRefPtr.h" @@ -93,17 +94,22 @@ public: page->m_perGlyphFontData[i] = m_glyphs[i] ? m_fontDataForAllGlyphs : 0; } } + page->m_customFontToLoad = m_customFontToLoad; return page.release(); } ~GlyphPage() { } - static const size_t size = 256; // Covers Latin-1 in a single page. - static unsigned indexForCharacter(UChar32 c) { return c % GlyphPage::size; } + static const unsigned char sizeBits = 8; + static const size_t size = (1 << GlyphPage::sizeBits); // Covers Latin-1 in a single page. + static unsigned indexForCharacter(UChar32 c) { return c & 0xFF; } ALWAYS_INLINE GlyphData glyphDataForCharacter(UChar32 c) const { - return glyphDataForIndex(indexForCharacter(c)); + unsigned index = indexForCharacter(c); + if (const CustomFontData* customData = customFontToLoadAt(index)) + customData->beginLoadIfNeeded(); + return glyphDataForIndex(index); } ALWAYS_INLINE GlyphData glyphDataForIndex(unsigned index) const @@ -126,14 +132,6 @@ public: return m_glyphs[index]; } - ALWAYS_INLINE const SimpleFontData* fontDataForCharacter(UChar32 c) const - { - unsigned index = indexForCharacter(c); - if (hasPerGlyphFontData()) - return m_perGlyphFontData[index]; - return m_glyphs[index] ? m_fontDataForAllGlyphs : 0; - } - void setGlyphDataForCharacter(UChar32 c, Glyph g, const SimpleFontData* f) { setGlyphDataForIndex(indexForCharacter(c), g, f); @@ -143,6 +141,7 @@ public: { ASSERT_WITH_SECURITY_IMPLICATION(index < size); m_glyphs[index] = glyph; + setCustomFontToLoad(index, 0); // GlyphPage getters will always return a null SimpleFontData* for glyph #0 if there's no per-glyph font array. if (hasPerGlyphFontData()) { @@ -159,6 +158,23 @@ public: setGlyphDataForIndex(index, glyphData.glyph, glyphData.fontData); } + const CustomFontData* customFontToLoadAt(unsigned index) const + { + ASSERT_WITH_SECURITY_IMPLICATION(index < size); + return m_customFontToLoad ? m_customFontToLoad->at(index) : 0; + } + + void setCustomFontToLoad(unsigned index, const CustomFontData* customFontToLoad) + { + if (!m_customFontToLoad) { + if (!customFontToLoad) + return; + m_customFontToLoad = CustomDataPage::create(); + } + ASSERT_WITH_SECURITY_IMPLICATION(index < size); + m_customFontToLoad->set(index, customFontToLoad); + } + void removeFontDataFromSystemFallbackPage(const SimpleFontData* fontData) { // This method should only be called on the system fallback page, which is never single-font. @@ -173,9 +189,6 @@ public: GlyphPageTreeNode* owner() const { return m_owner; } - // Implemented by the platform. - bool fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const SimpleFontData*); - private: explicit GlyphPage(GlyphPageTreeNode* owner, const SimpleFontData* fontDataForAllGlyphs = 0) : m_fontDataForAllGlyphs(fontDataForAllGlyphs) @@ -188,8 +201,19 @@ private: bool hasPerGlyphFontData() const { return !m_fontDataForAllGlyphs; } + class CustomDataPage : public RefCounted<CustomDataPage> { + public: + static RefPtr<CustomDataPage> create() { return adoptRef(new CustomDataPage()); } + const CustomFontData* at(size_t index) const { return m_customData[index]; } + void set(size_t index, const CustomFontData* data) { m_customData[index] = data; } + private: + CustomDataPage() { memset(m_customData, 0, sizeof(m_customData)); } + const CustomFontData* m_customData[size]; + }; + const SimpleFontData* m_fontDataForAllGlyphs; GlyphPageTreeNode* m_owner; + RefPtr<CustomDataPage> m_customFontToLoad; Glyph m_glyphs[size]; // NOTE: This array has (GlyphPage::size) elements if m_fontDataForAllGlyphs is null. diff --git a/chromium/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp b/chromium/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp index a81f23bf7ab..3f0537f32b5 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNode.cpp @@ -124,7 +124,7 @@ static bool fill(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* if (fontData->isSVGFont()) return fontData->customFontData()->fillSVGGlyphPage(pageToFill, offset, length, buffer, bufferLength, fontData); #endif - bool hasGlyphs = pageToFill->fill(offset, length, buffer, bufferLength, fontData); + bool hasGlyphs = fontData->fillGlyphPage(pageToFill, offset, length, buffer, bufferLength); #if ENABLE(OPENTYPE_VERTICAL) if (hasGlyphs && fontData->verticalData()) fontData->verticalData()->substituteWithVerticalGlyphs(fontData, pageToFill, offset, length); @@ -214,52 +214,32 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu haveGlyphs = false; const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); - unsigned numRanges = segmentedFontData->numRanges(); - bool zeroFilled = false; - RefPtr<GlyphPage> scratchPage; - GlyphPage* pageToFill = m_page.get(); - for (unsigned i = 0; i < numRanges; i++) { + for (int i = segmentedFontData->numRanges() - 1; i >= 0; i--) { const FontDataRange& range = segmentedFontData->rangeAt(i); // all this casting is to ensure all the parameters to min and max have the same type, // to avoid ambiguous template parameter errors on Windows int from = max(0, static_cast<int>(range.from()) - static_cast<int>(start)); int to = 1 + min(static_cast<int>(range.to()) - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1); - if (from < static_cast<int>(GlyphPage::size) && to > 0) { - // If this is a custom font needs to be loaded, kick off - // the load here, and do not fill the page so that - // font fallback is used while loading. - RefPtr<CustomFontData> customData = range.fontData()->customFontData(); - if (customData && customData->isLoadingFallback()) { - customData->beginLoadIfNeeded(); - continue; - } - - if (haveGlyphs && !scratchPage) { - scratchPage = GlyphPage::createForMixedFontData(this); - pageToFill = scratchPage.get(); - } - - if (!zeroFilled) { - if (from > 0 || to < static_cast<int>(GlyphPage::size)) { - for (unsigned i = 0; i < GlyphPage::size; i++) - pageToFill->setGlyphDataForIndex(i, 0, 0); - } - zeroFilled = true; - } - haveGlyphs |= fill(pageToFill, from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), range.fontData().get()); - if (scratchPage) { - ASSERT_WITH_SECURITY_IMPLICATION(to <= static_cast<int>(GlyphPage::size)); - for (int j = from; j < to; j++) { - if (!m_page->glyphAt(j) && pageToFill->glyphAt(j)) - m_page->setGlyphDataForIndex(j, pageToFill->glyphDataForIndex(j)); - } + if (from >= static_cast<int>(GlyphPage::size) || to <= 0) + continue; + + // If this is a custom font needs to be loaded, do not fill + // the page so that font fallback is used while loading. + RefPtr<CustomFontData> customData = range.fontData()->customFontData(); + if (customData && customData->isLoadingFallback()) { + for (int j = from; j < to; j++) { + m_page->setCustomFontToLoad(j, customData.get()); + haveGlyphs = true; } + continue; } + + haveGlyphs |= fill(m_page.get(), from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), range.fontData().get()); } } if (!haveGlyphs) - m_page = 0; + m_page = nullptr; } else if (parentPage && parentPage->owner() != m_parent) { // The page we're overriding may not be owned by our parent node. // This happens when our parent node provides no useful overrides @@ -294,13 +274,19 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu // has added anything. bool newGlyphs = false; for (unsigned i = 0; i < GlyphPage::size; i++) { - if (parentPage->glyphAt(i)) + if (parentPage->glyphAt(i)) { m_page->setGlyphDataForIndex(i, parentPage->glyphDataForIndex(i)); - else if (fallbackPage->glyphAt(i)) { + } else if (fallbackPage->glyphAt(i)) { m_page->setGlyphDataForIndex(i, fallbackPage->glyphDataForIndex(i)); newGlyphs = true; - } else - m_page->setGlyphDataForIndex(i, 0, 0); + } + + if (parentPage->customFontToLoadAt(i)) { + m_page->setCustomFontToLoad(i, parentPage->customFontToLoadAt(i)); + } else if (fallbackPage->customFontToLoadAt(i) && !parentPage->glyphAt(i)) { + m_page->setCustomFontToLoad(i, fallbackPage->customFontToLoadAt(i)); + newGlyphs = true; + } } if (!newGlyphs) diff --git a/chromium/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNodeTest.cpp b/chromium/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNodeTest.cpp new file mode 100644 index 00000000000..51cc356c44e --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/GlyphPageTreeNodeTest.cpp @@ -0,0 +1,226 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "platform/fonts/GlyphPageTreeNode.h" + +#include "platform/fonts/SegmentedFontData.h" +#include "platform/fonts/SimpleFontData.h" +#include <gtest/gtest.h> + +namespace WebCore { + +class TestCustomFontData : public CustomFontData { +public: + static PassRefPtr<TestCustomFontData> create() { return adoptRef(new TestCustomFontData()); } +private: + TestCustomFontData() { } + virtual bool isLoadingFallback() const OVERRIDE { return true; } +}; + +class TestSimpleFontData : public SimpleFontData { +public: + static PassRefPtr<TestSimpleFontData> create(UChar32 from, UChar32 to) + { + return adoptRef(new TestSimpleFontData(nullptr, from, to)); + } + + static PassRefPtr<TestSimpleFontData> createUnloaded(UChar32 from, UChar32 to) + { + return adoptRef(new TestSimpleFontData(TestCustomFontData::create(), from, to)); + } + +private: + TestSimpleFontData(PassRefPtr<CustomFontData> customData, UChar32 from, UChar32 to) + : SimpleFontData(customData, 10, false, false) + , m_from(from) + , m_to(to) + { + } + + bool fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const OVERRIDE + { + const Glyph kGlyph = 1; + String bufferString(buffer, bufferLength); + unsigned bufferIndex = 0; + bool hasGlyphs = false; + for (unsigned i = 0; i < length; i++) { + UChar32 c = bufferString.characterStartingAt(bufferIndex); + bufferIndex += U16_LENGTH(c); + if (m_from <= c && c <= m_to) { + pageToFill->setGlyphDataForIndex(offset + i, kGlyph, this); + hasGlyphs = true; + } + } + return hasGlyphs; + } + + UChar32 m_from; + UChar32 m_to; +}; + +TEST(GlyphPageTreeNode, rootChild) +{ + const unsigned kPageNumber = 0; + size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); + { + RefPtr<TestSimpleFontData> data = TestSimpleFontData::create('a', 'z'); + GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(data.get(), kPageNumber); + EXPECT_EQ(pageCountBeforeTest + 1, GlyphPageTreeNode::treeGlyphPageCount()); + EXPECT_TRUE(node->page()->glyphAt('a')); + EXPECT_FALSE(node->page()->glyphAt('A')); + EXPECT_FALSE(node->isSystemFallback()); + EXPECT_EQ(1u, node->level()); + EXPECT_EQ(node, node->page()->owner()); + } + EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); +} + +TEST(GlyphPageTreeNode, level2) +{ + const unsigned kPageNumber = 0; + size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); + { + RefPtr<TestSimpleFontData> dataAtoC = TestSimpleFontData::create('A', 'C'); + RefPtr<TestSimpleFontData> dataCtoE = TestSimpleFontData::create('C', 'E'); + GlyphPageTreeNode* node1 = GlyphPageTreeNode::getRootChild(dataAtoC.get(), kPageNumber); + GlyphPageTreeNode* node2 = node1->getChild(dataCtoE.get(), kPageNumber); + EXPECT_EQ(pageCountBeforeTest + 3, GlyphPageTreeNode::treeGlyphPageCount()); + + EXPECT_EQ(2u, node2->level()); + EXPECT_EQ(dataAtoC, node2->page()->glyphDataForCharacter('A').fontData); + EXPECT_EQ(dataAtoC, node2->page()->glyphDataForCharacter('C').fontData); + EXPECT_EQ(dataCtoE, node2->page()->glyphDataForCharacter('E').fontData); + } + EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); +} + +TEST(GlyphPageTreeNode, segmentedData) +{ + const unsigned kPageNumber = 0; + size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); + { + RefPtr<TestSimpleFontData> dataBtoC = TestSimpleFontData::create('B', 'C'); + RefPtr<TestSimpleFontData> dataCtoE = TestSimpleFontData::create('C', 'E'); + RefPtr<SegmentedFontData> segmentedData = SegmentedFontData::create(); + segmentedData->appendRange(FontDataRange('A', 'C', dataBtoC)); + segmentedData->appendRange(FontDataRange('C', 'D', dataCtoE)); + GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(segmentedData.get(), kPageNumber); + + EXPECT_EQ(0, node->page()->glyphDataForCharacter('A').fontData); + EXPECT_EQ(dataBtoC, node->page()->glyphDataForCharacter('B').fontData); + EXPECT_EQ(dataBtoC, node->page()->glyphDataForCharacter('C').fontData); + EXPECT_EQ(dataCtoE, node->page()->glyphDataForCharacter('D').fontData); + EXPECT_EQ(0, node->page()->glyphDataForCharacter('E').fontData); + } + EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); +} + +TEST(GlyphPageTreeNode, outsideBMP) +{ + const unsigned kPageNumber = 0x1f300 / GlyphPage::size; + size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); + { + RefPtr<TestSimpleFontData> data = TestSimpleFontData::create(0x1f310, 0x1f320); + GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(data.get(), kPageNumber); + EXPECT_EQ(pageCountBeforeTest + 1, GlyphPageTreeNode::treeGlyphPageCount()); + EXPECT_FALSE(node->page()->glyphForCharacter(0x1f30f)); + EXPECT_TRUE(node->page()->glyphForCharacter(0x1f310)); + EXPECT_TRUE(node->page()->glyphForCharacter(0x1f320)); + EXPECT_FALSE(node->page()->glyphForCharacter(0x1f321)); + } + EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); +} + +TEST(GlyphPageTreeNode, customData) +{ + const unsigned kPageNumber = 0; + size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); + { + RefPtr<TestSimpleFontData> dataAtoC = TestSimpleFontData::createUnloaded('A', 'C'); + RefPtr<TestSimpleFontData> dataBtoD = TestSimpleFontData::create('B', 'D'); + RefPtr<TestSimpleFontData> dataCtoE = TestSimpleFontData::createUnloaded('C', 'E'); + RefPtr<SegmentedFontData> segmentedData = SegmentedFontData::create(); + segmentedData->appendRange(FontDataRange('A', 'C', dataAtoC)); + segmentedData->appendRange(FontDataRange('B', 'D', dataBtoD)); + segmentedData->appendRange(FontDataRange('C', 'E', dataCtoE)); + GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(segmentedData.get(), kPageNumber); + + EXPECT_EQ(0, node->page()->glyphDataForCharacter('A').fontData); + EXPECT_EQ(dataBtoD, node->page()->glyphDataForCharacter('B').fontData); + EXPECT_EQ(dataBtoD, node->page()->glyphDataForCharacter('C').fontData); + EXPECT_EQ(dataBtoD, node->page()->glyphDataForCharacter('D').fontData); + EXPECT_EQ(0, node->page()->glyphDataForCharacter('E').fontData); + + EXPECT_EQ(dataAtoC->customFontData(), node->page()->customFontToLoadAt('A')); + EXPECT_EQ(dataAtoC->customFontData(), node->page()->customFontToLoadAt('B')); + EXPECT_EQ(dataAtoC->customFontData(), node->page()->customFontToLoadAt('C')); + EXPECT_EQ(0, node->page()->customFontToLoadAt('D')); + EXPECT_EQ(dataCtoE->customFontData(), node->page()->customFontToLoadAt('E')); + } + EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); +} + +TEST(GlyphPageTreeNode, customDataWithMultiplePages) +{ + const unsigned kPageNumber = 0; + size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); + { + RefPtr<TestSimpleFontData> dataAtoC = TestSimpleFontData::createUnloaded('A', 'C'); + RefPtr<TestSimpleFontData> dataBtoD = TestSimpleFontData::create('B', 'D'); + RefPtr<TestSimpleFontData> dataCtoE = TestSimpleFontData::createUnloaded('C', 'E'); + RefPtr<SegmentedFontData> segmentedData1 = SegmentedFontData::create(); + RefPtr<SegmentedFontData> segmentedData2 = SegmentedFontData::create(); + RefPtr<SegmentedFontData> segmentedData3 = SegmentedFontData::create(); + segmentedData1->appendRange(FontDataRange('A', 'C', dataAtoC)); + segmentedData2->appendRange(FontDataRange('B', 'D', dataBtoD)); + segmentedData3->appendRange(FontDataRange('C', 'E', dataCtoE)); + GlyphPageTreeNode* node1 = GlyphPageTreeNode::getRootChild(segmentedData1.get(), kPageNumber); + GlyphPageTreeNode* node2 = node1->getChild(segmentedData2.get(), kPageNumber); + GlyphPageTreeNode* node3 = node2->getChild(segmentedData3.get(), kPageNumber); + + EXPECT_EQ(0, node3->page()->glyphDataForCharacter('A').fontData); + EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('B').fontData); + EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('C').fontData); + EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('D').fontData); + EXPECT_EQ(0, node3->page()->glyphDataForCharacter('E').fontData); + + EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('A')); + EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('B')); + EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('C')); + EXPECT_EQ(0, node3->page()->customFontToLoadAt('D')); + EXPECT_EQ(dataCtoE->customFontData(), node3->page()->customFontToLoadAt('E')); + } + EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); +} + +TEST(GlyphPageTreeNode, systemFallback) +{ + const unsigned kPageNumber = 0; + size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); + { + RefPtr<TestSimpleFontData> dataAtoC = TestSimpleFontData::createUnloaded('A', 'C'); + RefPtr<TestSimpleFontData> dataBtoD = TestSimpleFontData::create('B', 'D'); + RefPtr<SegmentedFontData> segmentedData = SegmentedFontData::create(); + segmentedData->appendRange(FontDataRange('A', 'C', dataAtoC)); + GlyphPageTreeNode* node1 = GlyphPageTreeNode::getRootChild(segmentedData.get(), kPageNumber); + GlyphPageTreeNode* node2 = node1->getChild(dataBtoD.get(), kPageNumber); + GlyphPageTreeNode* node3 = node2->getChild(0, kPageNumber); + + EXPECT_TRUE(node3->isSystemFallback()); + + EXPECT_EQ(0, node3->page()->glyphDataForCharacter('A').fontData); + EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('B').fontData); + EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('C').fontData); + EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('D').fontData); + + EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('A')); + EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('B')); + EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('C')); + EXPECT_EQ(0, node3->page()->customFontToLoadAt('D')); + } + EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp b/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp index 451e5fe5d29..c81e5c80b9d 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.cpp @@ -57,17 +57,6 @@ bool SegmentedFontData::containsCharacter(UChar32 c) const return false; } -bool SegmentedFontData::containsCharacters(const UChar* characters, int length) const -{ - UChar32 c; - for (int i = 0; i < length; ) { - U16_NEXT(characters, i, length, c) - if (!containsCharacter(c)) - return false; - } - return true; -} - bool SegmentedFontData::isCustomFont() const { // All segmented fonts are custom fonts. @@ -84,15 +73,15 @@ bool SegmentedFontData::isLoading() const return false; } -// Returns true only if all of the sub fonts are loadingFallback. +// Returns true if any of the sub fonts are loadingFallback. bool SegmentedFontData::isLoadingFallback() const { Vector<FontDataRange>::const_iterator end = m_ranges.end(); for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) { - if (!it->fontData()->isLoadingFallback()) - return false; + if (it->fontData()->isLoadingFallback()) + return true; } - return true; + return false; } bool SegmentedFontData::isSegmented() const @@ -100,6 +89,16 @@ bool SegmentedFontData::isSegmented() const return true; } +bool SegmentedFontData::shouldSkipDrawing() const +{ + Vector<FontDataRange>::const_iterator end = m_ranges.end(); + for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) { + if (it->fontData()->shouldSkipDrawing()) + return true; + } + return false; +} + #ifndef NDEBUG String SegmentedFontData::description() const { diff --git a/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h b/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h index ffc34e067e9..db828ad2c3c 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/SegmentedFontData.h @@ -62,32 +62,27 @@ public: void appendRange(const FontDataRange& range) { m_ranges.append(range); } unsigned numRanges() const { return m_ranges.size(); } const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; } + bool containsCharacter(UChar32) const; #ifndef NDEBUG - virtual String description() const; + virtual String description() const OVERRIDE; #endif private: SegmentedFontData() { } virtual const SimpleFontData* fontDataForCharacter(UChar32) const OVERRIDE; - virtual bool containsCharacters(const UChar*, int length) const OVERRIDE; virtual bool isCustomFont() const OVERRIDE; virtual bool isLoading() const OVERRIDE; virtual bool isLoadingFallback() const OVERRIDE; virtual bool isSegmented() const OVERRIDE; - - bool containsCharacter(UChar32) const; + virtual bool shouldSkipDrawing() const OVERRIDE; Vector<FontDataRange, 1> m_ranges; }; -inline SegmentedFontData* toSegmentedFontData(FontData* fontData) -{ - ASSERT_WITH_SECURITY_IMPLICATION(!fontData || fontData->isSegmented()); - return static_cast<SegmentedFontData*>(fontData); -} +DEFINE_TYPE_CASTS(SegmentedFontData, FontData, fontData, fontData->isSegmented(), fontData.isSegmented()); } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp b/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp index b6846b2ac00..849e889a0c0 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp @@ -47,7 +47,7 @@ SimpleFontData::SimpleFontData(const FontPlatformData& platformData, PassRefPtr< , m_isTextOrientationFallback(isTextOrientationFallback) , m_isBrokenIdeographFallback(false) #if ENABLE(OPENTYPE_VERTICAL) - , m_verticalData(0) + , m_verticalData(nullptr) #endif , m_hasVerticalGlyphs(false) , m_customFontData(customData) @@ -69,7 +69,7 @@ SimpleFontData::SimpleFontData(PassRefPtr<CustomFontData> customData, float font , m_isTextOrientationFallback(false) , m_isBrokenIdeographFallback(false) #if ENABLE(OPENTYPE_VERTICAL) - , m_verticalData(0) + , m_verticalData(nullptr) #endif , m_hasVerticalGlyphs(false) , m_customFontData(customData) @@ -160,8 +160,9 @@ const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const Glyph SimpleFontData::glyphForCharacter(UChar32 character) const { - GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(this, character / GlyphPage::size); - return node->page() ? node->page()->glyphAt(character % GlyphPage::size) : 0; + // As GlyphPage::size is power of 2 so shifting is valid + GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(this, character >> GlyphPage::sizeBits); + return node->page() ? node->page()->glyphAt(character & 0xFF) : 0; } bool SimpleFontData::isSegmented() const @@ -176,7 +177,7 @@ PassRefPtr<SimpleFontData> SimpleFontData::verticalRightOrientationFontData() co if (!m_derivedFontData->verticalRightOrientation) { FontPlatformData verticalRightPlatformData(m_platformData); verticalRightPlatformData.setOrientation(Horizontal); - m_derivedFontData->verticalRightOrientation = create(verticalRightPlatformData, isCustomFont() ? CustomFontData::create(false): 0, true); + m_derivedFontData->verticalRightOrientation = create(verticalRightPlatformData, isCustomFont() ? CustomFontData::create(): nullptr, true); } return m_derivedFontData->verticalRightOrientation; } @@ -186,7 +187,7 @@ PassRefPtr<SimpleFontData> SimpleFontData::uprightOrientationFontData() const if (!m_derivedFontData) m_derivedFontData = DerivedFontData::create(isCustomFont()); if (!m_derivedFontData->uprightOrientation) - m_derivedFontData->uprightOrientation = create(m_platformData, isCustomFont() ? CustomFontData::create(false): 0, true); + m_derivedFontData->uprightOrientation = create(m_platformData, isCustomFont() ? CustomFontData::create(): nullptr, true); return m_derivedFontData->uprightOrientation; } @@ -215,7 +216,7 @@ PassRefPtr<SimpleFontData> SimpleFontData::brokenIdeographFontData() const if (!m_derivedFontData) m_derivedFontData = DerivedFontData::create(isCustomFont()); if (!m_derivedFontData->brokenIdeograph) { - m_derivedFontData->brokenIdeograph = create(m_platformData, isCustomFont() ? CustomFontData::create(false): 0); + m_derivedFontData->brokenIdeograph = create(m_platformData, isCustomFont() ? CustomFontData::create(): nullptr); m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFallback = true; } return m_derivedFontData->brokenIdeograph; @@ -259,7 +260,7 @@ PassRefPtr<SimpleFontData> SimpleFontData::createScaledFontData(const FontDescri { // FIXME: Support scaled SVG fonts. Given that SVG is scalable in general this should be achievable. if (isSVGFont()) - return 0; + return nullptr; return platformCreateScaledFontData(fontDescription, scaleFactor); } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.h b/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.h index bd2201676d5..8768872d8b9 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/SimpleFontData.h @@ -30,7 +30,6 @@ #include "platform/fonts/FontData.h" #include "platform/fonts/FontMetrics.h" #include "platform/fonts/FontPlatformData.h" -#include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/GlyphMetricsMap.h" #include "platform/fonts/GlyphPageTreeNode.h" #include "platform/fonts/TypesettingFeatures.h" @@ -57,7 +56,7 @@ enum Pitch { UnknownPitch, FixedPitch, VariablePitch }; class PLATFORM_EXPORT SimpleFontData : public FontData { public: // Used to create platform fonts. - static PassRefPtr<SimpleFontData> create(const FontPlatformData& platformData, PassRefPtr<CustomFontData> customData = 0, bool isTextOrientationFallback = false) + static PassRefPtr<SimpleFontData> create(const FontPlatformData& platformData, PassRefPtr<CustomFontData> customData = nullptr, bool isTextOrientationFallback = false) { return adoptRef(new SimpleFontData(platformData, customData, isTextOrientationFallback)); } @@ -136,7 +135,6 @@ public: void setZeroGlyph(Glyph zeroGlyph) { m_zeroGlyph = zeroGlyph; } virtual const SimpleFontData* fontDataForCharacter(UChar32) const OVERRIDE; - virtual bool containsCharacters(const UChar*, int length) const OVERRIDE; Glyph glyphForCharacter(UChar32) const; @@ -148,12 +146,13 @@ public: virtual bool isLoading() const OVERRIDE { return m_customFontData ? m_customFontData->isLoading() : false; } virtual bool isLoadingFallback() const OVERRIDE { return m_customFontData ? m_customFontData->isLoadingFallback() : false; } virtual bool isSegmented() const OVERRIDE; + virtual bool shouldSkipDrawing() const OVERRIDE { return m_customFontData && m_customFontData->shouldSkipDrawing(); } const GlyphData& missingGlyphData() const { return m_missingGlyphData; } void setMissingGlyphData(const GlyphData& glyphData) { m_missingGlyphData = glyphData; } #ifndef NDEBUG - virtual String description() const; + virtual String description() const OVERRIDE; #endif #if OS(MACOSX) @@ -165,22 +164,19 @@ public: CFDictionaryRef getCFStringAttributes(TypesettingFeatures, FontOrientation) const; #endif -#if OS(MACOSX) || USE(HARFBUZZ) bool canRenderCombiningCharacterSequence(const UChar*, size_t) const; -#endif - - bool applyTransforms(GlyphBufferGlyph*, GlyphBufferAdvance*, size_t, TypesettingFeatures) const - { - return false; - } PassRefPtr<CustomFontData> customFontData() const { return m_customFontData; } -private: + // Implemented by the platform. + virtual bool fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const; + +protected: SimpleFontData(const FontPlatformData&, PassRefPtr<CustomFontData> customData, bool isTextOrientationFallback = false); SimpleFontData(PassRefPtr<CustomFontData> customData, float fontSize, bool syntheticBold, bool syntheticItalic); +private: void platformInit(); void platformGlyphInit(); void platformCharWidthInit(); @@ -249,9 +245,7 @@ private: mutable HashMap<unsigned, RetainPtr<CFDictionaryRef> > m_CFStringAttributes; #endif -#if OS(MACOSX) || USE(HARFBUZZ) mutable OwnPtr<HashMap<String, bool> > m_combiningCharacterSequenceSupport; -#endif }; ALWAYS_INLINE FloatRect SimpleFontData::boundsForGlyph(Glyph glyph) const diff --git a/chromium/third_party/WebKit/Source/platform/fonts/WidthCache.h b/chromium/third_party/WebKit/Source/platform/fonts/WidthCache.h index 82f1b1e3d6d..7c47babf978 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/WidthCache.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/WidthCache.h @@ -26,6 +26,7 @@ #ifndef WidthCache_h #define WidthCache_h +#include "platform/geometry/IntRectExtent.h" #include "platform/text/TextRun.h" #include "wtf/Forward.h" #include "wtf/HashFunctions.h" @@ -37,6 +38,16 @@ namespace WebCore { struct GlyphOverflow; +struct WidthCacheEntry { + WidthCacheEntry() + { + width = std::numeric_limits<float>::quiet_NaN(); + } + bool isValid() const { return !std::isnan(width); } + float width; + IntRectExtent glyphBounds; +}; + class WidthCache { private: // Used to optimize small strings as hash table keys. Avoids malloc'ing an out-of-line StringImpl. @@ -119,20 +130,8 @@ public: { } - float* add(const TextRun& run, float entry, bool hasKerningOrLigatures, bool hasWordSpacingOrLetterSpacing, GlyphOverflow* glyphOverflow) + WidthCacheEntry* add(const TextRun& run, WidthCacheEntry entry) { - // The width cache is not really profitable unless we're doing expensive glyph transformations. - if (!hasKerningOrLigatures) - return 0; - // Word spacing and letter spacing can change the width of a word. - if (hasWordSpacingOrLetterSpacing) - return 0; - // Since this is just a width cache, we don't have enough information to satisfy glyph queries. - if (glyphOverflow) - return 0; - // If we allow tabs and a tab occurs inside a word, the width of the word varies based on its position on the line. - if (run.allowTabs()) - return 0; if (static_cast<unsigned>(run.length()) > SmallStringKey::capacity()) return 0; @@ -151,15 +150,15 @@ public: } private: - float* addSlowCase(const TextRun& run, float entry) + WidthCacheEntry* addSlowCase(const TextRun& run, WidthCacheEntry entry) { int length = run.length(); bool isNewEntry; - float *value; + WidthCacheEntry *value; if (length == 1) { SingleCharMap::AddResult addResult = m_singleCharMap.add(run[0], entry); isNewEntry = addResult.isNewEntry; - value = &addResult.iterator->value; + value = &addResult.storedValue->value; } else { SmallStringKey smallStringKey; if (run.is8Bit()) @@ -169,7 +168,7 @@ private: Map::AddResult addResult = m_map.add(smallStringKey, entry); isNewEntry = addResult.isNewEntry; - value = &addResult.iterator->value; + value = &addResult.storedValue->value; } // Cache hit: ramp up by sampling the next few words. @@ -192,8 +191,8 @@ private: return 0; } - typedef HashMap<SmallStringKey, float, SmallStringKeyHash, SmallStringKeyHashTraits> Map; - typedef HashMap<uint32_t, float, DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t> > SingleCharMap; + typedef HashMap<SmallStringKey, WidthCacheEntry, SmallStringKeyHash, SmallStringKeyHashTraits> Map; + typedef HashMap<uint32_t, WidthCacheEntry, DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t> > SingleCharMap; static const int s_minInterval = -3; // A cache hit pays for about 3 cache misses. static const int s_maxInterval = 20; // Sampling at this interval has almost no overhead. static const unsigned s_maxSize = 500000; // Just enough to guard against pathological growth. diff --git a/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.cpp b/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.cpp index b871cb95aa0..8816fd8158f 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.cpp @@ -22,6 +22,8 @@ #include "config.h" #include "platform/fonts/WidthIterator.h" +#include "platform/fonts/Character.h" +#include "platform/fonts/FontPlatformFeatures.h" #include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/Latin1TextIterator.h" #include "platform/fonts/SimpleFontData.h" @@ -41,7 +43,7 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const , m_runWidthSoFar(0) , m_isAfterExpansion(!run.allowsLeadingExpansion()) , m_finalRoundingWidth(0) - , m_typesettingFeatures(font->typesettingFeatures()) + , m_typesettingFeatures(font->fontDescription().typesettingFeatures()) , m_fallbackFonts(fallbackFonts) , m_accountForGlyphBounds(accountForGlyphBounds) , m_maxGlyphBoundingBoxY(numeric_limits<float>::min()) @@ -57,7 +59,7 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const m_expansionPerOpportunity = 0; else { bool isAfterExpansion = m_isAfterExpansion; - unsigned expansionOpportunityCount = m_run.is8Bit() ? Font::expansionOpportunityCount(m_run.characters8(), m_run.length(), m_run.ltr() ? LTR : RTL, isAfterExpansion) : Font::expansionOpportunityCount(m_run.characters16(), m_run.length(), m_run.ltr() ? LTR : RTL, isAfterExpansion); + unsigned expansionOpportunityCount = m_run.is8Bit() ? Character::expansionOpportunityCount(m_run.characters8(), m_run.length(), m_run.direction(), isAfterExpansion) : Character::expansionOpportunityCount(m_run.characters16(), m_run.length(), m_run.direction(), isAfterExpansion); if (isAfterExpansion && !m_run.allowsTrailingExpansion()) expansionOpportunityCount--; @@ -96,7 +98,7 @@ public: typedef Vector<pair<int, OriginalAdvancesForCharacterTreatedAsSpace>, 64> CharactersTreatedAsSpace; -static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, bool ltr, unsigned& lastGlyphCount, const SimpleFontData* fontData, TypesettingFeatures typesettingFeatures, CharactersTreatedAsSpace& charactersTreatedAsSpace) +static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, unsigned& lastGlyphCount, TypesettingFeatures typesettingFeatures, CharactersTreatedAsSpace& charactersTreatedAsSpace) { ASSERT(typesettingFeatures & (Kerning | Ligatures)); @@ -107,19 +109,11 @@ static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, bool ltr, unsi if (glyphBuffer->size() <= lastGlyphCount + 1) return 0; - GlyphBufferAdvance* advances = glyphBuffer->advances(0); + FloatSize* advances = glyphBuffer->advances(0); float widthDifference = 0; for (unsigned i = lastGlyphCount; i < glyphBufferSize; ++i) widthDifference -= advances[i].width(); - if (!ltr) - glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount); - - fontData->applyTransforms(glyphBuffer->glyphs(lastGlyphCount), advances + lastGlyphCount, glyphBufferSize - lastGlyphCount, typesettingFeatures); - - if (!ltr) - glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount); - for (size_t i = 0; i < charactersTreatedAsSpace.size(); ++i) { int spaceOffset = charactersTreatedAsSpace[i].first; const OriginalAdvancesForCharacterTreatedAsSpace& originalAdvances = charactersTreatedAsSpace[i].second; @@ -140,7 +134,7 @@ template <typename TextIterator> inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, GlyphBuffer* glyphBuffer) { bool rtl = m_run.rtl(); - bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_expansion) && !m_run.spacingDisabled(); + bool hasExtraSpacing = (m_font->fontDescription().letterSpacing() || m_font->fontDescription().wordSpacing() || m_expansion) && !m_run.spacingDisabled(); float widthSinceLastRounding = m_runWidthSoFar; m_runWidthSoFar = floorf(m_runWidthSoFar); @@ -184,15 +178,16 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph if (fontData != lastFontData && width) { if (shouldApplyFontTransforms()) - m_runWidthSoFar += applyFontTransforms(glyphBuffer, m_run.ltr(), lastGlyphCount, lastFontData, m_typesettingFeatures, charactersTreatedAsSpace); + m_runWidthSoFar += applyFontTransforms(glyphBuffer, lastGlyphCount, m_typesettingFeatures, charactersTreatedAsSpace); lastFontData = fontData; if (m_fallbackFonts && fontData != primaryFont) { // FIXME: This does a little extra work that could be avoided if // glyphDataForCharacter() returned whether it chose to use a small caps font. - if (!m_font->isSmallCaps() || character == toUpper(character)) + if (m_font->fontDescription().variant() == FontVariantNormal || character == toUpper(character)) m_fallbackFonts->add(fontData); else { + ASSERT(m_font->fontDescription().variant() == FontVariantSmallCaps); const GlyphData& uppercaseGlyphData = m_font->glyphDataForCharacter(toUpper(character), rtl); if (uppercaseGlyphData.fontData != primaryFont) m_fallbackFonts->add(uppercaseGlyphData.fontData); @@ -202,12 +197,12 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph if (hasExtraSpacing) { // Account for letter-spacing. - if (width && m_font->letterSpacing()) - width += m_font->letterSpacing(); + if (width && m_font->fontDescription().letterSpacing()) + width += m_font->fontDescription().letterSpacing(); - static bool expandAroundIdeographs = Font::canExpandAroundIdeographsInComplexText(); - bool treatAsSpace = Font::treatAsSpace(character); - if (treatAsSpace || (expandAroundIdeographs && Font::isCJKIdeographOrSymbol(character))) { + static bool expandAroundIdeographs = FontPlatformFeatures::canExpandAroundIdeographsInComplexText(); + bool treatAsSpace = Character::treatAsSpace(character); + if (treatAsSpace || (expandAroundIdeographs && Character::isCJKIdeographOrSymbol(character))) { // Distribute the run's total expansion evenly over all expansion opportunities in the run. if (m_expansion) { float previousExpansion = m_expansion; @@ -238,15 +233,18 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph // Account for word spacing. // We apply additional space between "words" by adding width to the space character. - if (treatAsSpace && (character != '\t' || !m_run.allowTabs()) && (textIterator.currentCharacter() || character == noBreakSpace) && m_font->wordSpacing()) - width += m_font->wordSpacing(); + if (treatAsSpace && (character != '\t' || !m_run.allowTabs()) && (textIterator.currentCharacter() || character == noBreakSpace) && m_font->fontDescription().wordSpacing()) + width += m_font->fontDescription().wordSpacing(); } else m_isAfterExpansion = false; } - if (shouldApplyFontTransforms() && glyphBuffer && Font::treatAsSpace(character)) + if (shouldApplyFontTransforms() && glyphBuffer && Character::treatAsSpace(character)) { charactersTreatedAsSpace.append(make_pair(glyphBuffer->size(), - OriginalAdvancesForCharacterTreatedAsSpace(character == ' ', glyphBuffer->size() ? glyphBuffer->advanceAt(glyphBuffer->size() - 1) : 0, width))); + OriginalAdvancesForCharacterTreatedAsSpace(character == ' ', + glyphBuffer->size() ? glyphBuffer->advanceAt(glyphBuffer->size() - 1).width() : 0, + width))); + } if (m_accountForGlyphBounds) { bounds = fontData->boundsForGlyph(glyph); @@ -254,7 +252,7 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph m_firstGlyphOverflow = max<float>(0, -bounds.x()); } - if (m_forTextEmphasis && !Font::canReceiveTextEmphasis(character)) + if (m_forTextEmphasis && !Character::canReceiveTextEmphasis(character)) glyph = 0; // Advance past the character we just dealt with. @@ -264,7 +262,7 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph // Force characters that are used to determine word boundaries for the rounding hack // to be integer width, so following words will start on an integer boundary. - if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(character)) { + if (m_run.applyWordRounding() && Character::isRoundingHackCharacter(character)) { width = ceilf(width); // Since widthSinceLastRounding can lose precision if we include measurements for @@ -277,7 +275,7 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph } else { // Check to see if the next character is a "rounding hack character", if so, adjust // width so that the total run width will be on an integer boundary. - if ((m_run.applyWordRounding() && textIterator.currentCharacter() < m_run.length() && Font::isRoundingHackCharacter(*(textIterator.characters()))) + if ((m_run.applyWordRounding() && textIterator.currentCharacter() < m_run.length() && Character::isRoundingHackCharacter(*(textIterator.characters()))) || (m_run.applyRunRounding() && textIterator.currentCharacter() >= m_run.length())) { float totalWidth = widthSinceLastRounding + width; widthSinceLastRounding = ceilf(totalWidth); @@ -301,7 +299,7 @@ inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph } if (shouldApplyFontTransforms()) - m_runWidthSoFar += applyFontTransforms(glyphBuffer, m_run.ltr(), lastGlyphCount, lastFontData, m_typesettingFeatures, charactersTreatedAsSpace); + m_runWidthSoFar += applyFontTransforms(glyphBuffer, lastGlyphCount, m_typesettingFeatures, charactersTreatedAsSpace); unsigned consumedCharacters = textIterator.currentCharacter() - m_currentCharacter; m_currentCharacter = textIterator.currentCharacter(); @@ -335,7 +333,7 @@ bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer& glyphBuffer) advance(m_currentCharacter + 1, &glyphBuffer); float w = 0; for (unsigned i = oldSize; i < glyphBuffer.size(); ++i) - w += glyphBuffer.advanceAt(i); + w += glyphBuffer.advanceAt(i).width(); width = w; return glyphBuffer.size() > oldSize; } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.h b/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.h index e8f94207845..bd54b164abf 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/WidthIterator.h @@ -55,15 +55,13 @@ public: float runWidthSoFar() const { return m_runWidthSoFar; } #if ENABLE(SVG_FONTS) - String lastGlyphName() const { return m_lastGlyphName; } - void setLastGlyphName(const String& name) { m_lastGlyphName = name; } Vector<SVGGlyph::ArabicForm>& arabicForms() { return m_arabicForms; } #endif static bool supportsTypesettingFeatures(const Font& font) { - return !font.typesettingFeatures(); + return !font.fontDescription().typesettingFeatures(); } const Font* m_font; @@ -78,7 +76,6 @@ public: float m_finalRoundingWidth; #if ENABLE(SVG_FONTS) - String m_lastGlyphName; Vector<SVGGlyph::ArabicForm> m_arabicForms; #endif diff --git a/chromium/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp b/chromium/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp index 58ca789213f..72c649d07ab 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp @@ -64,15 +64,16 @@ static AtomicString getFamilyNameForCharacter(UChar32 c, UScriptCode script) SkString skiaFamilyName; if (!SkGetFallbackFamilyNameForChar(c, locale, &skiaFamilyName) || skiaFamilyName.isEmpty()) - return AtomicString(); + return emptyAtom; + return skiaFamilyName.c_str(); } -PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*, bool) +PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*) { AtomicString familyName = getFamilyNameForCharacter(c, fontDescription.script()); if (familyName.isEmpty()) - return 0; + return getLastResortFallbackFont(fontDescription, DoNotRetain); return fontDataFromFontPlatformData(getFontPlatformData(fontDescription, familyName), DoNotRetain); } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroidTest.cpp b/chromium/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroidTest.cpp new file mode 100644 index 00000000000..db0f122bedd --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroidTest.cpp @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" +#include "platform/fonts/FontCache.h" + +#include "platform/fonts/SimpleFontData.h" +#include <gtest/gtest.h> + +namespace WebCore { + +TEST(FontCacheAndroid, fallbackFontForCharacter) +{ + // A Latin character in the common locale system font, but not in the + // Chinese locale-preferred font. + const UChar32 testChar = 228; + + FontDescription fontDescription; + fontDescription.setScript(USCRIPT_SIMPLIFIED_HAN); + fontDescription.setGenericFamily(FontDescription::StandardFamily); + + FontCache* fontCache = FontCache::fontCache(); + ASSERT_TRUE(fontCache); + RefPtr<SimpleFontData> fontData = fontCache->fallbackFontForCharacter(fontDescription, testChar, 0); + EXPECT_TRUE(fontData); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/cocoa/FontPlatformDataCocoa.mm b/chromium/third_party/WebKit/Source/platform/fonts/cocoa/FontPlatformDataCocoa.mm index 5d76c1a5b14..2d3a5da6a3d 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/cocoa/FontPlatformDataCocoa.mm +++ b/chromium/third_party/WebKit/Source/platform/fonts/cocoa/FontPlatformDataCocoa.mm @@ -30,6 +30,7 @@ #if OS(MACOSX) #import "platform/fonts/harfbuzz/HarfBuzzFace.h" +#include "third_party/skia/include/ports/SkTypeface_mac.h" #endif namespace WebCore { @@ -37,7 +38,7 @@ namespace WebCore { // These CoreText Text Spacing feature selectors are not defined in CoreText. enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth }; -FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool isPrinterFont, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant) +FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant) : m_syntheticBold(syntheticBold) , m_syntheticOblique(syntheticOblique) , m_orientation(orientation) @@ -46,13 +47,12 @@ FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool isPrinterFon , m_font(nsFont) , m_isColorBitmapFont(false) , m_isCompositeFontReference(false) - , m_isPrinterFont(isPrinterFont) { ASSERT_ARG(nsFont, nsFont); CGFontRef cgFont = 0; loadFont(nsFont, size, m_font, cgFont); - + #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might // have blocked font loading, in which case we'll only have the real loaded font file after the call to loadFont(). @@ -87,6 +87,7 @@ void FontPlatformData::platformDataInit(const FontPlatformData& f) #if OS(MACOSX) m_inMemoryFont = f.m_inMemoryFont; m_harfBuzzFace = f.m_harfBuzzFace; + m_typeface = f.m_typeface; #endif } @@ -104,6 +105,7 @@ const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformD #if OS(MACOSX) m_inMemoryFont = f.m_inMemoryFont; m_harfBuzzFace = f.m_harfBuzzFace; + m_typeface = f.m_typeface; #endif return *this; } @@ -128,11 +130,11 @@ void FontPlatformData::setFont(NSFont *font) CFRelease(m_font); m_font = font; m_size = [font pointSize]; - + CGFontRef cgFont = 0; NSFont* loadedFont = 0; loadFont(m_font, m_size, loadedFont, cgFont); - + #if OS(MACOSX) // If loadFont replaced m_font with a fallback font, then release the // previous font to counter the retain above. Then retain the new font. @@ -142,7 +144,7 @@ void FontPlatformData::setFont(NSFont *font) m_font = loadedFont; } #endif - + m_cgFont.adoptCF(cgFont); #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 { @@ -278,6 +280,14 @@ CTFontRef FontPlatformData::ctFont() const return m_CTFont.get(); } +SkTypeface* FontPlatformData::typeface() const{ + if (m_typeface) + return m_typeface.get(); + + m_typeface = adoptRef(SkCreateTypefaceFromCTFont(ctFont())); + return m_typeface.get(); +} + #if OS(MACOSX) static bool isAATFont(CTFontRef ctFont) { diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontHarfBuzz.cpp b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontHarfBuzz.cpp index f4ffeb69c83..d9d77dbc443 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontHarfBuzz.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontHarfBuzz.cpp @@ -32,6 +32,7 @@ #include "platform/fonts/Font.h" #include "platform/NotImplemented.h" +#include "platform/fonts/FontPlatformFeatures.h" #include "platform/fonts/SimpleFontData.h" #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" #include "platform/fonts/GlyphBuffer.h" @@ -45,52 +46,55 @@ namespace WebCore { -bool Font::canReturnFallbackFontsForComplexText() +bool FontPlatformFeatures::canReturnFallbackFontsForComplexText() { return false; } -bool Font::canExpandAroundIdeographsInComplexText() +bool FontPlatformFeatures::canExpandAroundIdeographsInComplexText() { return false; } - static void paintGlyphs(GraphicsContext* gc, const SimpleFontData* font, - const GlyphBufferGlyph* glyphs, unsigned numGlyphs, + const Glyph* glyphs, unsigned numGlyphs, SkPoint* pos, const FloatRect& textRect) { TextDrawingModeFlags textMode = gc->textDrawingMode(); // We draw text up to two times (once for fill, once for stroke). if (textMode & TextModeFill) { - SkPaint paint; - gc->setupPaintForFilling(&paint); + SkPaint paint = gc->fillPaint(); font->platformData().setupPaint(&paint, gc); gc->adjustTextRenderMode(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint); + gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); } if ((textMode & TextModeStroke) && gc->strokeStyle() != NoStroke && gc->strokeThickness() > 0) { - SkPaint paint; - gc->setupPaintForStroking(&paint); + SkPaint paint = gc->strokePaint(); font->platformData().setupPaint(&paint, gc); gc->adjustTextRenderMode(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); if (textMode & TextModeFill) { - // If we also filled, we don't want to draw shadows twice. - // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. - // Since we use the looper for shadows, we remove it (if any) now. + // 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); } - gc->drawPosText(glyphs, numGlyphs << 1, pos, textRect, paint); + gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); } } @@ -98,8 +102,6 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& point, const FloatRect& textRect) const { - SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert - SkScalar x = SkFloatToScalar(point.x()); SkScalar y = SkFloatToScalar(point.y()); @@ -123,7 +125,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, while (glyphIndex < numGlyphs) { unsigned chunkLength = std::min(kMaxBufferLength, numGlyphs - glyphIndex); - const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); + const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); translations.resize(chunkLength); verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], chunkLength, reinterpret_cast<float*>(&translations[0])); @@ -135,7 +137,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, pos[i].set( x + SkIntToScalar(lroundf(translations[i].x())), y + -SkIntToScalar(-lroundf(currentWidth - translations[i].y()))); - currentWidth += glyphBuffer.advanceAt(from + glyphIndex); + currentWidth += glyphBuffer.advanceAt(from + glyphIndex).width(); } horizontalOffset += currentWidth; paintGlyphs(gc, font, glyphs, chunkLength, pos, textRect); @@ -151,14 +153,14 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, // 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); + const FloatSize* adv = glyphBuffer.advances(from); for (unsigned i = 0; i < numGlyphs; i++) { pos[i].set(x, y); x += SkFloatToScalar(adv[i].width()); y += SkFloatToScalar(adv[i].height()); } - const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); + const Glyph* glyphs = glyphBuffer.glyphs(from); paintGlyphs(gc, font, glyphs, numGlyphs, pos, textRect); } @@ -179,22 +181,43 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRunPaintInfo& runInfo, GlyphBuffer glyphBuffer; HarfBuzzShaper shaper(this, runInfo.run); shaper.setDrawRange(runInfo.from, runInfo.to); - if (!shaper.shape(&glyphBuffer)) + if (!shaper.shape(&glyphBuffer) || glyphBuffer.isEmpty()) return; FloatPoint adjustedPoint = shaper.adjustStartPoint(point); drawGlyphBuffer(gc, runInfo, glyphBuffer, adjustedPoint); } -void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRunPaintInfo& /* runInfo */, const AtomicString& /* mark */, const FloatPoint& /* point */) const +void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const { - notImplemented(); + GlyphBuffer glyphBuffer; + + float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer, ForTextEmphasis); + + if (glyphBuffer.isEmpty()) + return; + + drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const +float Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const +{ + HarfBuzzShaper shaper(this, runInfo.run, HarfBuzzShaper::ForTextEmphasis); + shaper.setDrawRange(runInfo.from, runInfo.to); + shaper.shape(&glyphBuffer); + return 0; +} + +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, IntRectExtent* glyphBounds) const { HarfBuzzShaper shaper(this, run); if (!shaper.shape()) return 0; + + glyphBounds->setTop(floorf(-shaper.glyphBoundingBox().top())); + glyphBounds->setBottom(ceilf(shaper.glyphBoundingBox().bottom())); + glyphBounds->setLeft(std::max<int>(0, floorf(-shaper.glyphBoundingBox().left()))); + glyphBounds->setRight(std::max<int>(0, ceilf(shaper.glyphBoundingBox().right() - shaper.totalWidth()))); + return shaper.totalWidth(); } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.cpp b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.cpp index 2c8ec376e57..5320c1bc907 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.cpp @@ -31,119 +31,109 @@ #include "config.h" #include "platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h" -#include "RuntimeEnabledFeatures.h" #include "SkTypeface.h" -#include "platform/LayoutTestSupport.h" -#include "platform/NotImplemented.h" -#include "platform/fonts/FontCache.h" #include "platform/fonts/harfbuzz/HarfBuzzFace.h" - -#include "public/platform/linux/WebFontInfo.h" -#include "public/platform/linux/WebFontRenderStyle.h" -#include "public/platform/linux/WebSandboxSupport.h" -#include "public/platform/Platform.h" #include "wtf/text/WTFString.h" namespace WebCore { -static SkPaint::Hinting skiaHinting = SkPaint::kNormal_Hinting; -static bool useSkiaAutoHint = true; -static bool useSkiaBitmaps = true; -static bool useSkiaAntiAlias = true; -static bool useSkiaSubpixelRendering = false; - -void FontPlatformData::setHinting(SkPaint::Hinting hinting) -{ - skiaHinting = hinting; -} - -void FontPlatformData::setAutoHint(bool useAutoHint) -{ - useSkiaAutoHint = useAutoHint; -} - -void FontPlatformData::setUseBitmaps(bool useBitmaps) -{ - useSkiaBitmaps = useBitmaps; -} - -void FontPlatformData::setAntiAlias(bool useAntiAlias) -{ - useSkiaAntiAlias = useAntiAlias; -} - -void FontPlatformData::setSubpixelRendering(bool useSubpixelRendering) -{ - useSkiaSubpixelRendering = useSubpixelRendering; -} - FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType) : m_textSize(0) - , m_emSizeInFontUnits(0) - , m_fakeBold(false) - , m_fakeItalic(false) + , m_syntheticBold(false) + , m_syntheticItalic(false) , m_orientation(Horizontal) , m_isHashTableDeletedValue(true) +#if OS(WIN) + , m_paintTextFlags(0) + , m_minSizeForAntiAlias(0) + , m_useSubpixelPositioning(false) +#endif { } FontPlatformData::FontPlatformData() : m_textSize(0) - , m_emSizeInFontUnits(0) - , m_fakeBold(false) - , m_fakeItalic(false) + , m_syntheticBold(false) + , m_syntheticItalic(false) , m_orientation(Horizontal) , m_isHashTableDeletedValue(false) +#if OS(WIN) + , m_paintTextFlags(0) + , m_minSizeForAntiAlias(0) + , m_useSubpixelPositioning(false) +#endif { } -FontPlatformData::FontPlatformData(float textSize, bool fakeBold, bool fakeItalic) +FontPlatformData::FontPlatformData(float textSize, bool syntheticBold, bool syntheticItalic) : m_textSize(textSize) - , m_emSizeInFontUnits(0) - , m_fakeBold(fakeBold) - , m_fakeItalic(fakeItalic) + , m_syntheticBold(syntheticBold) + , m_syntheticItalic(syntheticItalic) , m_orientation(Horizontal) , m_isHashTableDeletedValue(false) +#if OS(WIN) + , m_paintTextFlags(0) + , m_minSizeForAntiAlias(0) + , m_useSubpixelPositioning(false) +#endif { } FontPlatformData::FontPlatformData(const FontPlatformData& src) : m_typeface(src.m_typeface) +#if !OS(WIN) , m_family(src.m_family) +#endif , m_textSize(src.m_textSize) - , m_emSizeInFontUnits(src.m_emSizeInFontUnits) - , m_fakeBold(src.m_fakeBold) - , m_fakeItalic(src.m_fakeItalic) + , m_syntheticBold(src.m_syntheticBold) + , m_syntheticItalic(src.m_syntheticItalic) , m_orientation(src.m_orientation) , m_style(src.m_style) - , m_harfBuzzFace(0) + , m_harfBuzzFace(nullptr) , m_isHashTableDeletedValue(false) +#if OS(WIN) + , m_paintTextFlags(src.m_paintTextFlags) + , m_minSizeForAntiAlias(src.m_minSizeForAntiAlias) + , m_useSubpixelPositioning(src.m_useSubpixelPositioning) +#endif { } -FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation, bool subpixelTextPosition) +FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family, float textSize, bool syntheticBold, bool syntheticItalic, FontOrientation orientation, bool subpixelTextPosition) : m_typeface(tf) +#if !OS(WIN) , m_family(family) +#endif , m_textSize(textSize) - , m_emSizeInFontUnits(0) - , m_fakeBold(fakeBold) - , m_fakeItalic(fakeItalic) + , m_syntheticBold(syntheticBold) + , m_syntheticItalic(syntheticItalic) , m_orientation(orientation) , m_isHashTableDeletedValue(false) +#if OS(WIN) + , m_paintTextFlags(0) + , m_minSizeForAntiAlias(0) + , m_useSubpixelPositioning(subpixelTextPosition) +#endif { querySystemForRenderStyle(subpixelTextPosition); } FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) : m_typeface(src.m_typeface) +#if !OS(WIN) , m_family(src.m_family) +#endif , m_textSize(textSize) - , m_emSizeInFontUnits(src.m_emSizeInFontUnits) - , m_fakeBold(src.m_fakeBold) - , m_fakeItalic(src.m_fakeItalic) + , m_syntheticBold(src.m_syntheticBold) + , m_syntheticItalic(src.m_syntheticItalic) , m_orientation(src.m_orientation) - , m_harfBuzzFace(0) + , m_harfBuzzFace(nullptr) , m_isHashTableDeletedValue(false) +#if OS(WIN) + , m_paintTextFlags(src.m_paintTextFlags) + , m_minSizeForAntiAlias(src.m_minSizeForAntiAlias) + , m_useSubpixelPositioning(src.m_useSubpixelPositioning) +#endif { querySystemForRenderStyle(FontDescription::subpixelPositioning()); } @@ -152,26 +142,23 @@ FontPlatformData::~FontPlatformData() { } -int FontPlatformData::emSizeInFontUnits() const -{ - if (m_emSizeInFontUnits) - return m_emSizeInFontUnits; - - m_emSizeInFontUnits = m_typeface->getUnitsPerEm(); - return m_emSizeInFontUnits; -} - FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) { m_typeface = src.m_typeface; +#if !OS(WIN) m_family = src.m_family; +#endif m_textSize = src.m_textSize; - m_fakeBold = src.m_fakeBold; - m_fakeItalic = src.m_fakeItalic; - m_harfBuzzFace = 0; + m_syntheticBold = src.m_syntheticBold; + m_syntheticItalic = src.m_syntheticItalic; + m_harfBuzzFace = nullptr; m_orientation = src.m_orientation; m_style = src.m_style; - m_emSizeInFontUnits = src.m_emSizeInFontUnits; +#if OS(WIN) + m_paintTextFlags = 0; + m_minSizeForAntiAlias = src.m_minSizeForAntiAlias; + m_useSubpixelPositioning = src.m_useSubpixelPositioning; +#endif return *this; } @@ -183,28 +170,6 @@ String FontPlatformData::description() const } #endif -void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext*) const -{ - paint->setAntiAlias(m_style.useAntiAlias); - paint->setHinting(static_cast<SkPaint::Hinting>(m_style.hintStyle)); - paint->setEmbeddedBitmapText(m_style.useBitmaps); - paint->setAutohinted(m_style.useAutoHint); - if (m_style.useAntiAlias) - paint->setLCDRenderText(m_style.useSubpixelRendering); - - // TestRunner specifically toggles the subpixel positioning flag. - if (RuntimeEnabledFeatures::subpixelFontScalingEnabled() && !isRunningLayoutTest()) - paint->setSubpixelText(true); - else - paint->setSubpixelText(m_style.useSubpixelPositioning); - - const float ts = m_textSize >= 0 ? m_textSize : 12; - paint->setTextSize(SkFloatToScalar(ts)); - paint->setTypeface(m_typeface.get()); - paint->setFakeBoldText(m_fakeBold); - paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0); -} - SkFontID FontPlatformData::uniqueID() const { return m_typeface->uniqueID(); @@ -234,8 +199,8 @@ bool FontPlatformData::operator==(const FontPlatformData& a) const return typefacesEqual && m_textSize == a.m_textSize - && m_fakeBold == a.m_fakeBold - && m_fakeItalic == a.m_fakeItalic + && m_syntheticBold == a.m_syntheticBold + && m_syntheticItalic == a.m_syntheticItalic && m_orientation == a.m_orientation && m_style == a.m_style && m_isHashTableDeletedValue == a.m_isHashTableDeletedValue; @@ -243,8 +208,7 @@ bool FontPlatformData::operator==(const FontPlatformData& a) const bool FontPlatformData::isFixedPitch() const { - notImplemented(); - return false; + return typeface() && typeface()->isFixedPitch(); } HarfBuzzFace* FontPlatformData::harfBuzzFace() const @@ -255,50 +219,4 @@ HarfBuzzFace* FontPlatformData::harfBuzzFace() const return m_harfBuzzFace.get(); } -void FontPlatformData::getRenderStyleForStrike(const char* font, int sizeAndStyle) -{ - blink::WebFontRenderStyle style; - -#if OS(ANDROID) - style.setDefaults(); -#else - if (!font || !*font) - style.setDefaults(); // It's probably a webfont. Take the system defaults. - else if (blink::Platform::current()->sandboxSupport()) - blink::Platform::current()->sandboxSupport()->getRenderStyleForStrike(font, sizeAndStyle, &style); - else - blink::WebFontInfo::renderStyleForStrike(font, sizeAndStyle, &style); -#endif - - style.toFontRenderStyle(&m_style); -} - -void FontPlatformData::querySystemForRenderStyle(bool useSkiaSubpixelPositioning) -{ - getRenderStyleForStrike(m_family.data(), (((int)m_textSize) << 2) | (m_typeface->style() & 3)); - - // Fix FontRenderStyle::NoPreference to actual styles. - if (m_style.useAntiAlias == FontRenderStyle::NoPreference) - m_style.useAntiAlias = useSkiaAntiAlias; - - if (!m_style.useHinting) - m_style.hintStyle = SkPaint::kNo_Hinting; - else if (m_style.useHinting == FontRenderStyle::NoPreference) - m_style.hintStyle = skiaHinting; - - if (m_style.useBitmaps == FontRenderStyle::NoPreference) - m_style.useBitmaps = useSkiaBitmaps; - if (m_style.useAutoHint == FontRenderStyle::NoPreference) - m_style.useAutoHint = useSkiaAutoHint; - if (m_style.useAntiAlias == FontRenderStyle::NoPreference) - m_style.useAntiAlias = useSkiaAntiAlias; - if (m_style.useSubpixelRendering == FontRenderStyle::NoPreference) - m_style.useSubpixelRendering = useSkiaSubpixelRendering; - - // TestRunner specifically toggles the subpixel positioning flag. - if (m_style.useSubpixelPositioning == FontRenderStyle::NoPreference - || isRunningLayoutTest()) - m_style.useSubpixelPositioning = useSkiaSubpixelPositioning; -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h index 0ae633b9a82..2d875a8f789 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h @@ -51,11 +51,6 @@ namespace WebCore { class GraphicsContext; class HarfBuzzFace; -// ----------------------------------------------------------------------------- -// 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 PLATFORM_EXPORT FontPlatformData { public: // Used for deleted values in the font cache's hash tables. The hash table @@ -65,43 +60,37 @@ public: // set everything to 0. FontPlatformData(WTF::HashTableDeletedValueType); FontPlatformData(); - FontPlatformData(float textSize, bool fakeBold, bool fakeItalic); + FontPlatformData(float textSize, bool syntheticBold, bool syntheticItalic); FontPlatformData(const FontPlatformData&); - FontPlatformData(PassRefPtr<SkTypeface>, const char* name, float textSize, bool fakeBold, bool fakeItalic, FontOrientation = Horizontal, bool subpixelTextPosition = FontDescription::subpixelPositioning()); + FontPlatformData(PassRefPtr<SkTypeface>, const char* name, float textSize, bool syntheticBold, bool syntheticItalic, FontOrientation = Horizontal, bool subpixelTextPosition = defaultUseSubpixelPositioning()); FontPlatformData(const FontPlatformData& src, float textSize); ~FontPlatformData(); String fontFamilyName() const; - - // ------------------------------------------------------------------------- - // Return true iff this font is monospaced (i.e. every glyph has an equal x - // advance) - // ------------------------------------------------------------------------- + float size() const { return m_textSize; } bool isFixedPitch() const; - // ------------------------------------------------------------------------- - // Setup a Skia painting context to use this font. - // ------------------------------------------------------------------------- - void setupPaint(SkPaint*, GraphicsContext* = 0) const; - - // ------------------------------------------------------------------------- - // Return Skia's unique id for this font. This encodes both the style and - // the font's file name so refers to a single face. - // ------------------------------------------------------------------------- - SkFontID uniqueID() const; SkTypeface* typeface() const { return m_typeface.get(); } - + HarfBuzzFace* harfBuzzFace() const; + SkFontID uniqueID() const; unsigned hash() const; - float size() const { return m_textSize; } - int emSizeInFontUnits() const; FontOrientation orientation() const { return m_orientation; } void setOrientation(FontOrientation orientation) { m_orientation = orientation; } - void setFakeBold(bool fakeBold) { m_fakeBold = fakeBold; } - void setFakeItalic(bool fakeItalic) { m_fakeItalic = fakeItalic; } + void setSyntheticBold(bool syntheticBold) { m_syntheticBold = syntheticBold; } + void setSyntheticItalic(bool syntheticItalic) { m_syntheticItalic = syntheticItalic; } bool operator==(const FontPlatformData&) const; FontPlatformData& operator=(const FontPlatformData&); bool isHashTableDeletedValue() const { return m_isHashTableDeletedValue; } +#if OS(WIN) + void setMinSizeForAntiAlias(unsigned size) { m_minSizeForAntiAlias = size; } + unsigned minSizeForAntiAlias() const { return m_minSizeForAntiAlias; } + void setHinting(SkPaint::Hinting style) + { + m_style.useAutoHint = 0; + m_style.hintStyle = style; + } +#endif #if ENABLE(OPENTYPE_VERTICAL) PassRefPtr<OpenTypeVerticalData> verticalData() const; @@ -112,34 +101,40 @@ public: String description() const; #endif - HarfBuzzFace* harfBuzzFace() const; - // The returned styles are all actual styles without FontRenderStyle::NoPreference. const FontRenderStyle& fontRenderStyle() const { return m_style; } + void setupPaint(SkPaint*, GraphicsContext* = 0) const; - // ------------------------------------------------------------------------- - // Global font preferences... - +#if OS(WIN) + int paintTextFlags() const { return m_paintTextFlags; } +#else static void setHinting(SkPaint::Hinting); static void setAutoHint(bool); static void setUseBitmaps(bool); static void setAntiAlias(bool); static void setSubpixelRendering(bool); +#endif private: - void getRenderStyleForStrike(const char*, int); + bool static defaultUseSubpixelPositioning(); void querySystemForRenderStyle(bool useSkiaSubpixelPositioning); RefPtr<SkTypeface> m_typeface; +#if !OS(WIN) CString m_family; +#endif float m_textSize; - mutable int m_emSizeInFontUnits; - bool m_fakeBold; - bool m_fakeItalic; + bool m_syntheticBold; + bool m_syntheticItalic; FontOrientation m_orientation; FontRenderStyle m_style; mutable RefPtr<HarfBuzzFace> m_harfBuzzFace; bool m_isHashTableDeletedValue; +#if OS(WIN) + int m_paintTextFlags; + bool m_useSubpixelPositioning; + unsigned m_minSizeForAntiAlias; +#endif }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFace.cpp b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFace.cpp index b35f636353a..306ea2c5056 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFace.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFace.cpp @@ -82,12 +82,12 @@ HarfBuzzFace::HarfBuzzFace(FontPlatformData* platformData, uint64_t uniqueID) , m_uniqueID(uniqueID) , m_scriptForVerticalText(HB_SCRIPT_INVALID) { - HarfBuzzFaceCache::AddResult result = harfBuzzFaceCache()->add(m_uniqueID, 0); + HarfBuzzFaceCache::AddResult result = harfBuzzFaceCache()->add(m_uniqueID, nullptr); if (result.isNewEntry) - result.iterator->value = FaceCacheEntry::create(createFace()); - result.iterator->value->ref(); - m_face = result.iterator->value->face(); - m_glyphCacheForFaceCacheEntry = result.iterator->value->glyphCache(); + result.storedValue->value = FaceCacheEntry::create(createFace()); + result.storedValue->value->ref(); + m_face = result.storedValue->value->face(); + m_glyphCacheForFaceCacheEntry = result.storedValue->value->glyphCache(); } HarfBuzzFace::~HarfBuzzFace() diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceCoreText.cpp b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceCoreText.cpp index 96b0285d4ec..afa73103f9f 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceCoreText.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceCoreText.cpp @@ -141,9 +141,4 @@ hb_font_t* HarfBuzzFace::createFont() return font; } -GlyphBufferAdvance HarfBuzzShaper::createGlyphBufferAdvance(float width, float height) -{ - return CGSizeMake(width, height); -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceSkia.cpp b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceSkia.cpp index b0daf5323db..20a22e77a80 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzFaceSkia.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2012 Google Inc. All rights reserved. + * Copyright (c) 2014 BlackBerry Limited. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -39,7 +40,6 @@ #include "SkUtils.h" #include "platform/fonts/FontPlatformData.h" #include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" #include "hb.h" @@ -94,10 +94,10 @@ static hb_bool_t harfBuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoin paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); uint16_t glyph16; paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &glyph16); - result.iterator->value = glyph16; + result.storedValue->value = glyph16; *glyph = glyph16; } - *glyph = result.iterator->value; + *glyph = result.storedValue->value; return !!*glyph; } @@ -117,6 +117,50 @@ static hb_bool_t harfBuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontD return true; } +static hb_position_t harfBuzzGetGlyphHorizontalKerning(hb_font_t*, void* fontData, hb_codepoint_t leftGlyph, hb_codepoint_t rightGlyph, void*) +{ + HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); + if (hbFontData->m_paint.isVerticalText()) { + // We don't support cross-stream kerning + return 0; + } + + SkTypeface* typeface = hbFontData->m_paint.getTypeface(); + + const uint16_t glyphs[2] = { static_cast<uint16_t>(leftGlyph), static_cast<uint16_t>(rightGlyph) }; + int32_t kerningAdjustments[1] = { 0 }; + + if (typeface->getKerningPairAdjustments(glyphs, 2, kerningAdjustments)) { + SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm()); + SkScalar size = hbFontData->m_paint.getTextSize(); + return SkiaScalarToHarfBuzzPosition(SkScalarMulDiv(SkIntToScalar(kerningAdjustments[0]), size, upm)); + } + + return 0; +} + +static hb_position_t harfBuzzGetGlyphVerticalKerning(hb_font_t*, void* fontData, hb_codepoint_t topGlyph, hb_codepoint_t bottomGlyph, void*) +{ + HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); + if (!hbFontData->m_paint.isVerticalText()) { + // We don't support cross-stream kerning + return 0; + } + + SkTypeface* typeface = hbFontData->m_paint.getTypeface(); + + const uint16_t glyphs[2] = { static_cast<uint16_t>(topGlyph), static_cast<uint16_t>(bottomGlyph) }; + int32_t kerningAdjustments[1] = { 0 }; + + if (typeface->getKerningPairAdjustments(glyphs, 2, kerningAdjustments)) { + SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm()); + SkScalar size = hbFontData->m_paint.getTextSize(); + return SkiaScalarToHarfBuzzPosition(SkScalarMulDiv(SkIntToScalar(kerningAdjustments[0]), size, upm)); + } + + return 0; +} + static hb_bool_t harfBuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData) { HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); @@ -135,7 +179,9 @@ static hb_font_funcs_t* harfBuzzSkiaGetFontFuncs() harfBuzzSkiaFontFuncs = hb_font_funcs_create(); hb_font_funcs_set_glyph_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyph, 0, 0); hb_font_funcs_set_glyph_h_advance_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyphHorizontalAdvance, 0, 0); + hb_font_funcs_set_glyph_h_kerning_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyphHorizontalKerning, 0, 0); hb_font_funcs_set_glyph_h_origin_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyphHorizontalOrigin, 0, 0); + hb_font_funcs_set_glyph_v_kerning_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyphVerticalKerning, 0, 0); hb_font_funcs_set_glyph_extents_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyphExtents, 0, 0); hb_font_funcs_make_immutable(harfBuzzSkiaFontFuncs); } @@ -188,9 +234,4 @@ hb_font_t* HarfBuzzFace::createFont() return font; } -GlyphBufferAdvance HarfBuzzShaper::createGlyphBufferAdvance(float width, float height) -{ - return GlyphBufferAdvance(width, height); -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.cpp b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.cpp index 77f482cce26..d27c200f3d9 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.cpp @@ -32,15 +32,21 @@ #include "config.h" #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" -#include "RuntimeEnabledFeatures.h" -#include "hb-icu.h" +#include "hb.h" +#include "platform/LayoutUnit.h" +#include "platform/RuntimeEnabledFeatures.h" +#include "platform/fonts/Character.h" #include "platform/fonts/Font.h" +#include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/harfbuzz/HarfBuzzFace.h" #include "platform/text/SurrogatePairAwareTextIterator.h" +#include "platform/text/TextBreakIterator.h" +#include "wtf/Compiler.h" #include "wtf/MathExtras.h" #include "wtf/unicode/Unicode.h" #include <unicode/normlzr.h> #include <unicode/uchar.h> +#include <unicode/uscript.h> #include <list> #include <map> @@ -81,12 +87,13 @@ typedef std::map<std::wstring, CachedShapingResults*> CachedShapingResultsMap; typedef std::list<CachedShapingResultsLRUNode*> CachedShapingResultsLRU; struct CachedShapingResults { - CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* runFont, hb_direction_t runDir); + CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* runFont, hb_direction_t runDir, const String& newLocale); ~CachedShapingResults(); hb_buffer_t* buffer; Font font; hb_direction_t dir; + String locale; CachedShapingResultsLRU::iterator lru; }; @@ -97,10 +104,11 @@ struct CachedShapingResultsLRUNode { CachedShapingResultsMap::iterator entry; }; -CachedShapingResults::CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* fontData, hb_direction_t dirData) +CachedShapingResults::CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* fontData, hb_direction_t dirData, const String& newLocale) : buffer(harfBuzzBuffer) , font(*fontData) , dir(dirData) + , locale(newLocale) { } @@ -207,6 +215,26 @@ static inline float harfBuzzPositionToFloat(hb_position_t value) return static_cast<float>(value) / (1 << 16); } +static inline unsigned countGraphemesInCluster(const UChar* normalizedBuffer, unsigned normalizedBufferLength, uint16_t startIndex, uint16_t endIndex) +{ + if (startIndex > endIndex) { + uint16_t tempIndex = startIndex; + startIndex = endIndex; + endIndex = tempIndex; + } + uint16_t length = endIndex - startIndex; + ASSERT(static_cast<unsigned>(startIndex + length) <= normalizedBufferLength); + TextBreakIterator* cursorPosIterator = cursorMovementIterator(&normalizedBuffer[startIndex], length); + + int cursorPos = cursorPosIterator->current(); + int numGraphemes = -1; + while (0 <= cursorPos) { + cursorPos = cursorPosIterator->next(); + numGraphemes++; + } + return numGraphemes < 0 ? 0 : numGraphemes; +} + inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_t script) : m_fontData(fontData) , m_startIndex(startIndex) @@ -289,7 +317,6 @@ int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX) if (currentX <= targetX && targetX <= nextX) return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphIndex]; currentX = nextX; - prevAdvance = currentAdvance; ++glyphIndex; } @@ -339,26 +366,28 @@ static void normalizeCharacters(const TextRun& run, unsigned length, UChar* dest UChar32 character; U16_NEXT(source, position, length, character); // Don't normalize tabs as they are not treated as spaces for word-end. - if (Font::treatAsSpace(character) && character != '\t') + if (Character::treatAsSpace(character) && character != '\t') character = ' '; - else if (Font::treatAsZeroWidthSpaceInComplexScript(character)) + else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) character = zeroWidthSpace; U16_APPEND(destination, *destinationLength, length, character, error); ASSERT_UNUSED(error, !error); } } -HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run) +HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmphasisOrNot forTextEmphasis) : m_font(font) , m_normalizedBufferLength(0) , m_run(run) - , m_wordSpacingAdjustment(font->wordSpacing()) + , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) , m_padding(0) , m_padPerWordBreak(0) , m_padError(0) - , m_letterSpacing(font->letterSpacing()) + , m_letterSpacing(font->fontDescription().letterSpacing()) , m_fromIndex(0) , m_toIndex(m_run.length()) + , m_forTextEmphasis(forTextEmphasis) + , m_glyphBoundingBox(std::numeric_limits<float>::max(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::max()) { m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]); normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_normalizedBufferLength); @@ -366,81 +395,6 @@ HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run) setFontFeatures(); } -static void normalizeSpacesAndMirrorChars(const UChar* source, unsigned length, UChar* destination, unsigned* destinationLength, HarfBuzzShaper::NormalizeMode normalizeMode) -{ - unsigned position = 0; - bool error = false; - // Iterate characters in source and mirror character if needed. - *destinationLength = 0; - while (position < length) { - UChar32 character; - U16_NEXT(source, position, length, character); - // Don't normalize tabs as they are not treated as spaces for word-end - if (Font::treatAsSpace(character) && character != '\t') - character = ' '; - else if (Font::treatAsZeroWidthSpace(character)) - character = zeroWidthSpace; - else if (normalizeMode == HarfBuzzShaper::NormalizeMirrorChars) - character = u_charMirror(character); - U16_APPEND(destination, *destinationLength, length, character, error); - ASSERT_UNUSED(error, !error); - } -} - -void HarfBuzzShaper::setNormalizedBuffer(NormalizeMode normalizeMode) -{ - // Normalize the text run in three ways: - // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks - // (U+0300..) are used in the run. This conversion is necessary since most OpenType - // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in - // their GSUB tables. - // - // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since - // the API returns FALSE (= not normalized) for complex runs that don't require NFC - // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, - // HarfBuzz will do the same thing for us using the GSUB table. - // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs - // for characters like '\n' otherwise. - // 3) Convert mirrored characters such as parenthesis for rtl text. - - // Convert to NFC form if the text has diacritical marks. - icu::UnicodeString normalizedString; - UErrorCode error = U_ZERO_ERROR; - - const UChar* runCharacters; - String stringFor8BitRun; - if (m_run.is8Bit()) { - stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length()); - runCharacters = stringFor8BitRun.characters16(); - } else - runCharacters = m_run.characters16(); - - for (int i = 0; i < m_run.length(); ++i) { - UChar ch = runCharacters[i]; - if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) { - icu::Normalizer::normalize(icu::UnicodeString(runCharacters, - m_run.length()), UNORM_NFC, 0 /* no options */, - normalizedString, error); - if (U_FAILURE(error)) - normalizedString.remove(); - break; - } - } - - const UChar* sourceText; - unsigned sourceLength; - if (normalizedString.isEmpty()) { - sourceLength = m_run.length(); - sourceText = runCharacters; - } else { - sourceLength = normalizedString.length(); - sourceText = normalizedString.getBuffer(); - } - - m_normalizedBuffer = adoptArrayPtr(new UChar[sourceLength + 1]); - normalizeSpacesAndMirrorChars(sourceText, sourceLength, m_normalizedBuffer.get(), &m_normalizedBufferLength, normalizeMode); -} - bool HarfBuzzShaper::isWordEnd(unsigned index) { // This could refer a high-surrogate, but should work. @@ -520,6 +474,53 @@ void HarfBuzzShaper::setFontFeatures() break; } + static hb_feature_t noClig = { HB_TAG('c', 'l', 'i', 'g'), 0, 0, static_cast<unsigned>(-1) }; + static hb_feature_t noLiga = { HB_TAG('l', 'i', 'g', 'a'), 0, 0, static_cast<unsigned>(-1) }; + switch (description.commonLigaturesState()) { + case FontDescription::DisabledLigaturesState: + m_features.append(noLiga); + m_features.append(noClig); + break; + case FontDescription::EnabledLigaturesState: + // liga and clig are on by default + break; + case FontDescription::NormalLigaturesState: + break; + } + static hb_feature_t dlig = { HB_TAG('d', 'l', 'i', 'g'), 1, 0, static_cast<unsigned>(-1) }; + switch (description.discretionaryLigaturesState()) { + case FontDescription::DisabledLigaturesState: + // dlig is off by default + break; + case FontDescription::EnabledLigaturesState: + m_features.append(dlig); + break; + case FontDescription::NormalLigaturesState: + break; + } + static hb_feature_t hlig = { HB_TAG('h', 'l', 'i', 'g'), 1, 0, static_cast<unsigned>(-1) }; + switch (description.historicalLigaturesState()) { + case FontDescription::DisabledLigaturesState: + // hlig is off by default + break; + case FontDescription::EnabledLigaturesState: + m_features.append(hlig); + break; + case FontDescription::NormalLigaturesState: + break; + } + static hb_feature_t noCalt = { HB_TAG('c', 'a', 'l', 't'), 0, 0, static_cast<unsigned>(-1) }; + switch (description.contextualLigaturesState()) { + case FontDescription::DisabledLigaturesState: + m_features.append(noCalt); + break; + case FontDescription::EnabledLigaturesState: + // calt is on by default + break; + case FontDescription::NormalLigaturesState: + break; + } + FontFeatureSettings* settings = description.featureSettings(); if (!settings) return; @@ -538,19 +539,18 @@ void HarfBuzzShaper::setFontFeatures() bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) { - if (!collectHarfBuzzRuns()) + if (!createHarfBuzzRuns()) return false; m_totalWidth = 0; - // WebKit doesn't set direction when calulating widths. Leave the direction setting to - // HarfBuzz when we are calculating widths (except when directionalOverride() is set). - if (!shapeHarfBuzzRuns(glyphBuffer || m_run.directionalOverride())) + if (!shapeHarfBuzzRuns()) return false; if (!RuntimeEnabledFeatures::subpixelFontScalingEnabled()) m_totalWidth = roundf(m_totalWidth); - if (glyphBuffer && !fillGlyphBuffer(glyphBuffer)) + if (m_harfBuzzRuns.last()->hasGlyphToCharacterIndexes() + && glyphBuffer && !fillGlyphBuffer(glyphBuffer)) return false; return true; @@ -561,17 +561,53 @@ FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point) return point + m_startOffset; } -bool HarfBuzzShaper::collectHarfBuzzRuns() +static inline int handleMultipleUChar( + UChar32 character, + unsigned clusterLength, + const SimpleFontData* currentFontData, + const UChar* currentCharacterPosition, + const UChar* markCharactersEnd, + const UChar* normalizedBufferEnd) { - const UChar* normalizedBufferEnd = m_normalizedBuffer.get() + m_normalizedBufferLength; - SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get(), 0, m_normalizedBufferLength, m_normalizedBufferLength); + if (U_GET_GC_MASK(character) & U_GC_M_MASK) { + int markLength = clusterLength; + while (markCharactersEnd < normalizedBufferEnd) { + UChar32 nextCharacter; + int nextCharacterLength = 0; + U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter); + if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK)) + break; + markLength += nextCharacterLength; + markCharactersEnd += nextCharacterLength; + } + + if (currentFontData->canRenderCombiningCharacterSequence(currentCharacterPosition, markCharactersEnd - currentCharacterPosition)) { + return markLength; + } + } + return 0; +} + +struct CandidateRun { + UChar32 character; + unsigned start; + unsigned end; + const SimpleFontData* fontData; + UScriptCode script; +}; + +static inline bool collectCandidateRuns(const UChar* normalizedBuffer, + size_t bufferLength, const Font* font, Vector<CandidateRun>* runs) +{ + const UChar* normalizedBufferEnd = normalizedBuffer + bufferLength; + SurrogatePairAwareTextIterator iterator(normalizedBuffer, 0, bufferLength, bufferLength); UChar32 character; unsigned clusterLength = 0; unsigned startIndexOfCurrentRun = 0; if (!iterator.consume(character, clusterLength)) return false; - const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData; + const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false).fontData; UErrorCode errorCode = U_ZERO_ERROR; UScriptCode nextScript = uscript_getScript(character, &errorCode); if (U_FAILURE(errorCode)) @@ -582,49 +618,169 @@ bool HarfBuzzShaper::collectHarfBuzzRuns() const SimpleFontData* currentFontData = nextFontData; UScriptCode currentScript = nextScript; + UChar32 lastCharacter = character; for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) { - if (Font::treatAsZeroWidthSpace(character)) + if (Character::treatAsZeroWidthSpace(character)) continue; - if (U_GET_GC_MASK(character) & U_GC_M_MASK) { - int markLength = clusterLength; - const UChar* markCharactersEnd = iterator.characters() + clusterLength; - while (markCharactersEnd < normalizedBufferEnd) { - UChar32 nextCharacter; - int nextCharacterLength = 0; - U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter); - if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK)) - break; - markLength += nextCharacterLength; - markCharactersEnd += nextCharacterLength; - } - - if (currentFontData->canRenderCombiningCharacterSequence(currentCharacterPosition, markCharactersEnd - currentCharacterPosition)) { - clusterLength = markLength; - continue; - } + int length = handleMultipleUChar(character, clusterLength, currentFontData, currentCharacterPosition, iterator.characters() + clusterLength, normalizedBufferEnd); + if (length) { + clusterLength = length; + continue; } - nextFontData = m_font->glyphDataForCharacter(character, false).fontData; + nextFontData = font->glyphDataForCharacter(character, false).fontData; nextScript = uscript_getScript(character, &errorCode); if (U_FAILURE(errorCode)) return false; + if (lastCharacter == zeroWidthJoiner) + currentFontData = nextFontData; if ((nextFontData != currentFontData) || ((currentScript != nextScript) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, currentScript)))) break; - if (nextScript == USCRIPT_INHERITED) - nextScript = currentScript; currentCharacterPosition = iterator.characters(); + lastCharacter = character; } - unsigned numCharactersOfCurrentRun = iterator.currentCharacter() - startIndexOfCurrentRun; - hb_script_t script = hb_icu_script_to_script(currentScript); - m_harfBuzzRuns.append(HarfBuzzRun::create(currentFontData, startIndexOfCurrentRun, numCharactersOfCurrentRun, m_run.direction(), script)); - currentFontData = nextFontData; + + CandidateRun run = { character, startIndexOfCurrentRun, iterator.currentCharacter(), currentFontData, currentScript }; + runs->append(run); + startIndexOfCurrentRun = iterator.currentCharacter(); } while (iterator.consume(character, clusterLength)); + return true; +} + +static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length, + CandidateRun& adjacentRun) +{ + for (int i = 0; i < length; i++) { + if (scriptExtensions[i] == adjacentRun.script) + return true; + } + return false; +} + +static inline void resolveRunBasedOnScriptExtensions(Vector<CandidateRun>& runs, + CandidateRun& run, size_t i, size_t length, UScriptCode* scriptExtensions, + int extensionsLength, size_t& nextResolvedRun) +{ + // If uscript_getScriptExtensions returns 1 it only contains the script value, + // we only care about ScriptExtensions which is indicated by a value >= 2. + if (extensionsLength <= 1) + return; + + if (i > 0 && matchesAdjacentRun(scriptExtensions, extensionsLength, runs[i - 1])) { + run.script = runs[i - 1].script; + return; + } + + for (size_t j = i + 1; j < length; j++) { + if (runs[j].script != USCRIPT_COMMON + && runs[j].script != USCRIPT_INHERITED + && matchesAdjacentRun(scriptExtensions, extensionsLength, runs[j])) { + nextResolvedRun = j; + break; + } + } +} + +static inline void resolveRunBasedOnScriptValue(Vector<CandidateRun>& runs, + CandidateRun& run, size_t i, size_t length, size_t& nextResolvedRun) +{ + if (run.script != USCRIPT_COMMON) + return; + + if (i > 0 && runs[i - 1].script != USCRIPT_COMMON) { + run.script = runs[i - 1].script; + return; + } + + for (size_t j = i + 1; j < length; j++) { + if (runs[j].script != USCRIPT_COMMON + && runs[j].script != USCRIPT_INHERITED) { + nextResolvedRun = j; + break; + } + } +} + +static inline bool resolveCandidateRuns(Vector<CandidateRun>& runs) +{ + UScriptCode scriptExtensions[8]; + UErrorCode errorCode = U_ZERO_ERROR; + size_t length = runs.size(); + size_t nextResolvedRun = 0; + for (size_t i = 0; i < length; i++) { + CandidateRun& run = runs[i]; + nextResolvedRun = 0; + + if (run.script == USCRIPT_INHERITED) + run.script = i > 0 ? runs[i - 1].script : USCRIPT_COMMON; + + int extensionsLength = uscript_getScriptExtensions(run.character, + scriptExtensions, sizeof(scriptExtensions), &errorCode); + if (U_FAILURE(errorCode)) + return false; + + resolveRunBasedOnScriptExtensions(runs, run, i, length, + scriptExtensions, extensionsLength, nextResolvedRun); + resolveRunBasedOnScriptValue(runs, run, i, length, + nextResolvedRun); + for (size_t j = i; j < nextResolvedRun; j++) + runs[j].script = runs[nextResolvedRun].script; + + i = std::max(i, nextResolvedRun); + } + return true; +} + +bool HarfBuzzShaper::createHarfBuzzRuns() +{ + Vector<CandidateRun> candidateRuns; + if (!collectCandidateRuns(m_normalizedBuffer.get(), + m_normalizedBufferLength, m_font, &candidateRuns)) + return false; + + if (!resolveCandidateRuns(candidateRuns)) + return false; + + size_t length = candidateRuns.size(); + for (size_t i = 0; i < length; ) { + CandidateRun& run = candidateRuns[i]; + CandidateRun lastMatchingRun = run; + for (i++; i < length; i++) { + if (candidateRuns[i].script != run.script + || candidateRuns[i].fontData != run.fontData) + break; + lastMatchingRun = candidateRuns[i]; + } + addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script); + } return !m_harfBuzzRuns.isEmpty(); } +// A port of hb_icu_script_to_script because harfbuzz on CrOS is built +// without hb-icu. See http://crbug.com/356929 +static inline hb_script_t ICUScriptToHBScript(UScriptCode script) +{ + if (UNLIKELY(script == USCRIPT_INVALID_CODE)) + return HB_SCRIPT_INVALID; + + return hb_script_from_string(uscript_getShortName(script), -1); +} + + +void HarfBuzzShaper::addHarfBuzzRun(unsigned startCharacter, + unsigned endCharacter, const SimpleFontData* fontData, + UScriptCode script) +{ + ASSERT(endCharacter > startCharacter); + ASSERT(script != USCRIPT_INVALID_CODE); + return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, + startCharacter, endCharacter - startCharacter, + m_run.direction(), ICUScriptToHBScript(script))); +} + static const uint16_t* toUint16(const UChar* src) { // FIXME: This relies on undefined behavior however it works on the @@ -634,12 +790,14 @@ static const uint16_t* toUint16(const UChar* src) return reinterpret_cast<const uint16_t*>(src); } -bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection) +bool HarfBuzzShaper::shapeHarfBuzzRuns() { HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy); - hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_funcs()); HarfBuzzRunCache& runCache = harfBuzzRunCache(); + const FontDescription& fontDescription = m_font->fontDescription(); + const String& localeString = fontDescription.locale(); + CString locale = localeString.latin1(); for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; @@ -653,12 +811,9 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection) if (!face) return false; + hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(locale.data(), locale.length())); hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); - if (shouldSetDirection) - hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); - else - // Leaving direction to HarfBuzz to guess is *really* bad, but will do for now. - hb_buffer_guess_segment_properties(harfBuzzBuffer.get()); + hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); hb_segment_properties_t props; hb_buffer_get_segment_properties(harfBuzzBuffer.get(), &props); @@ -668,11 +823,11 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection) CachedShapingResults* cachedResults = runCache.find(key); if (cachedResults) { - if (cachedResults->dir == props.direction && cachedResults->font == *m_font) { + if (cachedResults->dir == props.direction && cachedResults->font == *m_font && cachedResults->locale == localeString) { currentRun->applyShapeResult(cachedResults->buffer); setGlyphPositionsForHarfBuzzRun(currentRun, cachedResults->buffer); - hb_buffer_reset(harfBuzzBuffer.get()); + hb_buffer_clear_contents(harfBuzzBuffer.get()); runCache.moveToBack(cachedResults); @@ -687,16 +842,15 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection) static const uint16_t preContext = ' '; hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); - if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) { + if (fontDescription.variant() == FontVariantSmallCaps && u_islower(m_normalizedBuffer[currentRun->startIndex()])) { String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()).upper(); - currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData; ASSERT(!upperText.is8Bit()); // m_normalizedBuffer is 16 bit, therefore upperText is 16 bit, even after we call makeUpper(). hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(upperText.characters16()), currentRun->numCharacters(), 0, currentRun->numCharacters()); } else { hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(m_normalizedBuffer.get() + currentRun->startIndex()), currentRun->numCharacters(), 0, currentRun->numCharacters()); } - if (m_font->fontDescription().orientation() == Vertical) + if (fontDescription.orientation() == Vertical) face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy); @@ -705,10 +859,9 @@ bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection) currentRun->applyShapeResult(harfBuzzBuffer.get()); setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get()); - runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_font, props.direction)); + runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_font, props.direction, localeString)); harfBuzzBuffer.set(hb_buffer_create()); - hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_funcs()); } return true; @@ -720,9 +873,16 @@ void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0); + if (!currentRun->hasGlyphToCharacterIndexes()) { + // FIXME: https://crbug.com/337886 + ASSERT_NOT_REACHED(); + return; + } + unsigned numGlyphs = currentRun->numGlyphs(); uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); float totalAdvance = 0; + FloatPoint glyphOrigin; // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL. for (size_t i = 0; i < numGlyphs; ++i) { @@ -738,7 +898,7 @@ void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb glyphToCharacterIndexes[i] = glyphInfos[i].cluster; - if (isClusterEnd && !Font::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex])) + if (isClusterEnd && !Character::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex])) spacing += m_letterSpacing; if (isClusterEnd && isWordEnd(currentCharacterIndex)) @@ -759,6 +919,11 @@ void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); + FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); + glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); + m_glyphBoundingBox.unite(glyphBounds); + glyphOrigin += FloatSize(advance + offsetX, offsetY); + totalAdvance += advance; } currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); @@ -772,7 +937,6 @@ void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, Ha float* advances = currentRun->advances(); unsigned numGlyphs = currentRun->numGlyphs(); uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); - for (unsigned i = 0; i < numGlyphs; ++i) { uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i]; FloatPoint& currentOffset = offsets[i]; @@ -783,12 +947,66 @@ void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, Ha if (currentCharacterIndex >= m_toIndex) m_startOffset.move(glyphAdvanceX, glyphAdvanceY); else if (currentCharacterIndex >= m_fromIndex) - glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); + glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY)); } else { if (currentCharacterIndex < m_fromIndex) m_startOffset.move(glyphAdvanceX, glyphAdvanceY); else if (currentCharacterIndex < m_toIndex) - glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); + glyphBuffer->add(glyphs[i], currentRun->fontData(), FloatSize(glyphAdvanceX, glyphAdvanceY)); + } + } +} + +void HarfBuzzShaper::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun) +{ + // FIXME: Instead of generating a synthetic GlyphBuffer here which is then used by the + // drawEmphasisMarks method of FontFastPath, we should roll our own emphasis mark drawing function. + + float* advances = currentRun->advances(); + unsigned numGlyphs = currentRun->numGlyphs(); + uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); + unsigned graphemesInCluster = 1; + float clusterAdvance = 0; + uint16_t clusterStart; + + // A "cluster" in this context means a cluster as it is used by HarfBuzz: + // The minimal group of characters and corresponding glyphs, that cannot be broken + // down further from a text shaping point of view. + // A cluster can contain multiple glyphs and grapheme clusters, with mutually + // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters, + // then linearly split the sum of corresponding glyph advances by the number of + // grapheme clusters in order to find positions for emphasis mark drawing. + + if (m_run.rtl()) + clusterStart = currentRun->startIndex() + currentRun->numCharacters(); + else + clusterStart = currentRun->startIndex() + glyphToCharacterIndexes[0]; + + for (unsigned i = 0; i < numGlyphs; ++i) { + uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i]; + bool isRunEnd = (i + 1 == numGlyphs); + bool isClusterEnd = isRunEnd || (currentRun->startIndex() + glyphToCharacterIndexes[i + 1] != currentCharacterIndex); + clusterAdvance += advances[i]; + + if (isClusterEnd) { + uint16_t clusterEnd; + if (m_run.rtl()) + clusterEnd = currentCharacterIndex; + else + clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->numCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1]; + + graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get(), m_normalizedBufferLength, clusterStart, clusterEnd); + if (!graphemesInCluster || !clusterAdvance) + continue; + + float glyphAdvanceX = clusterAdvance / graphemesInCluster; + for (unsigned j = 0; j < graphemesInCluster; ++j) { + // Do not put emphasis marks on space, separator, and control characters. + Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[currentCharacterIndex]) ? 1 : 0; + glyphBuffer->add(glyphToAdd, currentRun->fontData(), glyphAdvanceX); + } + clusterStart = clusterEnd; + clusterAdvance = 0; } } } @@ -800,15 +1018,29 @@ bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer) m_startOffset = m_harfBuzzRuns.last()->offsets()[0]; for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) { HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); + if (!currentRun->hasGlyphToCharacterIndexes()) { + // FIXME: bug 337886, 359664 + continue; + } FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0]; - fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun); + if (m_forTextEmphasis == ForTextEmphasis) + fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun); + else + fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun); } } else { m_startOffset = m_harfBuzzRuns.first()->offsets()[0]; for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) { HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); + if (!currentRun->hasGlyphToCharacterIndexes()) { + // FIXME: bug 337886, 359664 + continue; + } FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0]; - fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun); + if (m_forTextEmphasis == ForTextEmphasis) + fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun); + else + fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun); } } return glyphBuffer->size(); @@ -886,10 +1118,15 @@ FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int if (!foundToX) toX = m_run.rtl() ? 0 : m_totalWidth; - // Using floorf() and roundf() as the same as mac port. - if (fromX < toX) - return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - fromX), height); - return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), height); + if (fromX < toX) { + return Font::pixelSnappedSelectionRect( + point.x() + fromX, point.x() + toX, + point.y(), height); + } + + return Font::pixelSnappedSelectionRect( + point.x() + toX, point.x() + fromX, + point.y(), height); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.h b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.h index c60d4213bbc..fd25d1ee01a 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/harfbuzz/HarfBuzzShaper.h @@ -32,7 +32,7 @@ #define HarfBuzzShaper_h #include "hb.h" -#include "platform/fonts/GlyphBuffer.h" +#include "platform/geometry/FloatBoxExtent.h" #include "platform/geometry/FloatPoint.h" #include "platform/text/TextRun.h" #include "wtf/HashSet.h" @@ -41,19 +41,22 @@ #include "wtf/unicode/CharacterNames.h" #include "wtf/Vector.h" +#include <unicode/uscript.h> + namespace WebCore { class Font; +class GlyphBuffer; class SimpleFontData; class HarfBuzzShaper FINAL { public: - enum NormalizeMode { - DoNotNormalizeMirrorChars, - NormalizeMirrorChars + enum ForTextEmphasisOrNot { + NotForTextEmphasis, + ForTextEmphasis }; - HarfBuzzShaper(const Font*, const TextRun&); + HarfBuzzShaper(const Font*, const TextRun&, ForTextEmphasisOrNot = NotForTextEmphasis); void setDrawRange(int from, int to); bool shape(GlyphBuffer* = 0); @@ -61,6 +64,7 @@ public: float totalWidth() { return m_totalWidth; } int offsetForPosition(float targetX); FloatRect selectionRect(const FloatPoint&, int height, int from, int to); + FloatBoxExtent glyphBoundingBox() const { return m_glyphBoundingBox; } private: class HarfBuzzRun { @@ -88,7 +92,14 @@ private: uint16_t* glyphs() { return &m_glyphs[0]; } float* advances() { return &m_advances[0]; } FloatPoint* offsets() { return &m_offsets[0]; } - uint16_t* glyphToCharacterIndexes() { return &m_glyphToCharacterIndexes[0]; } + bool hasGlyphToCharacterIndexes() const + { + return m_glyphToCharacterIndexes.size() > 0; + } + uint16_t* glyphToCharacterIndexes() + { + return &m_glyphToCharacterIndexes[0]; + } float width() { return m_width; } bool rtl() { return m_direction == RTL; } hb_script_t script() { return m_script; } @@ -109,8 +120,6 @@ private: float m_width; }; - void setNormalizedBuffer(NormalizeMode = DoNotNormalizeMirrorChars); - bool isWordEnd(unsigned); int determineWordBreakSpacing(); // setPadding sets a number of pixels to be distributed across the TextRun. @@ -122,13 +131,13 @@ private: void setFontFeatures(); - bool collectHarfBuzzRuns(); - bool shapeHarfBuzzRuns(bool shouldSetDirection); + bool createHarfBuzzRuns(); + bool shapeHarfBuzzRuns(); bool fillGlyphBuffer(GlyphBuffer*); void fillGlyphBufferFromHarfBuzzRun(GlyphBuffer*, HarfBuzzRun*, FloatPoint& firstOffsetOfNextRun); + void fillGlyphBufferForTextEmphasis(GlyphBuffer*, HarfBuzzRun* currentRun); void setGlyphPositionsForHarfBuzzRun(HarfBuzzRun*, hb_buffer_t*); - - GlyphBufferAdvance createGlyphBufferAdvance(float, float); + void addHarfBuzzRun(unsigned startCharacter, unsigned endCharacter, const SimpleFontData*, UScriptCode); const Font* m_font; OwnPtr<UChar[]> m_normalizedBuffer; @@ -149,7 +158,10 @@ private: int m_fromIndex; int m_toIndex; + ForTextEmphasisOrNot m_forTextEmphasis; + float m_totalWidth; + FloatBoxExtent m_glyphBoundingBox; friend struct CachedShapingResults; }; diff --git a/chromium/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp b/chromium/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp index 69e81b68174..358a3e13f47 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp @@ -26,7 +26,7 @@ #include "platform/fonts/FontCache.h" -#include "public/platform/linux/WebFontFamily.h" +#include "public/platform/linux/WebFallbackFont.h" #include "public/platform/linux/WebFontInfo.h" #include "public/platform/linux/WebSandboxSupport.h" #include "public/platform/Platform.h" @@ -34,16 +34,19 @@ namespace WebCore { -void FontCache::getFontFamilyForCharacter(UChar32 c, const char* preferredLocale, FontCache::SimpleFontFamily* family) +void FontCache::getFontForCharacter(UChar32 c, const char* preferredLocale, FontCache::PlatformFallbackFont* fallbackFont) { - blink::WebFontFamily webFamily; - if (blink::Platform::current()->sandboxSupport()) - blink::Platform::current()->sandboxSupport()->getFontFamilyForCharacter(c, preferredLocale, &webFamily); - else - blink::WebFontInfo::familyForChar(c, preferredLocale, &webFamily); - family->name = String::fromUTF8(CString(webFamily.name)); - family->isBold = webFamily.isBold; - family->isItalic = webFamily.isItalic; + blink::WebFallbackFont webFallbackFont; + if (blink::Platform::current()->sandboxSupport()) { + blink::Platform::current()->sandboxSupport()->getFallbackFontForCharacter(c, preferredLocale, &webFallbackFont); + } else { + blink::WebFontInfo::fallbackFontForChar(c, preferredLocale, &webFallbackFont); + } + fallbackFont->name = String::fromUTF8(CString(webFallbackFont.name)); + fallbackFont->filename = webFallbackFont.filename; + fallbackFont->ttcIndex = webFallbackFont.ttcIndex; + fallbackFont->isBold = webFallbackFont.isBold; + fallbackFont->isItalic = webFallbackFont.isItalic; } } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/linux/FontPlatformDataLinuxHarfBuzz.cpp b/chromium/third_party/WebKit/Source/platform/fonts/linux/FontPlatformDataLinuxHarfBuzz.cpp new file mode 100644 index 00000000000..c05fa20be98 --- /dev/null +++ b/chromium/third_party/WebKit/Source/platform/fonts/linux/FontPlatformDataLinuxHarfBuzz.cpp @@ -0,0 +1,151 @@ +/* + * 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 "public/platform/Platform.h" + +#include "SkTypeface.h" +#include "platform/LayoutTestSupport.h" +#include "platform/RuntimeEnabledFeatures.h" +#include "platform/fonts/harfbuzz/FontPlatformDataHarfBuzz.h" +#include "public/platform/linux/WebFontInfo.h" +#include "public/platform/linux/WebFontRenderStyle.h" +#include "public/platform/linux/WebSandboxSupport.h" + +namespace WebCore { + +static SkPaint::Hinting skiaHinting = SkPaint::kNormal_Hinting; +static bool useSkiaAutoHint = true; +static bool useSkiaBitmaps = true; +static bool useSkiaAntiAlias = true; +static bool useSkiaSubpixelRendering = false; + +void FontPlatformData::setHinting(SkPaint::Hinting hinting) +{ + skiaHinting = hinting; +} + +void FontPlatformData::setAutoHint(bool useAutoHint) +{ + useSkiaAutoHint = useAutoHint; +} + +void FontPlatformData::setUseBitmaps(bool useBitmaps) +{ + useSkiaBitmaps = useBitmaps; +} + +void FontPlatformData::setAntiAlias(bool useAntiAlias) +{ + useSkiaAntiAlias = useAntiAlias; +} + +void FontPlatformData::setSubpixelRendering(bool useSubpixelRendering) +{ + useSkiaSubpixelRendering = useSubpixelRendering; +} + +void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext*) const +{ + paint->setAntiAlias(m_style.useAntiAlias); + paint->setHinting(static_cast<SkPaint::Hinting>(m_style.hintStyle)); + paint->setEmbeddedBitmapText(m_style.useBitmaps); + paint->setAutohinted(m_style.useAutoHint); + if (m_style.useAntiAlias) + paint->setLCDRenderText(m_style.useSubpixelRendering); + + // TestRunner specifically toggles the subpixel positioning flag. + if (RuntimeEnabledFeatures::subpixelFontScalingEnabled() + && paint->getHinting() != SkPaint::kFull_Hinting + && !isRunningLayoutTest()) + paint->setSubpixelText(true); + else + paint->setSubpixelText(m_style.useSubpixelPositioning); + + const float ts = m_textSize >= 0 ? m_textSize : 12; + paint->setTextSize(SkFloatToScalar(ts)); + paint->setTypeface(m_typeface.get()); + paint->setFakeBoldText(m_syntheticBold); + paint->setTextSkewX(m_syntheticItalic ? -SK_Scalar1 / 4 : 0); +} + + +static inline void getRenderStyleForStrike(FontRenderStyle& fontRenderStyle, const char* font, int sizeAndStyle) +{ + blink::WebFontRenderStyle style; + +#if OS(ANDROID) + style.setDefaults(); +#else + if (!font || !*font) + style.setDefaults(); // It's probably a webfont. Take the system defaults. + else if (blink::Platform::current()->sandboxSupport()) + blink::Platform::current()->sandboxSupport()->getRenderStyleForStrike(font, sizeAndStyle, &style); + else + blink::WebFontInfo::renderStyleForStrike(font, sizeAndStyle, &style); +#endif + + style.toFontRenderStyle(&fontRenderStyle); +} + +void FontPlatformData::querySystemForRenderStyle(bool useSkiaSubpixelPositioning) +{ + getRenderStyleForStrike(m_style, m_family.data(), (((int)m_textSize) << 2) | (m_typeface->style() & 3)); + + // Fix FontRenderStyle::NoPreference to actual styles. + if (m_style.useAntiAlias == FontRenderStyle::NoPreference) + m_style.useAntiAlias = useSkiaAntiAlias; + + if (!m_style.useHinting) + m_style.hintStyle = SkPaint::kNo_Hinting; + else if (m_style.useHinting == FontRenderStyle::NoPreference) + m_style.hintStyle = skiaHinting; + + if (m_style.useBitmaps == FontRenderStyle::NoPreference) + m_style.useBitmaps = useSkiaBitmaps; + if (m_style.useAutoHint == FontRenderStyle::NoPreference) + m_style.useAutoHint = useSkiaAutoHint; + if (m_style.useAntiAlias == FontRenderStyle::NoPreference) + m_style.useAntiAlias = useSkiaAntiAlias; + if (m_style.useSubpixelRendering == FontRenderStyle::NoPreference) + m_style.useSubpixelRendering = useSkiaSubpixelRendering; + + // TestRunner specifically toggles the subpixel positioning flag. + if (m_style.useSubpixelPositioning == FontRenderStyle::NoPreference + || isRunningLayoutTest()) + m_style.useSubpixelPositioning = useSkiaSubpixelPositioning; +} + +bool FontPlatformData::defaultUseSubpixelPositioning() +{ + return FontDescription::subpixelPositioning(); +} + +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.cpp b/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.cpp index 57855a55b5e..4ddf0e3e92e 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.cpp @@ -25,77 +25,20 @@ #include "config.h" #include "platform/fonts/mac/ComplexTextController.h" -#include <ApplicationServices/ApplicationServices.h> +#include "platform/fonts/Character.h" #include "platform/fonts/Font.h" +#include "platform/fonts/GlyphBuffer.h" #include "platform/geometry/FloatSize.h" #include "platform/text/TextBreakIterator.h" #include "platform/text/TextRun.h" #include "wtf/StdLibExtras.h" #include "wtf/unicode/CharacterNames.h" +#include <ApplicationServices/ApplicationServices.h> using namespace std; namespace WebCore { -class TextLayout { -public: - static bool isNeeded(const TextRun& run, const Font& font) - { - return font.codePath(run) == Font::Complex; - } - - TextLayout(const TextRun& run, unsigned textLength, const Font& font, float xPos) - : m_font(font) - , m_run(constructTextRun(run, textLength, font, xPos)) - , m_controller(adoptPtr(new ComplexTextController(&m_font, m_run, true))) - { - } - - float width(unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts) - { - m_controller->advance(from, 0, ByWholeGlyphs, fallbackFonts); - float beforeWidth = m_controller->runWidthSoFar(); - if (m_font.wordSpacing() && from && Font::treatAsSpace(m_run[from])) - beforeWidth += m_font.wordSpacing(); - m_controller->advance(from + len, 0, ByWholeGlyphs, fallbackFonts); - float afterWidth = m_controller->runWidthSoFar(); - return afterWidth - beforeWidth; - } - -private: - static TextRun constructTextRun(const TextRun& textRun, unsigned textLength, const Font& font, float xPos) - { - TextRun run = textRun; - run.setCharactersLength(textLength); - ASSERT(run.charactersLength() >= run.length()); - - run.setXPos(xPos); - return run; - } - - // ComplexTextController has only references to its Font and TextRun so they must be kept alive here. - Font m_font; - TextRun m_run; - OwnPtr<ComplexTextController> m_controller; -}; - -PassOwnPtr<TextLayout> Font::createLayoutForMacComplexText(const TextRun& run, unsigned textLength, float xPos, bool collapseWhiteSpace) const -{ - if (!collapseWhiteSpace || !TextLayout::isNeeded(run, *this)) - return nullptr; - return adoptPtr(new TextLayout(run, textLength, *this, xPos)); -} - -void Font::deleteLayout(TextLayout* layout) -{ - delete layout; -} - -float Font::width(TextLayout& layout, unsigned from, unsigned len, HashSet<const SimpleFontData*>* fallbackFonts) -{ - return layout.width(from, len, fallbackFonts); -} - static inline CGFloat roundCGFloat(CGFloat f) { if (sizeof(CGFloat) == sizeof(float)) @@ -141,9 +84,9 @@ ComplexTextController::ComplexTextController(const Font* font, const TextRun& ru bool isAfterExpansion = m_afterExpansion; unsigned expansionOpportunityCount; if (m_run.is8Bit()) - expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters8(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion); + expansionOpportunityCount = Character::expansionOpportunityCount(m_run.characters8(), m_end, m_run.direction(), isAfterExpansion); else - expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters16(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion); + expansionOpportunityCount = Character::expansionOpportunityCount(m_run.characters16(), m_end, m_run.direction(), isAfterExpansion); if (isAfterExpansion && !m_run.allowsTrailingExpansion()) expansionOpportunityCount--; @@ -302,7 +245,7 @@ void ComplexTextController::collectComplexTextRuns() } else cp = m_run.characters16(); - if (m_font.isSmallCaps()) + if (m_font.fontDescription().variant() == FontVariantSmallCaps) m_smallCapsBuffer.resize(m_end); unsigned indexOfFontTransition = 0; @@ -323,7 +266,7 @@ void ComplexTextController::collectComplexTextRuns() UChar uppercaseCharacter = 0; bool isSmallCaps; - bool nextIsSmallCaps = m_font.isSmallCaps() && !(U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK) && (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter; + bool nextIsSmallCaps = m_font.fontDescription().variant() == FontVariantSmallCaps && !(U_GET_GC_MASK(baseCharacter) & U_GC_M_MASK) && (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter; if (nextIsSmallCaps) { m_smallCapsBuffer[sequenceStart - cp] = uppercaseCharacter; @@ -345,7 +288,7 @@ void ComplexTextController::collectComplexTextRuns() if (!advanceByCombiningCharacterSequence(curr, end, baseCharacter, markCount)) return; - if (m_font.isSmallCaps()) { + if (m_font.fontDescription().variant()) { nextIsSmallCaps = (uppercaseCharacter = u_toupper(baseCharacter)) != baseCharacter; if (nextIsSmallCaps) { m_smallCapsBuffer[index] = uppercaseCharacter; @@ -528,7 +471,7 @@ void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer, G return; if (glyphBuffer && !m_characterInCurrentGlyph) - glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance); + glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), FloatSize(adjustedAdvance)); unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph; m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset; @@ -570,7 +513,7 @@ void ComplexTextController::adjustGlyphsAndAdvances() { CGFloat widthSinceLastCommit = 0; size_t runCount = m_complexTextRuns.size(); - bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_expansion) && !m_run.spacingDisabled(); + bool hasExtraSpacing = (m_font.fontDescription().letterSpacing() || m_font.fontDescription().wordSpacing() || m_expansion) && !m_run.spacingDisabled(); for (size_t r = 0; r < runCount; ++r) { ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; unsigned glyphCount = complexTextRun.glyphCount(); @@ -583,7 +526,7 @@ void ComplexTextController::adjustGlyphsAndAdvances() const CGSize* advances = complexTextRun.advances(); bool lastRun = r + 1 == runCount; - bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); + bool roundsAdvances = fontData->platformData().roundsGlyphAdvances(); float spaceWidth = fontData->spaceWidth() - fontData->syntheticBoldOffset(); CGFloat roundedSpaceWidth = roundCGFloat(spaceWidth); const UChar* cp = complexTextRun.characters(); @@ -610,13 +553,13 @@ void ComplexTextController::adjustGlyphsAndAdvances() else nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0)); - bool treatAsSpace = Font::treatAsSpace(ch); + bool treatAsSpace = Character::treatAsSpace(ch); CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i]; CGSize advance = treatAsSpace ? CGSizeMake(spaceWidth, advances[i].height) : advances[i]; - if (ch == '\t' && m_run.allowTabs()) + if (ch == '\t' && m_run.allowTabs()) { advance.width = m_font.tabWidth(*fontData, m_run.tabSize(), m_run.xPos() + m_totalWidth + widthSinceLastCommit); - else if (Font::treatAsZeroWidthSpace(ch) && !treatAsSpace) { + } else if (Character::treatAsZeroWidthSpace(ch) && !treatAsSpace) { advance.width = 0; glyph = fontData->spaceGlyph(); } @@ -638,11 +581,11 @@ void ComplexTextController::adjustGlyphsAndAdvances() if (hasExtraSpacing) { // If we're a glyph with an advance, go ahead and add in letter-spacing. // That way we weed out zero width lurkers. This behavior matches the fast text code path. - if (advance.width && m_font.letterSpacing()) - advance.width += m_font.letterSpacing(); + if (advance.width && m_font.fontDescription().letterSpacing()) + advance.width += m_font.fontDescription().letterSpacing(); // Handle justification and word-spacing. - if (treatAsSpace || Font::isCJKIdeographOrSymbol(ch)) { + if (treatAsSpace || Character::isCJKIdeographOrSymbol(ch)) { // Distribute the run's total expansion evenly over all expansion opportunities in the run. if (m_expansion) { float previousExpansion = m_expansion; @@ -666,8 +609,8 @@ void ComplexTextController::adjustGlyphsAndAdvances() m_afterExpansion = false; // Account for word-spacing. - if (treatAsSpace && (ch != '\t' || !m_run.allowTabs()) && (characterIndex > 0 || r > 0) && m_font.wordSpacing()) - advance.width += m_font.wordSpacing(); + if (treatAsSpace && (ch != '\t' || !m_run.allowTabs()) && (characterIndex > 0 || r > 0) && m_font.fontDescription().wordSpacing()) + advance.width += m_font.fontDescription().wordSpacing(); } else m_afterExpansion = false; } @@ -676,12 +619,12 @@ void ComplexTextController::adjustGlyphsAndAdvances() // We adjust the width of the last character of a "word" to ensure an integer width. // Force characters that are used to determine word boundaries for the rounding hack // to be integer width, so the following words will start on an integer boundary. - if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(ch)) + if (m_run.applyWordRounding() && Character::isRoundingHackCharacter(ch)) advance.width = ceilCGFloat(advance.width); // Check to see if the next character is a "rounding hack character", if so, adjust the // width so that the total run width will be on an integer boundary. - if ((m_run.applyWordRounding() && !lastGlyph && Font::isRoundingHackCharacter(nextCh)) || (m_run.applyRunRounding() && lastGlyph)) { + if ((m_run.applyWordRounding() && !lastGlyph && Character::isRoundingHackCharacter(nextCh)) || (m_run.applyRunRounding() && lastGlyph)) { CGFloat totalWidth = widthSinceLastCommit + advance.width; widthSinceLastCommit = ceilCGFloat(totalWidth); CGFloat extraWidth = widthSinceLastCommit - totalWidth; @@ -700,7 +643,7 @@ void ComplexTextController::adjustGlyphsAndAdvances() widthSinceLastCommit += advance.width; // FIXME: Combining marks should receive a text emphasis mark if they are combine with a space. - if (m_forTextEmphasis && (!Font::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK))) + if (m_forTextEmphasis && (!Character::canReceiveTextEmphasis(ch) || (U_GET_GC_MASK(ch) & U_GC_M_MASK))) glyph = 0; advance.height *= -1; diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.h b/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.h index 06bd70ab036..e1eabfae80f 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextController.h @@ -25,7 +25,6 @@ #ifndef ComplexTextController_h #define ComplexTextController_h -#include "platform/fonts/GlyphBuffer.h" #include "wtf/HashSet.h" #include "wtf/PassRefPtr.h" #include "wtf/RefCounted.h" @@ -33,6 +32,7 @@ #include "wtf/text/WTFString.h" #include "wtf/unicode/Unicode.h" #include "wtf/Vector.h" +#include <ApplicationServices/ApplicationServices.h> typedef unsigned short CGGlyph; @@ -42,6 +42,7 @@ typedef const struct __CTLine * CTLineRef; namespace WebCore { class Font; +class GlyphBuffer; class SimpleFontData; class TextRun; diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextControllerCoreText.mm b/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextControllerCoreText.mm index 822aa8cb8f0..98b062f328c 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextControllerCoreText.mm +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/ComplexTextControllerCoreText.mm @@ -202,15 +202,15 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, RetainPtr<WebCascadeList> cascadeList(AdoptNS, [[WebCascadeList alloc] initWithFont:&m_font character:baseCharacter]); - stringAttributes.adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()))); + stringAttributes.adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, fontData->getCFStringAttributes(m_font.fontDescription().typesettingFeatures(), fontData->platformData().orientation()))); static const void* attributeKeys[] = { kCTFontCascadeListAttribute }; const void* values[] = { cascadeList.get() }; RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, attributeKeys, values, sizeof(attributeKeys) / sizeof(*attributeKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); RetainPtr<CTFontDescriptorRef> fontDescriptor(AdoptCF, CTFontDescriptorCreateWithAttributes(attributes.get())); - RetainPtr<CTFontRef> fontWithCascadeList(AdoptCF, CTFontCreateCopyWithAttributes(fontData->platformData().ctFont(), m_font.pixelSize(), 0, fontDescriptor.get())); + RetainPtr<CTFontRef> fontWithCascadeList(AdoptCF, CTFontCreateCopyWithAttributes(fontData->platformData().ctFont(), m_font.fontDescription().computedPixelSize(), 0, fontDescriptor.get())); CFDictionarySetValue(const_cast<CFMutableDictionaryRef>(stringAttributes.get()), kCTFontAttributeName, fontWithCascadeList.get()); } else - stringAttributes = fontData->getCFStringAttributes(m_font.typesettingFeatures(), fontData->platformData().orientation()); + stringAttributes = fontData->getCFStringAttributes(m_font.fontDescription().typesettingFeatures(), fontData->platformData().orientation()); RetainPtr<CTLineRef> line; @@ -279,7 +279,7 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, // Core Text may have used a font that is not known to NSFontManager. In that case, fall back on // using the font as returned, even though it may not have the best NSFontRenderingMode. if (!runFontData) { - FontPlatformData runFontPlatformData((NSFont *)runFont, CTFontGetSize(runFont), m_font.fontDescription().usePrinterFont()); + FontPlatformData runFontPlatformData((NSFont *)runFont, CTFontGetSize(runFont)); runFontData = FontCache::fontCache()->fontDataFromFontPlatformData(&runFontPlatformData, DoNotRetain).get(); } } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm b/chromium/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm index ef8862c1006..3f69c1002d8 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm @@ -31,6 +31,8 @@ #import "platform/fonts/FontCache.h" #import <AppKit/AppKit.h> +#import "platform/LayoutTestSupport.h" +#import "platform/RuntimeEnabledFeatures.h" #import "platform/fonts/FontDescription.h" #import "platform/fonts/FontPlatformData.h" #import "platform/fonts/SimpleFontData.h" @@ -64,6 +66,14 @@ static void fontCacheRegisteredFontsChangedNotificationCallback(CFNotificationCe invalidateFontCache(0); } +static bool useHinting() +{ + // Enable hinting when subpixel font scaling is disabled or + // when running the set of standard non-subpixel layout tests, + // otherwise use subpixel glyph positioning. + return (isRunningLayoutTest() && !isFontAntialiasingEnabledForTest()) || !RuntimeEnabledFeatures::subpixelFontScalingEnabled(); +} + void FontCache::platformInit() { CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this, fontCacheRegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); @@ -90,7 +100,7 @@ static inline bool isAppKitFontWeightBold(NSInteger appKitFontWeight) return appKitFontWeight >= 7; } -PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData* fontDataToSubstitute, bool disallowSynthetics) +PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData* fontDataToSubstitute) { // FIXME: We should fix getFallbackFamily to take a UChar32 // and remove this split-to-UChar16 code. @@ -116,11 +126,11 @@ PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDes if (!substituteFont && codeUnitsLength == 1) substituteFont = [NSFont findFontLike:nsFont forCharacter:codeUnits[0] inLanguage:nil]; if (!substituteFont) - return 0; + return nullptr; // Chromium can't render AppleColorEmoji. if ([[substituteFont familyName] isEqual:@"Apple Color Emoji"]) - return 0; + return nullptr; // Use the family name from the AppKit-supplied substitute font, requesting the // traits, weight, and size we want. One way this does better than the original @@ -144,7 +154,7 @@ PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDes size = [nsFont pointSize]; } else { // For custom fonts nsFont is nil. - traits = fontDescription.italic() ? NSFontItalicTrait : 0; + traits = fontDescription.style() ? NSFontItalicTrait : 0; weight = toAppKitFontWeight(fontDescription.weight()); size = fontDescription.computedPixelSize(); } @@ -154,20 +164,20 @@ PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDes if (traits != substituteFontTraits || weight != substituteFontWeight || !nsFont) { if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont familyName] traits:traits weight:weight size:size]) { - if (!nsFont || (([fontManager traitsOfFont:bestVariation] != substituteFontTraits || [fontManager weightOfFont:bestVariation] != substituteFontWeight) - && [[bestVariation coveredCharacterSet] longCharacterIsMember:character])) + if ((!nsFont || [fontManager traitsOfFont:bestVariation] != substituteFontTraits || [fontManager weightOfFont:bestVariation] != substituteFontWeight) + && [[bestVariation coveredCharacterSet] longCharacterIsMember:character]) substituteFont = bestVariation; } } - substituteFont = fontDescription.usePrinterFont() ? [substituteFont printerFont] : [substituteFont screenFont]; + substituteFont = useHinting() ? [substituteFont screenFont] : [substituteFont printerFont]; substituteFontTraits = [fontManager traitsOfFont:substituteFont]; substituteFontWeight = [fontManager weightOfFont:substituteFont]; - FontPlatformData alternateFont(substituteFont, platformData.size(), platformData.isPrinterFont(), - !disallowSynthetics && isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(substituteFontWeight), - !disallowSynthetics && (traits & NSFontItalicTrait) && !(substituteFontTraits & NSFontItalicTrait), + FontPlatformData alternateFont(substituteFont, platformData.size(), + isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(substituteFontWeight), + (traits & NSFontItalicTrait) && !(substituteFontTraits & NSFontItalicTrait), platformData.m_orientation); return fontDataFromFontPlatformData(&alternateFont, DoNotRetain); @@ -193,7 +203,7 @@ PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescri FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, float fontSize) { - NSFontTraitMask traits = fontDescription.italic() ? NSFontItalicTrait : 0; + NSFontTraitMask traits = fontDescription.style() ? NSFontItalicTrait : 0; NSInteger weight = toAppKitFontWeight(fontDescription.weight()); float size = fontSize; @@ -203,17 +213,17 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD NSFontManager *fontManager = [NSFontManager sharedFontManager]; NSFontTraitMask actualTraits = 0; - if (fontDescription.italic()) + if (fontDescription.style()) actualTraits = [fontManager traitsOfFont:nsFont]; NSInteger actualWeight = [fontManager weightOfFont:nsFont]; - NSFont *platformFont = fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont]; + NSFont *platformFont = useHinting() ? [nsFont screenFont] : [nsFont printerFont]; bool syntheticBold = (isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight)) || fontDescription.isSyntheticBold(); bool syntheticOblique = ((traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait)) || fontDescription.isSyntheticItalic(); // FontPlatformData::font() can be null for the case of Chromium out-of-process font loading. // In that case, we don't want to use the platformData. - OwnPtr<FontPlatformData> platformData = adoptPtr(new FontPlatformData(platformFont, size, fontDescription.usePrinterFont(), syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant())); + OwnPtr<FontPlatformData> platformData = adoptPtr(new FontPlatformData(platformFont, size, syntheticBold, syntheticOblique, fontDescription.orientation(), fontDescription.widthVariant())); if (!platformData->font()) return 0; return platformData.leakPtr(); diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/FontComplexTextMac.cpp b/chromium/third_party/WebKit/Source/platform/fonts/mac/FontComplexTextMac.cpp index 1626aaacb81..73eb52c1e6a 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/FontComplexTextMac.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/FontComplexTextMac.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "platform/fonts/Font.h" +#include "platform/fonts/Character.h" #include "platform/fonts/FontFallbackList.h" #include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/SimpleFontData.h" @@ -68,23 +69,23 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x() + afterWidth) - floorf(point.x() + beforeWidth), h); } -float Font::getGlyphsAndAdvancesForComplexText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const +float Font::getGlyphsAndAdvancesForComplexText(const TextRunPaintInfo& runInfo, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const { float initialAdvance; - ComplexTextController controller(this, run, false, 0, forTextEmphasis); - controller.advance(from); + ComplexTextController controller(this, runInfo.run, false, 0, forTextEmphasis); + controller.advance(runInfo.from); float beforeWidth = controller.runWidthSoFar(); - controller.advance(to, &glyphBuffer); + controller.advance(runInfo.to, &glyphBuffer); if (glyphBuffer.isEmpty()) return 0; float afterWidth = controller.runWidthSoFar(); - if (run.rtl()) { + if (runInfo.run.rtl()) { initialAdvance = controller.totalWidth() + controller.finalRoundingWidth() - afterWidth; - glyphBuffer.reverse(0, glyphBuffer.size()); + glyphBuffer.reverse(); } else initialAdvance = beforeWidth; @@ -105,7 +106,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRunPaintInfo& run // This glyph buffer holds our glyphs + advances + font data for each glyph. GlyphBuffer glyphBuffer; - float startX = point.x() + getGlyphsAndAdvancesForComplexText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer); + float startX = point.x() + getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer); // We couldn't generate any glyphs for the run. Give up. if (glyphBuffer.isEmpty()) @@ -119,7 +120,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRunPaintInfo& run void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const { GlyphBuffer glyphBuffer; - float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo.run, runInfo.from, runInfo.to, glyphBuffer, ForTextEmphasis); + float initialAdvance = getGlyphsAndAdvancesForComplexText(runInfo, glyphBuffer, ForTextEmphasis); if (glyphBuffer.isEmpty()) return; @@ -127,7 +128,7 @@ void Font::drawEmphasisMarksForComplexText(GraphicsContext* context, const TextR drawEmphasisMarks(context, runInfo, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y())); } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, IntRectExtent* glyphBounds) const { if (preferHarfBuzz(this)) { HarfBuzzShaper shaper(this, run); @@ -135,12 +136,11 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon return shaper.totalWidth(); } ComplexTextController controller(this, run, true, fallbackFonts); - if (glyphOverflow) { - glyphOverflow->top = max<int>(glyphOverflow->top, ceilf(-controller.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent())); - glyphOverflow->bottom = max<int>(glyphOverflow->bottom, ceilf(controller.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent())); - glyphOverflow->left = max<int>(0, ceilf(-controller.minGlyphBoundingBoxX())); - glyphOverflow->right = max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth())); - } + glyphBounds->setTop(floorf(-controller.minGlyphBoundingBoxY())); + glyphBounds->setBottom(ceilf(controller.maxGlyphBoundingBoxY())); + glyphBounds->setLeft(max<int>(0, floorf(-controller.minGlyphBoundingBoxX()))); + glyphBounds->setRight(max<int>(0, ceilf(controller.maxGlyphBoundingBoxX() - controller.totalWidth()))); + return controller.totalWidth(); } @@ -176,7 +176,7 @@ const SimpleFontData* Font::fontDataForCombiningCharacterSequence(const UChar* c const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(baseCharacter); if (variant == NormalVariant) { if (simpleFontData->platformData().orientation() == Vertical) { - if (isCJKIdeographOrSymbol(baseCharacter) && !simpleFontData->hasVerticalGlyphs()) { + if (Character::isCJKIdeographOrSymbol(baseCharacter) && !simpleFontData->hasVerticalGlyphs()) { variant = BrokenIdeographVariant; simpleFontData = simpleFontData->brokenIdeographFontData().get(); } else if (m_fontDescription.nonCJKGlyphOrientation() == NonCJKGlyphOrientationVerticalRight) { diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/FontMac.cpp b/chromium/third_party/WebKit/Source/platform/fonts/mac/FontMac.cpp index b0fd0274743..b140c463817 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/FontMac.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/FontMac.cpp @@ -32,6 +32,7 @@ #include "platform/fonts/Font.h" #include "platform/LayoutTestSupport.h" +#include "platform/fonts/FontPlatformFeatures.h" #include "platform/fonts/FontSmoothingMode.h" #include "platform/fonts/GlyphBuffer.h" #include "platform/fonts/SimpleFontData.h" @@ -40,16 +41,15 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkTypeface.h" -#include "third_party/skia/include/ports/SkTypeface_mac.h" namespace WebCore { -bool Font::canReturnFallbackFontsForComplexText() +bool FontPlatformFeatures::canReturnFallbackFontsForComplexText() { return true; } -bool Font::canExpandAroundIdeographsInComplexText() +bool FontPlatformFeatures::canExpandAroundIdeographsInComplexText() { return true; } @@ -63,23 +63,16 @@ static void setupPaint(SkPaint* paint, const SimpleFontData* fontData, const Fon paint->setEmbeddedBitmapText(false); paint->setTextSize(SkFloatToScalar(textSize)); paint->setVerticalText(platformData.orientation() == Vertical); - SkTypeface* typeface = SkCreateTypefaceFromCTFont(platformData.ctFont()); - SkAutoUnref autoUnref(typeface); - paint->setTypeface(typeface); + paint->setTypeface(platformData.typeface()); paint->setFakeBoldText(platformData.m_syntheticBold); paint->setTextSkewX(platformData.m_syntheticOblique ? -SK_Scalar1 / 4 : 0); paint->setAutohinted(false); // freetype specific paint->setLCDRenderText(shouldSmoothFonts); paint->setSubpixelText(true); -#if OS(MACOSX) // When using CoreGraphics, disable hinting when webkit-font-smoothing:antialiased is used. // See crbug.com/152304 - if (font->fontDescription().fontSmoothing() == Antialiased) - paint->setHinting(SkPaint::kNo_Hinting); -#endif - - if (font->fontDescription().textRenderingMode() == GeometricPrecision) + if (font->fontDescription().fontSmoothing() == Antialiased || font->fontDescription().textRendering() == GeometricPrecision) paint->setHinting(SkPaint::kNo_Hinting); } @@ -90,8 +83,6 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& point, const FloatRect& textRect) const { - COMPILE_ASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t), GlyphBufferGlyphSize_equals_uint16_t); - bool shouldSmoothFonts = true; bool shouldAntialias = true; @@ -110,12 +101,12 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, break; } - if (!shouldUseSmoothing() || isRunningLayoutTest()) { + if (isRunningLayoutTest()) { shouldSmoothFonts = false; - shouldAntialias = false; + shouldAntialias = shouldAntialias && isFontAntialiasingEnabledForTest(); } - const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); + const Glyph* glyphs = glyphBuffer.glyphs(from); SkScalar x = SkFloatToScalar(point.x()); SkScalar y = SkFloatToScalar(point.y()); @@ -127,7 +118,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, // 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); + const FloatSize* adv = glyphBuffer.advances(from); SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); SkPoint* pos = storage.get(); @@ -149,32 +140,30 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, // We draw text up to two times (once for fill, once for stroke). if (textMode & TextModeFill) { - SkPaint paint; - gc->setupPaintForFilling(&paint); + SkPaint paint = gc->fillPaint(); setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts); gc->adjustTextRenderMode(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - gc->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, textRect, paint); + gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); } if ((textMode & TextModeStroke) && gc->strokeStyle() != NoStroke && gc->strokeThickness() > 0) { - SkPaint paint; - gc->setupPaintForStroking(&paint); + SkPaint paint = gc->strokePaint(); setupPaint(&paint, font, this, shouldAntialias, shouldSmoothFonts); gc->adjustTextRenderMode(&paint); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); if (textMode & TextModeFill) { // If we also filled, we don't want to draw shadows twice. - // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. + // See comment in FontHarfBuzz.cpp::paintGlyphs() for more details. paint.setLooper(0); } - gc->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, textRect, paint); + gc->drawPosText(glyphs, numGlyphs * sizeof(Glyph), pos, textRect, paint); } if (font->platformData().orientation() == Vertical) gc->restore(); diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/GlyphPageTreeNodeMac.cpp b/chromium/third_party/WebKit/Source/platform/fonts/mac/GlyphPageTreeNodeMac.cpp deleted file mode 100644 index 704d10df799..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/GlyphPageTreeNodeMac.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "platform/fonts/GlyphPageTreeNode.h" - -#include <ApplicationServices/ApplicationServices.h> -#include "platform/fonts/Font.h" -#include "platform/fonts/SimpleFontData.h" - -// Forward declare Mac SPIs. -// Request for public API: rdar://13787589 -extern "C" { -void CGFontGetGlyphsForUnichars(CGFontRef font, const UniChar chars[], CGGlyph glyphs[], size_t length); -} - -namespace WebCore { - -static bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) -{ - if (fontData->platformData().isCompositeFontReference()) - return true; - if (fontData->platformData().widthVariant() != RegularWidth || fontData->hasVerticalGlyphs()) { - // Ideographs don't have a vertical variant or width variants. - for (unsigned i = 0; i < bufferLength; ++i) { - if (!Font::isCJKIdeograph(buffer[i])) - return true; - } - } - - return false; -} - -bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) -{ - bool haveGlyphs = false; - - Vector<CGGlyph, 512> glyphs(bufferLength); - if (!shouldUseCoreText(buffer, bufferLength, fontData)) { - CGFontGetGlyphsForUnichars(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength); - for (unsigned i = 0; i < length; ++i) { - if (!glyphs[i]) - setGlyphDataForIndex(offset + i, 0, 0); - else { - setGlyphDataForIndex(offset + i, glyphs[i], fontData); - haveGlyphs = true; - } - } - } else if (!fontData->platformData().isCompositeFontReference() && fontData->platformData().widthVariant() != RegularWidth - && CTFontGetGlyphsForCharacters(fontData->platformData().ctFont(), buffer, glyphs.data(), bufferLength)) { - // When buffer consists of surrogate pairs, CTFontGetGlyphsForCharacters - // places the glyphs at indices corresponding to the first character of each pair. - unsigned glyphStep = bufferLength / length; - for (unsigned i = 0; i < length; ++i) { - if (!glyphs[i * glyphStep]) - setGlyphDataForIndex(offset + i, 0, 0); - else { - setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], fontData); - haveGlyphs = true; - } - } - } else { - // We ask CoreText for possible vertical variant glyphs - RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull)); - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), fontData->getCFStringAttributes(0, fontData->hasVerticalGlyphs() ? Vertical : Horizontal))); - RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get())); - - CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); - CFIndex runCount = CFArrayGetCount(runArray); - - // Initialize glyph entries - for (unsigned index = 0; index < length; ++index) - setGlyphDataForIndex(offset + index, 0, 0); - - Vector<CGGlyph, 512> glyphVector; - Vector<CFIndex, 512> indexVector; - bool done = false; - - // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may - // be non-CFEqual to fontData->platformData().cgFont(). - RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(fontData->platformData().ctFont(), 0)); - - for (CFIndex r = 0; r < runCount && !done ; ++r) { - // CTLine could map characters over multiple fonts using its own font fallback list. - // We need to pick runs that use the exact font we need, i.e., fontData->platformData().ctFont(). - CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); - ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); - - CFDictionaryRef attributes = CTRunGetAttributes(ctRun); - CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName)); - RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0)); - // Use CGFont here as CFEqual for CTFont counts all attributes for font. - bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get()); - if (gotBaseFont || fontData->platformData().isCompositeFontReference()) { - // This run uses the font we want. Extract glyphs. - CFIndex glyphCount = CTRunGetGlyphCount(ctRun); - const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun); - if (!glyphs) { - glyphVector.resize(glyphCount); - CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data()); - glyphs = glyphVector.data(); - } - const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun); - if (!stringIndices) { - indexVector.resize(glyphCount); - CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data()); - stringIndices = indexVector.data(); - } - - if (gotBaseFont) { - for (CFIndex i = 0; i < glyphCount; ++i) { - if (stringIndices[i] >= static_cast<CFIndex>(length)) { - done = true; - break; - } - if (glyphs[i]) { - setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], fontData); - haveGlyphs = true; - } - } - } else { - const SimpleFontData* runSimple = fontData->getCompositeFontReferenceFontData((NSFont *)runFont); - if (runSimple) { - for (CFIndex i = 0; i < glyphCount; ++i) { - if (stringIndices[i] >= static_cast<CFIndex>(length)) { - done = true; - break; - } - if (glyphs[i]) { - setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], runSimple); - haveGlyphs = true; - } - } - } - } - } - } - } - - return haveGlyphs; -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/MemoryActivatedFont.mm b/chromium/third_party/WebKit/Source/platform/fonts/mac/MemoryActivatedFont.mm index 3f3bbef007d..c96fe1e1e58 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/MemoryActivatedFont.mm +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/MemoryActivatedFont.mm @@ -118,10 +118,10 @@ PassRefPtr<MemoryActivatedFont> loadFontFromBrowserProcess(NSFont* nsFont) // font due to being blocked by the sandbox. // This by definition shouldn't happen if there is no sandbox support. ASSERT_NOT_REACHED(); - return 0; + return nullptr; } if (!sandboxSupport->loadFont(nsFont, &tmpCGFont, &fontID)) - return 0; + return nullptr; RetainPtr<CGFontRef> cgFont(tmpCGFont); // Now that we have the fontID from the browser process, we can consult diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataCoreText.cpp b/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataCoreText.cpp index 80a146e1f48..e3b0b86a380 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataCoreText.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataCoreText.cpp @@ -27,15 +27,24 @@ #include "config.h" #include "platform/fonts/SimpleFontData.h" +#include "platform/fonts/Character.h" +#include "platform/fonts/Font.h" +#include "platform/fonts/GlyphPage.h" #include <ApplicationServices/ApplicationServices.h> +// Forward declare Mac SPIs. +// Request for public API: rdar://13787589 +extern "C" { +void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar chars[], CGGlyph glyphs[], size_t length); +} + namespace WebCore { CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typesettingFeatures, FontOrientation orientation) const { unsigned key = typesettingFeatures + 1; HashMap<unsigned, RetainPtr<CFDictionaryRef> >::AddResult addResult = m_CFStringAttributes.add(key, RetainPtr<CFDictionaryRef>()); - RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.iterator->value; + RetainPtr<CFDictionaryRef>& attributesDictionary = addResult.storedValue->value; if (!addResult.isNewEntry) return attributesDictionary.get(); @@ -63,4 +72,130 @@ CFDictionaryRef SimpleFontData::getCFStringAttributes(TypesettingFeatures typese return attributesDictionary.get(); } +static bool shouldUseCoreText(UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + if (fontData->platformData().isCompositeFontReference()) + return true; + + // CoreText doesn't have vertical glyphs of surrogate pair characters. + // Therefore, we should not use CoreText, but this always returns horizontal glyphs. + // FIXME: We should use vertical glyphs. https://code.google.com/p/chromium/issues/detail?id=340173 + if (bufferLength >= 2 && U_IS_SURROGATE(buffer[0]) && fontData->hasVerticalGlyphs()) { + ASSERT(U_IS_SURROGATE_LEAD(buffer[0])); + ASSERT(U_IS_TRAIL(buffer[1])); + return false; + } + + if (fontData->platformData().widthVariant() != RegularWidth || fontData->hasVerticalGlyphs()) { + // Ideographs don't have a vertical variant or width variants. + for (unsigned i = 0; i < bufferLength; ++i) { + if (!Character::isCJKIdeograph(buffer[i])) + return true; + } + } + + return false; +} + +bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const +{ + bool haveGlyphs = false; + + Vector<CGGlyph, 512> glyphs(bufferLength); + if (!shouldUseCoreText(buffer, bufferLength, this)) { + CGFontGetGlyphsForUnichars(platformData().cgFont(), buffer, glyphs.data(), bufferLength); + for (unsigned i = 0; i < length; ++i) { + if (glyphs[i]) { + pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this); + haveGlyphs = true; + } + } + } else if (!platformData().isCompositeFontReference() && platformData().widthVariant() != RegularWidth + && CTFontGetGlyphsForCharacters(platformData().ctFont(), buffer, glyphs.data(), bufferLength)) { + // When buffer consists of surrogate pairs, CTFontGetGlyphsForCharacters + // places the glyphs at indices corresponding to the first character of each pair. + unsigned glyphStep = bufferLength / length; + for (unsigned i = 0; i < length; ++i) { + if (glyphs[i * glyphStep]) { + pageToFill->setGlyphDataForIndex(offset + i, glyphs[i * glyphStep], this); + haveGlyphs = true; + } + } + } else { + // We ask CoreText for possible vertical variant glyphs + RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, buffer, bufferLength, kCFAllocatorNull)); + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(kCFAllocatorDefault, string.get(), getCFStringAttributes(0, hasVerticalGlyphs() ? Vertical : Horizontal))); + RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithAttributedString(attributedString.get())); + + CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); + CFIndex runCount = CFArrayGetCount(runArray); + + Vector<CGGlyph, 512> glyphVector; + Vector<CFIndex, 512> indexVector; + bool done = false; + + // For the CGFont comparison in the loop, use the CGFont that Core Text assigns to the CTFont. This may + // be non-CFEqual to platformData().cgFont(). + RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().ctFont(), 0)); + + for (CFIndex r = 0; r < runCount && !done ; ++r) { + // CTLine could map characters over multiple fonts using its own font fallback list. + // We need to pick runs that use the exact font we need, i.e., platformData().ctFont(). + CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); + ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); + + CFDictionaryRef attributes = CTRunGetAttributes(ctRun); + CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(attributes, kCTFontAttributeName)); + RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0)); + // Use CGFont here as CFEqual for CTFont counts all attributes for font. + bool gotBaseFont = CFEqual(cgFont.get(), runCGFont.get()); + if (gotBaseFont || platformData().isCompositeFontReference()) { + // This run uses the font we want. Extract glyphs. + CFIndex glyphCount = CTRunGetGlyphCount(ctRun); + const CGGlyph* glyphs = CTRunGetGlyphsPtr(ctRun); + if (!glyphs) { + glyphVector.resize(glyphCount); + CTRunGetGlyphs(ctRun, CFRangeMake(0, 0), glyphVector.data()); + glyphs = glyphVector.data(); + } + const CFIndex* stringIndices = CTRunGetStringIndicesPtr(ctRun); + if (!stringIndices) { + indexVector.resize(glyphCount); + CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), indexVector.data()); + stringIndices = indexVector.data(); + } + + if (gotBaseFont) { + for (CFIndex i = 0; i < glyphCount; ++i) { + if (stringIndices[i] >= static_cast<CFIndex>(length)) { + done = true; + break; + } + if (glyphs[i]) { + pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], this); + haveGlyphs = true; + } + } + } else { + const SimpleFontData* runSimple = getCompositeFontReferenceFontData((NSFont *)runFont); + if (runSimple) { + for (CFIndex i = 0; i < glyphCount; ++i) { + if (stringIndices[i] >= static_cast<CFIndex>(length)) { + done = true; + break; + } + if (glyphs[i]) { + pageToFill->setGlyphDataForIndex(offset + stringIndices[i], glyphs[i], runSimple); + haveGlyphs = true; + } + } + } + } + } + } + } + + return haveGlyphs; +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataMac.mm b/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataMac.mm index 4d5533eea80..1fce9b54549 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataMac.mm +++ b/chromium/third_party/WebKit/Source/platform/fonts/mac/SimpleFontDataMac.mm @@ -31,6 +31,8 @@ #import <ApplicationServices/ApplicationServices.h> #import <float.h> #import <unicode/uchar.h> +#import "platform/LayoutTestSupport.h" +#import "platform/RuntimeEnabledFeatures.h" #import "platform/SharedBuffer.h" #import "platform/fonts/Font.h" #import "platform/fonts/FontCache.h" @@ -106,6 +108,14 @@ static NSString *webFallbackFontFamily(void) return webFallbackFontFamily.get(); } +static bool useHinting() +{ + // Enable hinting when subpixel font scaling is disabled or + // when running the set of standard non-subpixel layout tests, + // otherwise use subpixel glyph positioning. + return (isRunningLayoutTest() && !isFontAntialiasingEnabledForTest()) || !RuntimeEnabledFeatures::subpixelFontScalingEnabled(); +} + const SimpleFontData* SimpleFontData::getCompositeFontReferenceFontData(NSFont *key) const { if (key && !CFEqual(RetainPtr<CFStringRef>(AdoptCF, CTFontCopyPostScriptName(CTFontRef(key))).get(), CFSTR("LastResort"))) { @@ -119,15 +129,14 @@ const SimpleFontData* SimpleFontData::getCompositeFontReferenceFontData(NSFont * return found; } if (CFMutableDictionaryRef dictionary = m_derivedFontData->compositeFontReferences.get()) { - bool isUsingPrinterFont = platformData().isPrinterFont(); - NSFont *substituteFont = isUsingPrinterFont ? [key printerFont] : [key screenFont]; + NSFont *substituteFont = [key printerFont]; CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(substituteFont)); bool syntheticBold = platformData().syntheticBold() && !(traits & kCTFontBoldTrait); bool syntheticOblique = platformData().syntheticOblique() && !(traits & kCTFontItalicTrait); - FontPlatformData substitutePlatform(substituteFont, platformData().size(), isUsingPrinterFont, syntheticBold, syntheticOblique, platformData().orientation(), platformData().widthVariant()); - SimpleFontData* value = new SimpleFontData(substitutePlatform, isCustomFont() ? CustomFontData::create(false) : 0); + FontPlatformData substitutePlatform(substituteFont, platformData().size(), syntheticBold, syntheticOblique, platformData().orientation(), platformData().widthVariant()); + SimpleFontData* value = new SimpleFontData(substitutePlatform, isCustomFont() ? CustomFontData::create() : nullptr); if (value) { CFDictionaryAddValue(dictionary, key, value); return value; @@ -155,7 +164,7 @@ void SimpleFontData::platformInit() fallbackFontFamily = @"Times New Roman"; else fallbackFontFamily = webFallbackFontFamily(); - + // Try setting up the alternate font. // This is a last ditch effort to use a substitute font when something has gone wrong. #if !ERROR_DISABLED @@ -195,11 +204,12 @@ void SimpleFontData::platformInit() WTF_LOG_ERROR("failed to set up font, using system font %s", m_platformData.font()); initFontData(this); } - + int iAscent; int iDescent; int iLineGap; unsigned unitsPerEm; + iAscent = CGFontGetAscent(m_platformData.cgFont()); // Some fonts erroneously specify a positive descender value. We follow Core Text in assuming that // such fonts meant the same distance, but in the reverse direction. @@ -211,6 +221,8 @@ void SimpleFontData::platformInit() float ascent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize; float descent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize; float lineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize; + float underlineThickness = CTFontGetUnderlineThickness(m_platformData.ctFont()); + float underlinePosition = CTFontGetUnderlinePosition(m_platformData.ctFont()); // We need to adjust Times, Helvetica, and Courier to closely match the // vertical metrics of their Microsoft counterparts that are the de facto @@ -230,7 +242,7 @@ void SimpleFontData::platformInit() lineGap -= 3 - descent; descent = 3; } - + if (platformData().orientation() == Vertical && !isTextOrientationFallback()) m_hasVerticalGlyphs = fontHasVerticalGlyphs(m_platformData.ctFont()); @@ -253,6 +265,8 @@ void SimpleFontData::platformInit() m_fontMetrics.setDescent(descent); m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setXHeight(xHeight); + m_fontMetrics.setUnderlineThickness(underlineThickness); + m_fontMetrics.setUnderlinePosition(underlinePosition); } static CFDataRef copyFontTableForTag(FontPlatformData& platformData, FourCharCode tableName) @@ -264,7 +278,7 @@ void SimpleFontData::platformCharWidthInit() { m_avgCharWidth = 0; m_maxCharWidth = 0; - + RetainPtr<CFDataRef> os2Table(AdoptCF, copyFontTableForTag(m_platformData, 'OS/2')); if (os2Table && CFDataGetLength(os2Table.get()) >= 4) { const UInt8* os2 = CFDataGetBytePtr(os2Table.get()); @@ -304,16 +318,15 @@ PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const Fo if (isCustomFont()) { FontPlatformData scaledFontData(m_platformData); scaledFontData.m_size = scaledFontData.m_size * scaleFactor; - return SimpleFontData::create(scaledFontData, CustomFontData::create(false)); + return SimpleFontData::create(scaledFontData, CustomFontData::create()); } BEGIN_BLOCK_OBJC_EXCEPTIONS; float size = m_platformData.size() * scaleFactor; - FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size, m_platformData.isPrinterFont(), false, false, m_platformData.orientation()); + FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size, false, false, m_platformData.orientation()); - // AppKit resets the type information (screen/printer) when you convert a font to a different size. - // We have to fix up the font that we're handed back. - scaledFontData.setFont(fontDescription.usePrinterFont() ? [scaledFontData.font() printerFont] : [scaledFontData.font() screenFont]); + // AppKit forgets about hinting property when scaling, so we have to remind it. + scaledFontData.setFont(useHinting() ? [scaledFontData.font() screenFont] : [scaledFontData.font() printerFont]); if (scaledFontData.font()) { NSFontManager *fontManager = [NSFontManager sharedFontManager]; @@ -333,16 +346,7 @@ PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const Fo } END_BLOCK_OBJC_EXCEPTIONS; - return 0; -} - -bool SimpleFontData::containsCharacters(const UChar* characters, int length) const -{ - NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO]; - NSCharacterSet *set = [[m_platformData.font() coveredCharacterSet] invertedSet]; - bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound; - [string release]; - return result; + return nullptr; } void SimpleFontData::determinePitch() @@ -425,7 +429,7 @@ bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false); if (!addResult.isNewEntry) - return addResult.iterator->value; + return addResult.storedValue->value; RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().ctFont(), 0)); @@ -445,7 +449,7 @@ bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters return false; } - addResult.iterator->value = true; + addResult.storedValue->value = true; return true; } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeSanitizer.cpp b/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeSanitizer.cpp index 4829bd0fd0f..a66fec97067 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeSanitizer.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeSanitizer.cpp @@ -31,7 +31,7 @@ #include "config.h" #include "platform/fonts/opentype/OpenTypeSanitizer.h" -#include "RuntimeEnabledFeatures.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/SharedBuffer.h" #include "opentype-sanitiser.h" #include "ots-memory-stream.h" @@ -41,12 +41,12 @@ namespace WebCore { PassRefPtr<SharedBuffer> OpenTypeSanitizer::sanitize() { if (!m_buffer) - return 0; + return nullptr; // This is the largest web font size which we'll try to transcode. static const size_t maxWebFontSize = 30 * 1024 * 1024; // 30 MB if (m_buffer->size() > maxWebFontSize) - return 0; + return nullptr; if (RuntimeEnabledFeatures::woff2Enabled()) ots::EnableWOFF2(); @@ -60,7 +60,7 @@ PassRefPtr<SharedBuffer> OpenTypeSanitizer::sanitize() ots::ExpandingMemoryStream output(m_buffer->size(), maxWebFontSize); if (!ots::Process(&output, reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size())) - return 0; + return nullptr; const size_t transcodeLen = output.Tell(); return SharedBuffer::create(static_cast<unsigned char*>(output.get()), transcodeLen); diff --git a/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp b/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp index 7c8ab6ec5ce..c1df3abc0b6 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeVerticalData.cpp @@ -560,10 +560,9 @@ void OpenTypeVerticalData::substituteWithVerticalGlyphs(const SimpleFontData* fo return; for (unsigned index = offset, end = offset + length; index < end; ++index) { - Glyph glyph = glyphPage->glyphAt(index); - if (glyph) { - ASSERT(glyphPage->glyphDataForIndex(index).fontData == font); - Glyph to = map.get(glyph); + GlyphData glyphData = glyphPage->glyphDataForIndex(index); + if (glyphData.glyph && glyphData.fontData == font) { + Glyph to = map.get(glyphData.glyph); if (to) glyphPage->setGlyphDataForIndex(index, to, font); } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp b/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp index 6498da1a56e..1dfc9c768e5 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp @@ -49,57 +49,70 @@ void FontCache::platformInit() } #if !OS(WIN) && !OS(ANDROID) -PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*, bool) +PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*) { icu::Locale locale = icu::Locale::getDefault(); - FontCache::SimpleFontFamily family; - FontCache::getFontFamilyForCharacter(c, locale.getLanguage(), &family); - if (family.name.isEmpty()) - return 0; + FontCache::PlatformFallbackFont fallbackFont; + FontCache::getFontForCharacter(c, locale.getLanguage(), &fallbackFont); + if (fallbackFont.name.isEmpty()) + return nullptr; - AtomicString atomicFamily(family.name); + AtomicString atomicFamily(fallbackFont.name); // Changes weight and/or italic of given FontDescription depends on // the result of fontconfig so that keeping the correct font mapping // of the given character. See http://crbug.com/32109 for details. - bool shouldSetFakeBold = false; - bool shouldSetFakeItalic = false; + bool shouldSetSyntheticBold = false; + bool shouldSetSyntheticItalic = false; FontDescription description(fontDescription); - if (family.isBold && description.weight() < FontWeightBold) + if (fallbackFont.isBold && description.weight() < FontWeightBold) description.setWeight(FontWeightBold); - if (!family.isBold && description.weight() >= FontWeightBold) { - shouldSetFakeBold = true; + if (!fallbackFont.isBold && description.weight() >= FontWeightBold) { + shouldSetSyntheticBold = true; description.setWeight(FontWeightNormal); } - if (family.isItalic && description.italic() == FontItalicOff) - description.setItalic(FontItalicOn); - if (!family.isItalic && description.italic() == FontItalicOn) { - shouldSetFakeItalic = true; - description.setItalic(FontItalicOff); + if (fallbackFont.isItalic && description.style() == FontStyleNormal) + description.setStyle(FontStyleItalic); + if (!fallbackFont.isItalic && description.style() == FontStyleItalic) { + shouldSetSyntheticItalic = true; + description.setStyle(FontStyleNormal); } FontPlatformData* substitutePlatformData = getFontPlatformData(description, atomicFamily); if (!substitutePlatformData) - return 0; + return nullptr; FontPlatformData platformData = FontPlatformData(*substitutePlatformData); - platformData.setFakeBold(shouldSetFakeBold); - platformData.setFakeItalic(shouldSetFakeItalic); + platformData.setSyntheticBold(shouldSetSyntheticBold); + platformData.setSyntheticItalic(shouldSetSyntheticItalic); return fontDataFromFontPlatformData(&platformData, DoNotRetain); } -#endif // !OS(WINDOWNS) && !OS(ANDROID) +#endif // !OS(WIN) && !OS(ANDROID) PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& description, ShouldRetain shouldRetain) { const AtomicString fallbackFontFamily = getFallbackFontFamily(description); - const FontPlatformData* fontPlatformData = 0; - if (!fallbackFontFamily.isEmpty()) - fontPlatformData = getFontPlatformData(description, fallbackFontFamily); + const FontPlatformData* fontPlatformData = getFontPlatformData(description, fallbackFontFamily); + // We should at least have Sans or Arial which is the last resort fallback of SkFontHost ports. + if (!fontPlatformData) { + DEFINE_STATIC_LOCAL(const AtomicString, sansStr, ("Sans", AtomicString::ConstructFromLiteral)); + fontPlatformData = getFontPlatformData(description, sansStr); + } if (!fontPlatformData) { - // we should at least have Arial; this is the SkFontHost_fontconfig last resort fallback DEFINE_STATIC_LOCAL(const AtomicString, arialStr, ("Arial", AtomicString::ConstructFromLiteral)); fontPlatformData = getFontPlatformData(description, arialStr); } +#if OS(WIN) + // Try some more Windows-specific fallbacks. + if (!fontPlatformData) { + DEFINE_STATIC_LOCAL(const AtomicString, msuigothicStr, ("MS UI Gothic", AtomicString::ConstructFromLiteral)); + fontPlatformData = getFontPlatformData(description, msuigothicStr); + } + if (!fontPlatformData) { + DEFINE_STATIC_LOCAL(const AtomicString, mssansserifStr, ("Microsoft Sans Serif", AtomicString::ConstructFromLiteral)); + fontPlatformData = getFontPlatformData(description, mssansserifStr); + } +#endif ASSERT(fontPlatformData); return fontDataFromFontPlatformData(fontPlatformData, shouldRetain); @@ -107,42 +120,29 @@ PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescri PassRefPtr<SkTypeface> FontCache::createTypeface(const FontDescription& fontDescription, const AtomicString& family, CString& name) { - name = ""; - // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into // the fallback name (like "monospace") that fontconfig understands. if (!family.length() || family.startsWith("-webkit-")) { - 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; - } - } + name = getFallbackFontFamily(fontDescription).string().utf8(); } else { // convert the name to utf8 - name = family.string().utf8(); + name = family.utf8(); } int style = SkTypeface::kNormal; if (fontDescription.weight() >= FontWeightBold) style |= SkTypeface::kBold; - if (fontDescription.italic()) + if (fontDescription.style()) style |= SkTypeface::kItalic; +#if OS(WIN) + if (s_sideloadedFonts) { + HashMap<String, SkTypeface*>::iterator sideloadedFont = s_sideloadedFonts->find(name.data()); + if (sideloadedFont != s_sideloadedFonts->end()) { + return adoptRef(sideloadedFont->value); + } + } // FIXME: Use SkFontStyle and matchFamilyStyle instead of legacyCreateTypeface. -#if OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS) if (m_fontManager) return adoptRef(m_fontManager->legacyCreateTypeface(name.data(), style)); #endif @@ -162,11 +162,11 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD name.data(), fontSize, (fontDescription.weight() >= FontWeightBold && !tf->isBold()) || fontDescription.isSyntheticBold(), - (fontDescription.italic() && !tf->isItalic()) || fontDescription.isSyntheticItalic(), + (fontDescription.style() && !tf->isItalic()) || fontDescription.isSyntheticItalic(), fontDescription.orientation(), fontDescription.useSubpixelPositioning()); return result; } -#endif // !OS(WINDOWNS) +#endif // !OS(WIN) } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCustomPlatformDataSkia.cpp b/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCustomPlatformDataSkia.cpp index ecf42ef0664..3f552dc11e6 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCustomPlatformDataSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCustomPlatformDataSkia.cpp @@ -57,26 +57,31 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(float size, bool bold, { ASSERT(m_typeface); #if OS(WIN) - // FIXME: Skia currently renders synthetic bold and italics with hinting and without - // linear metrics on windows. Using CreateFromName and specifying the bold/italics - // style allows for proper rendering of synthetic style. Once Skia has been updated - // this workaround will no longer be needed. crbug.com/332958 - bool syntheticBold = bold && !m_typeface->isBold(); - bool syntheticItalic = italic && !m_typeface->isItalic(); - if (syntheticBold || syntheticItalic) { - SkString name; - m_typeface->getFamilyName(&name); + if (!FontCache::useDirectWrite()) { + // FIXME: Skia currently renders synthetic bold and italics with + // hinting and without linear metrics on the windows GDI backend + // while the DirectWrite backend does the right thing. Using + // CreateFromName and specifying the bold/italics style allows + // for proper rendering of synthetic style. Once Skia has been + // updated this workaround will no longer be needed. + // http://crbug.com/332958 + bool syntheticBold = bold && !m_typeface->isBold(); + bool syntheticItalic = italic && !m_typeface->isItalic(); + if (syntheticBold || syntheticItalic) { + SkString name; + m_typeface->getFamilyName(&name); - int style = SkTypeface::kNormal; - if (syntheticBold) - style |= SkTypeface::kBold; - if (syntheticItalic) - style |= SkTypeface::kItalic; + int style = SkTypeface::kNormal; + if (syntheticBold) + style |= SkTypeface::kBold; + if (syntheticItalic) + style |= SkTypeface::kItalic; - RefPtr<SkTypeface> typeface = adoptRef(SkTypeface::CreateFromName(name.c_str(), static_cast<SkTypeface::Style>(style))); - syntheticBold = false; - syntheticItalic = false; - return FontPlatformData(typeface.release(), "", size, syntheticBold, syntheticItalic, orientation); + RefPtr<SkTypeface> typeface = adoptRef(FontCache::fontCache()->fontManager()->legacyCreateTypeface(name.c_str(), static_cast<SkTypeface::Style>(style))); + syntheticBold = false; + syntheticItalic = false; + return FontPlatformData(typeface.release(), "", size, syntheticBold, syntheticItalic, orientation); + } } #endif return FontPlatformData(m_typeface.get(), "", size, bold && !m_typeface->isBold(), italic && !m_typeface->isItalic(), orientation); @@ -93,7 +98,7 @@ PassOwnPtr<FontCustomPlatformData> FontCustomPlatformData::create(SharedBuffer* buffer = transcodeBuffer.get(); RefPtr<SkMemoryStream> stream = adoptRef(new SkMemoryStream(buffer->getAsSkData().get())); -#if OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS) +#if OS(WIN) RefPtr<SkTypeface> typeface = adoptRef(FontCache::fontCache()->fontManager()->createFromStream(stream.get())); #else RefPtr<SkTypeface> typeface = adoptRef(SkTypeface::CreateFromStream(stream.get())); diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontPlatformDataSkia.cpp b/chromium/third_party/WebKit/Source/platform/fonts/skia/FontPlatformDataSkia.cpp index 3744cd2f233..ed0de7eab07 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontPlatformDataSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/skia/FontPlatformDataSkia.cpp @@ -37,11 +37,11 @@ namespace WebCore { -#if (!ENABLE(GDI_FONTS_ON_WINDOWS) || !OS(WIN)) && !OS(MACOSX) +#if !OS(MACOSX) unsigned FontPlatformData::hash() const { unsigned h = SkTypeface::UniqueID(m_typeface.get()); - h ^= 0x01010101 * ((static_cast<int>(m_orientation) << 2) | (static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic)); + h ^= 0x01010101 * ((static_cast<int>(m_orientation) << 2) | (static_cast<int>(m_syntheticBold) << 1) | static_cast<int>(m_syntheticItalic)); // This memcpy is to avoid a reinterpret_cast that breaks strict-aliasing // rules. Memcpy is generally optimized enough so that performance doesn't diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/SimpleFontDataSkia.cpp b/chromium/third_party/WebKit/Source/platform/fonts/skia/SimpleFontDataSkia.cpp index 7171bfb5a4a..0e20e86668f 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/SimpleFontDataSkia.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/skia/SimpleFontDataSkia.cpp @@ -36,15 +36,13 @@ #include "SkPath.h" #include "SkTypeface.h" #include "SkTypes.h" +#include "SkUtils.h" #include "platform/fonts/FontDescription.h" +#include "platform/fonts/GlyphPage.h" #include "platform/fonts/VDMXParser.h" #include "platform/geometry/FloatRect.h" #include "wtf/unicode/Unicode.h" -#if OS(WIN) -#include "platform/win/HWndDC.h" -#endif - namespace WebCore { // This is the largest VDMX table which we'll try to load and parse. @@ -67,20 +65,31 @@ void SimpleFontData::platformInit() SkTypeface* face = paint.getTypeface(); ASSERT(face); - static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); - int pixelSize = m_platformData.size() + 0.5; - int vdmxAscent, vdmxDescent; + int vdmxAscent = 0, vdmxDescent = 0; bool isVDMXValid = false; - size_t vdmxSize = face->getTableSize(vdmxTag); - if (vdmxSize && vdmxSize < maxVDMXTableSize) { - uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize); - if (vdmxTable - && face->getTableData(vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize - && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) - isVDMXValid = true; - fastFree(vdmxTable); +#if OS(LINUX) || OS(ANDROID) + // Manually digging up VDMX metrics is only applicable when bytecode hinting using FreeType. + // With GDI, the metrics will already have taken this into account (as needed). + // With DirectWrite or CoreText, no bytecode hinting is ever done. + // This code should be pushed into FreeType (hinted font metrics). + static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); + int pixelSize = m_platformData.size() + 0.5; + if (!paint.isAutohinted() + && (paint.getHinting() == SkPaint::kFull_Hinting + || paint.getHinting() == SkPaint::kNormal_Hinting)) + { + size_t vdmxSize = face->getTableSize(vdmxTag); + if (vdmxSize && vdmxSize < maxVDMXTableSize) { + uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize); + if (vdmxTable + && face->getTableData(vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize + && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize)) + isVDMXValid = true; + fastFree(vdmxTable); + } } +#endif float ascent; float descent; @@ -91,8 +100,8 @@ void SimpleFontData::platformInit() ascent = vdmxAscent; descent = -vdmxDescent; } else { - ascent = SkScalarRound(-metrics.fAscent); - descent = SkScalarRound(metrics.fDescent); + ascent = SkScalarRoundToInt(-metrics.fAscent); + descent = SkScalarRoundToInt(metrics.fDescent); #if OS(LINUX) || OS(ANDROID) // When subpixel positioning is enabled, if the descent is rounded down, the descent part // of the glyph may be truncated when displayed in a 'overflow: hidden' container. @@ -122,6 +131,13 @@ void SimpleFontData::platformInit() m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); + SkScalar underlineThickness, underlinePosition; + if (metrics.hasUnderlineThickness(&underlineThickness) + && metrics.hasUnderlinePosition(&underlinePosition)) { + m_fontMetrics.setUnderlineThickness(SkScalarToFloat(underlineThickness)); + m_fontMetrics.setUnderlinePosition(SkScalarToFloat(-underlinePosition)); + } + if (platformData().orientation() == Vertical && !isTextOrientationFallback()) { static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a'); static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G'); @@ -135,16 +151,16 @@ void SimpleFontData::platformInit() // calculated for us, but we need to calculate m_maxCharWidth and // m_avgCharWidth in order for text entry widgets to be sized correctly. #if OS(WIN) - m_maxCharWidth = SkScalarRound(metrics.fMaxCharWidth); + m_maxCharWidth = SkScalarRoundToInt(metrics.fMaxCharWidth); #else // FIXME: This seems incorrect and should probably use fMaxCharWidth as // the code path above. SkScalar xRange = metrics.fXMax - metrics.fXMin; - m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size())); + m_maxCharWidth = SkScalarRoundToInt(xRange * SkScalarRoundToInt(m_platformData.size())); #endif if (metrics.fAvgCharWidth) - m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); + m_avgCharWidth = SkScalarRoundToInt(metrics.fAvgCharWidth); else { m_avgCharWidth = xHeight; @@ -181,33 +197,7 @@ void SimpleFontData::platformDestroy() PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const FontDescription& fontDescription, float scaleFactor) const { const float scaledSize = lroundf(fontDescription.computedSize() * scaleFactor); - return SimpleFontData::create(FontPlatformData(m_platformData, scaledSize), isCustomFont() ? CustomFontData::create(false) : 0); -} - -bool SimpleFontData::containsCharacters(const UChar* characters, int length) const -{ - SkPaint paint; - static const unsigned maxBufferCount = 64; - uint16_t glyphs[maxBufferCount]; - - m_platformData.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 (!glyphs[i]) - return false; // missing glyph - } - - characters += n; - length -= n; - } - - return true; + return SimpleFontData::create(FontPlatformData(m_platformData, scaledSize), isCustomFont() ? CustomFontData::create() : nullptr); } void SimpleFontData::determinePitch() @@ -223,12 +213,6 @@ static inline void getSkiaBoundsForGlyph(SkPaint& paint, Glyph glyph, SkRect& bo paint.getTextPath(&glyph, sizeof(glyph), 0, 0, &path); bounds = path.getBounds(); - // FIXME(eae): getBounds currently returns an empty rect for bitmap - // fonts so fall back on the old behavior. Once fixed in Skia this - // fallback can go away. - if (bounds.isEmpty()) - paint.measureText(&glyph, 2, &bounds); - if (!paint.isSubpixelText()) { SkIRect ir; bounds.round(&ir); @@ -265,7 +249,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkScalar width = paint.measureText(&glyph, 2); if (!paint.isSubpixelText()) - width = SkScalarRound(width); + width = SkScalarRoundToInt(width); return SkScalarToFloat(width); } @@ -277,7 +261,7 @@ bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false); if (!addResult.isNewEntry) - return addResult.iterator->value; + return addResult.storedValue->value; UErrorCode error = U_ZERO_ERROR; Vector<UChar, 4> normalizedCharacters(length); @@ -290,11 +274,35 @@ bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters m_platformData.setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); if (paint.textToGlyphs(&normalizedCharacters[0], normalizedLength * 2, 0)) { - addResult.iterator->value = true; + addResult.storedValue->value = true; return true; } return false; } #endif +bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const +{ + if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { + SkDebugf("%s last char is high-surrogate", __FUNCTION__); + return false; + } + + SkAutoSTMalloc<GlyphPage::size, uint16_t> glyphStorage(length); + + uint16_t* glyphs = glyphStorage.get(); + SkTypeface* typeface = platformData().typeface(); + typeface->charsToGlyphs(buffer, SkTypeface::kUTF16_Encoding, glyphs, length); + + bool haveGlyphs = false; + for (unsigned i = 0; i < length; i++) { + if (glyphs[i]) { + pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this); + haveGlyphs = true; + } + } + + return haveGlyphs; +} + } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/SkiaFontWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/skia/SkiaFontWin.cpp deleted file mode 100644 index 7332e3566f8..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/SkiaFontWin.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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 "platform/fonts/skia/SkiaFontWin.h" - -#include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/win/FontPlatformDataWin.h" -#include "platform/graphics/Gradient.h" -#include "platform/graphics/GraphicsContext.h" -#include "platform/graphics/Pattern.h" -#include "platform/transforms/AffineTransform.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkDevice.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkShader.h" -#include "third_party/skia/include/core/SkTemplates.h" -#include "wtf/RefPtr.h" - -namespace WebCore { - -static void skiaDrawText(GraphicsContext* context, - const SkPoint& point, - const SkRect& textRect, - SkPaint* paint, - const WORD* glyphs, - const int* advances, - const GOFFSET* offsets, - unsigned numGlyphs) -{ - // Reserve space for 64 SkPoints on the stack. If numGlyphs is larger, the array - // will dynamically allocate it space for numGlyph glyphs. This is used to store - // the computed x,y locations. In the case where offsets==null, then we use it - // to store (twice as many) SkScalars for x[] - static const size_t kLocalGlyphMax = 64; - - SkScalar x = point.fX; - SkScalar y = point.fY; - if (offsets) { - SkAutoSTArray<kLocalGlyphMax, SkPoint> storage(numGlyphs); - SkPoint* pos = storage.get(); - for (unsigned i = 0; i < numGlyphs; i++) { - // GDI has dv go up, so we negate it - pos[i].set(x + SkIntToScalar(offsets[i].du), - y + -SkIntToScalar(offsets[i].dv)); - x += SkIntToScalar(advances[i]); - } - context->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, textRect, *paint); - } else { - SkAutoSTArray<kLocalGlyphMax * 2, SkScalar> storage(numGlyphs); - SkScalar* xpos = storage.get(); - for (unsigned i = 0; i < numGlyphs; i++) { - xpos[i] = x; - x += SkIntToScalar(advances[i]); - } - context->drawPosTextH(glyphs, numGlyphs * sizeof(uint16_t), - xpos, y, textRect, *paint); - } -} - -static void paintSkiaText(GraphicsContext* context, - const FontPlatformData& data, - SkTypeface* face, float size, uint32_t textFlags, - unsigned numGlyphs, - const WORD* glyphs, - const int* advances, - const GOFFSET* offsets, - const SkPoint& origin, - const SkRect& textRect) -{ - TextDrawingModeFlags textMode = context->textDrawingMode(); - - // Filling (if necessary). This is the common case. - SkPaint paint; - context->setupPaintForFilling(&paint); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - data.setupPaint(&paint, context); - - // FIXME: Only needed to support the HFONT based paintSkiaText - // version where a new typeface is created from the HFONT. - // As such it can go away once the HFONT code path is removed. - paint.setTypeface(face); - - bool didFill = false; - - if ((textMode & TextModeFill) && (SkColorGetA(paint.getColor()) || paint.getLooper())) { - skiaDrawText(context, origin, textRect, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); - didFill = true; - } - - // Stroking on top (if necessary). - if ((textMode & TextModeStroke) - && context->strokeStyle() != NoStroke - && context->strokeThickness() > 0) { - - paint.reset(); - context->setupPaintForStroking(&paint); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - data.setupPaint(&paint, context); - paint.setTypeface(face); - - 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); - } - - skiaDrawText(context, origin, textRect, &paint, &glyphs[0], &advances[0], &offsets[0], numGlyphs); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -void paintSkiaText(GraphicsContext* context, - const FontPlatformData& data, - unsigned numGlyphs, - const WORD* glyphs, - const int* advances, - const GOFFSET* offsets, - const SkPoint& origin, - const SkRect& textRect) -{ - paintSkiaText(context, data, data.typeface(), data.size(), data.paintTextFlags(), - numGlyphs, glyphs, advances, offsets, origin, textRect); -} -#if !USE(HARFBUZZ) -void paintSkiaText(GraphicsContext* context, - const FontPlatformData& data, - HFONT hfont, - unsigned numGlyphs, - const WORD* glyphs, - const int* advances, - const GOFFSET* offsets, - const SkPoint& origin, - const SkRect& textRect) -{ - int size; - int paintTextFlags = data->paintTextFlags(); - - // Ensure font load for printing, because PDF device needs it. - if (context->isPrintingDevice()) - FontPlatformData::ensureFontLoaded(hfont); - - RefPtr<SkTypeface> face = CreateTypefaceFromHFont(hfont, &size, &paintTextFlags); - paintSkiaText(context, data, face.get(), size, paintTextFlags, numGlyphs, glyphs, advances, offsets, origin, textRect); -} -#endif -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkiaWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp index d1b35b42ae7..dd088b96602 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkiaWin.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/win/FontCacheSkiaWin.cpp @@ -32,34 +32,43 @@ #include "config.h" #include "platform/fonts/FontCache.h" -#include "RuntimeEnabledFeatures.h" #include "SkFontMgr.h" #include "SkTypeface_win.h" +#include "platform/RuntimeEnabledFeatures.h" #include "platform/fonts/FontDescription.h" #include "platform/fonts/SimpleFontData.h" +#include "platform/fonts/harfbuzz/FontPlatformDataHarfbuzz.h" #include "platform/fonts/win/FontFallbackWin.h" -#include "platform/fonts/win/FontPlatformDataWin.h" namespace WebCore { +HashMap<String, SkTypeface*>* FontCache::s_sideloadedFonts = 0; + +// static +void FontCache::addSideloadedFontForTesting(SkTypeface* typeface) +{ + if (!s_sideloadedFonts) + s_sideloadedFonts = new HashMap<String, SkTypeface*>; + SkString name; + typeface->getFamilyName(&name); + s_sideloadedFonts->set(name.c_str(), typeface); +} + FontCache::FontCache() : m_purgePreventCount(0) { - SkFontMgr* fontManager = 0; + SkFontMgr* fontManager; - // Prefer DirectWrite (if runtime feature is enabled) but fallback - // to GDI on platforms where DirectWrite is not supported. - if (RuntimeEnabledFeatures::directWriteEnabled()) - fontManager = SkFontMgr_New_DirectWrite(); - - // Subpixel text positioning is not supported by the GDI backend. - m_useSubpixelPositioning = fontManager - ? RuntimeEnabledFeatures::subpixelFontScalingEnabled() - : false; - - if (!fontManager) + if (s_useDirectWrite) { + fontManager = SkFontMgr_New_DirectWrite(s_directWriteFactory); + s_useSubpixelPositioning = RuntimeEnabledFeatures::subpixelFontScalingEnabled(); + } else { fontManager = SkFontMgr_New_GDI(); + // Subpixel text positioning is not supported by the GDI backend. + s_useSubpixelPositioning = false; + } + ASSERT(fontManager); m_fontManager = adoptPtr(fontManager); } @@ -76,14 +85,15 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, const wchar_ // 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. -PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData*, bool) +PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData*) { // FIXME: Consider passing fontDescription.dominantScript() // to GetFallbackFamily here. UScriptCode script; const wchar_t* family = getFallbackFamily(character, fontDescription.genericFamily(), - &script); + &script, + m_fontManager.get()); FontPlatformData* data = 0; if (family) data = getFontPlatformData(fontDescription, AtomicString(family, wcslen(family))); @@ -147,6 +157,7 @@ PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDes family = panUniFonts[i]; data = getFontPlatformData(fontDescription, AtomicString(family, wcslen(family))); } + // When i-th font (0-base) in |panUniFonts| contains a character and // we get out of the loop, |i| will be |i + 1|. That is, if only the // last font in the array covers the character, |i| will be numFonts. @@ -155,7 +166,7 @@ PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDes if (i <= numFonts) return fontDataFromFontPlatformData(data, DoNotRetain); - return 0; + return nullptr; } static inline bool equalIgnoringCase(const AtomicString& a, const SkString& b) @@ -210,9 +221,28 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD name.data(), fontSize, fontDescription.weight() >= FontWeightBold && !tf->isBold() || fontDescription.isSyntheticBold(), - fontDescription.italic() && !tf->isItalic() || fontDescription.isSyntheticItalic(), + fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(), fontDescription.orientation(), - m_useSubpixelPositioning); + s_useSubpixelPositioning); + + struct FamilyMinSize { + const wchar_t* family; + unsigned minSize; + }; + const static FamilyMinSize minAntiAliasSizeForFont[] = { + { L"simsun", 16 }, + { L"dotum", 12 }, + { L"gulim", 12 } + }; + size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont); + for (size_t i = 0; i < numFonts; i++) { + FamilyMinSize entry = minAntiAliasSizeForFont[i]; + if (typefacesMatchesFamily(tf.get(), entry.family)) { + result->setMinSizeForAntiAlias(entry.minSize); + break; + } + } + return result; } diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/FontCacheWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/FontCacheWin.cpp deleted file mode 100644 index c94f9ed71a8..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/FontCacheWin.cpp +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Computer, Inc. - * Copyright (c) 2006, 2007, 2008, 2009, 2012 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 <unicode/uniset.h> -#include "platform/fonts/FontDescription.h" -#include "platform/LayoutTestSupport.h" -#include "platform/fonts/FontCache.h" -#include "platform/fonts/FontFallbackWin.h" -#include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/win/FontPlatformDataWin.h" -#include "platform/win/HWndDC.h" -#include "wtf/HashMap.h" -#include "wtf/text/StringHash.h" - -#include <windows.h> -#include <mlang.h> -#include <objidl.h> - -using std::min; - -namespace WebCore -{ - -// 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 { - const WCHAR* name; - int codePage; - }; - - struct NamePair { - const 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}}, - // 宋体-ExtB, SimSun-ExtB - {L"\x5B8B\x4F53-ExtB", {L"SimSun-ExtB", simplifiedChineseCodepage}}, - {L"simsun-extb", {L"\x5B8B\x4F53-extb", 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}}, - // 新細明體-ExtB, PMingLiu-ExtB - {L"\x65B0\x7D30\x660E\x9AD4-ExtB", {L"PMingLiu-ExtB", traditionalChineseCodepage}}, - {L"pmingliu-extb", {L"\x65B0\x7D30\x660E\x9AD4-extb", traditionalChineseCodepage}}, - // 細明體, MingLiu - {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}}, - {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, - // 細明體-ExtB, MingLiu-ExtB - {L"\x7D30\x660E\x9AD4-ExtB", {L"MingLiu-ExtB", traditionalChineseCodepage}}, - {L"mingliu-extb", {L"x65B0\x7D30\x660E\x9AD4-extb", 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) { - fontNameMap = new NameMap; - for (size_t i = 0; i < WTF_ARRAY_LENGTH(namePairs); ++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 (name.containsOnlyASCII()) { - 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->value->codePage; - - if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) { - altName = String(iter->value->name); - return true; - } - - return false; -} - -static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winfont, String* winName) -{ - unsigned len = family.copyTo(winfont->lfFaceName, 0, LF_FACESIZE - 1); - winfont->lfFaceName[len] = '\0'; - - HFONT hfont = CreateFontIndirect(winfont); - if (!hfont) - return 0; - - HWndDC dc(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); - *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*, icu::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*, icu::UnicodeSet*>::iterator it = fontCmapCache->find(family); - if (it != fontCmapCache->end()) - return it->value->contains(character); - - HFONT hfont = fontData->hfont(); - HWndDC hdc(0); - HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont)); - int count = GetFontUnicodeRanges(hdc, 0); - if (!count && FontPlatformData::ensureFontLoaded(hfont)) - count = GetFontUnicodeRanges(hdc, 0); - if (!count) { - WTF_LOG_ERROR("Unable to get the font unicode range after second attempt"); - SelectObject(hdc, oldFont); - return true; - } - - static Vector<char, 512>* gGlyphsetBuffer = 0; - if (!gGlyphsetBuffer) - gGlyphsetBuffer = new Vector<char, 512>(); - gGlyphsetBuffer->resize(GetFontUnicodeRanges(hdc, 0)); - GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(gGlyphsetBuffer->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); - - // 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; - icu::UnicodeSet* cmap = new icu::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); -} - -// Tries the given font and save it |outFontFamilyName| if it succeeds. -PassRefPtr<SimpleFontData> FontCache::fontDataFromDescriptionAndLogFont(const FontDescription& fontDescription, ShouldRetain shouldRetain, const LOGFONT& font, wchar_t* outFontFamilyName) -{ - RefPtr<SimpleFontData> fontData = getFontData(fontDescription, font.lfFaceName, false, shouldRetain); - if (fontData) - memcpy(outFontFamilyName, font.lfFaceName, sizeof(font.lfFaceName)); - return fontData.release(); -} - -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]; -} - -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 = isRunningLayoutTest() ? 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 GetLastResortFallbackFontProcData { - GetLastResortFallbackFontProcData(FontCache* fontCache, const FontDescription* fontDescription, FontCache::ShouldRetain shouldRetain, wchar_t* fontName) - : m_fontCache(fontCache) - , m_fontDescription(fontDescription) - , m_shouldRetain(shouldRetain) - , m_fontName(fontName) - , m_fontData(0) - { - } - - FontCache* m_fontCache; - const FontDescription* m_fontDescription; - FontCache::ShouldRetain m_shouldRetain; - wchar_t* m_fontName; - RefPtr<SimpleFontData> m_fontData; -}; - -static int CALLBACK getLastResortFallbackFontProc(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) -{ - GetLastResortFallbackFontProcData* procData = reinterpret_cast<GetLastResortFallbackFontProcData*>(lParam); - procData->m_fontData = procData->m_fontCache->fontDataFromDescriptionAndLogFont(*procData->m_fontDescription, procData->m_shouldRetain, *logFont, procData->m_fontName); - return !procData->m_fontData; -} - -void FontCache::platformInit() -{ - // Not needed on Windows. -} - -// 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. -PassRefPtr<SimpleFontData> FontCache::platformFallbackForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*, bool) -{ - // FIXME: We should fix getFallbackFamily to take a UChar32 - // and remove this split-to-UChar16 code. - UChar codeUnits[2]; - int codeUnitsLength; - if (inputC <= 0xFFFF) { - codeUnits[0] = inputC; - codeUnitsLength = 1; - } else { - codeUnits[0] = U16_LEAD(inputC); - codeUnits[1] = U16_TRAIL(inputC); - codeUnitsLength = 2; - } - - // FIXME: Consider passing fontDescription.dominantScript() - // to GetFallbackFamily here. - FontDescription fontDescription = fontDescription; - UChar32 c; - UScriptCode script; - const wchar_t* family = getFallbackFamily(codeUnits, codeUnitsLength, fontDescription.genericFamily(), &c, &script); - FontPlatformData* data = 0; - if (family) - data = getFontPlatformData(fontDescription, AtomicString(family, wcslen(family))); - - // 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", - // Six fonts below (and code2000 at the end) are not from MS, but - // once installed, cover a very wide range of characters. - L"dejavu serif", - L"dejavu sasns", - 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 = WTF_ARRAY_LENGTH(cjkFonts); - } else { - panUniFonts = commonFonts; - numFonts = WTF_ARRAY_LENGTH(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 = getFontPlatformData(fontDescription, AtomicString(family, wcslen(family))); - } - // When i-th font (0-base) in |panUniFonts| contains a character and - // we get out of the loop, |i| will be |i + 1|. That is, if only the - // last font in the array covers the character, |i| will be numFonts. - // So, we have to use '<=" rather than '<' to see if we found a font - // covering the character. - if (i <= numFonts) - return fontDataFromPlatformData(data, DoNotRetain); - - return 0; - -} - -PassRefPtr<SimpleFontData> FontCache::getLastResortFallbackFont(const FontDescription& description, ShouldRetain shouldRetain) -{ - FontDescription::GenericFamilyType generic = description.genericFamily(); - - // 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. - DEFINE_STATIC_LOCAL(AtomicString, timesStr, "Times New Roman"); - DEFINE_STATIC_LOCAL(AtomicString, courierStr, "Courier New"); - DEFINE_STATIC_LOCAL(AtomicString, arialStr, "Arial"); - - AtomicString& fontStr = timesStr; - if (generic == FontDescription::SansSerifFamily) - fontStr = arialStr; - else if (generic == FontDescription::MonospaceFamily) - fontStr = courierStr; - - RefPtr<SimpleFontData> simpleFont = getFontData(description, fontStr, false, shouldRetain); - if (simpleFont) - return simpleFont.release(); - - // Fall back to system fonts as Win Safari does because this function must - // return a valid font. Once we find a valid system font, we save its name - // to a static variable and use it to prevent trying system fonts again. - static wchar_t fallbackFontName[LF_FACESIZE] = {0}; - if (fallbackFontName[0]) - return getFontData(description, fallbackFontName, false, shouldRetain); - - // Fall back to the DEFAULT_GUI_FONT if no known Unicode fonts are available. - if (HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))) { - LOGFONT defaultGUILogFont; - GetObject(defaultGUIFont, sizeof(defaultGUILogFont), &defaultGUILogFont); - if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRetain, defaultGUILogFont, fallbackFontName)) - return simpleFont.release(); - } - - // Fall back to Non-client metrics fonts. - NONCLIENTMETRICS nonClientMetrics = {0}; - nonClientMetrics.cbSize = sizeof(nonClientMetrics); - if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nonClientMetrics), &nonClientMetrics, 0)) { - if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRetain, nonClientMetrics.lfMessageFont, fallbackFontName)) - return simpleFont.release(); - if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRetain, nonClientMetrics.lfMenuFont, fallbackFontName)) - return simpleFont.release(); - if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRetain, nonClientMetrics.lfStatusFont, fallbackFontName)) - return simpleFont.release(); - if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRetain, nonClientMetrics.lfCaptionFont, fallbackFontName)) - return simpleFont.release(); - if (simpleFont = fontDataFromDescriptionAndLogFont(description, shouldRetain, nonClientMetrics.lfSmCaptionFont, fallbackFontName)) - return simpleFont.release(); - } - - // Fall back to all the fonts installed in this PC. When a font has a - // localized name according to the system locale as well as an English name, - // both GetTextFace() and EnumFontFamilies() return the localized name. So, - // FontCache::createFontPlatformData() does not filter out the fonts - // returned by this EnumFontFamilies() call. - HWndDC dc(0); - if (dc) { - GetLastResortFallbackFontProcData procData(this, &description, shouldRetain, fallbackFontName); - EnumFontFamilies(dc, 0, getLastResortFallbackFontProc, reinterpret_cast<LPARAM>(&procData)); - - if (procData.m_fontData) - return procData.m_fontData.release(); - } - - ASSERT_NOT_REACHED(); - return 0; -} - -FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, float fontSize) -{ - 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, fontSize, fontDescription.orientation()); -} - -} diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/FontCustomPlatformDataWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/FontCustomPlatformDataWin.cpp deleted file mode 100644 index 43ae74c825e..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/FontCustomPlatformDataWin.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2013 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 "platform/fonts/FontCustomPlatformData.h" - -#include "platform/LayoutTestSupport.h" -#include "platform/SharedBuffer.h" -#include "platform/fonts/FontPlatformData.h" -#include "platform/fonts/opentype/OpenTypeSanitizer.h" -#include "platform/fonts/opentype/OpenTypeUtilities.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/RefPtr.h" -#include "wtf/text/Base64.h" - -#include <objbase.h> - -namespace { - -// Creates a unique and unpredictable font name, in order to avoid collisions and to -// not allow access from CSS. -String createUniqueFontName() -{ - GUID fontUuid; - CoCreateGuid(&fontUuid); - - String fontName = base64Encode(reinterpret_cast<char*>(&fontUuid), sizeof(fontUuid)); - ASSERT(fontName.length() < LF_FACESIZE); - return fontName; -} - -} // namespace - -namespace WebCore { - -FontCustomPlatformData::FontCustomPlatformData(HANDLE fontReference, const String& name) - : m_fontReference(fontReference) - , m_name(name) -{ -} - -FontCustomPlatformData::~FontCustomPlatformData() -{ - if (m_fontReference) - RemoveFontMemResourceEx(m_fontReference); -} - -FontPlatformData FontCustomPlatformData::fontPlatformData(float size, bool bold, bool italic, FontOrientation orientation, FontWidthVariant) -{ - ASSERT(m_fontReference); - - LOGFONT logFont; - // 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(); - } - unsigned len = m_name.copyTo(logFont.lfFaceName, 0, LF_FACESIZE - 1); - logFont.lfFaceName[len] = '\0'; - - // FIXME: almost identical to FillLogFont in FontCacheWin.cpp. - // Need to refactor. - logFont.lfHeight = -static_cast<int>(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 = isRunningLayoutTest() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings. - logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - logFont.lfItalic = italic; - logFont.lfWeight = bold ? FW_BOLD : FW_DONTCARE; - - HFONT hfont = CreateFontIndirect(&logFont); - return FontPlatformData(hfont, size, orientation); -} - -PassOwnPtr<FontCustomPlatformData> FontCustomPlatformData::create(SharedBuffer* buffer) -{ - ASSERT_ARG(buffer, buffer); - - OpenTypeSanitizer sanitizer(buffer); - RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize(); - if (!transcodeBuffer) - return nullptr; // validation failed. - buffer = transcodeBuffer.get(); - - // Introduce the font to GDI. AddFontMemResourceEx should be used with care, 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). - String fontName = createUniqueFontName(); - HANDLE fontReference = renameAndActivateFont(buffer, fontName); - if (!fontReference) - return nullptr; - - return adoptPtr(new FontCustomPlatformData(fontReference, fontName)); -} - -bool FontCustomPlatformData::supportsFormat(const String& format) -{ - return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype") || OpenTypeSanitizer::supportsFormat(format); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp index 6f4d91d6eb5..d8afcdc5155 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp @@ -31,7 +31,8 @@ #include "config.h" #include "platform/fonts/win/FontFallbackWin.h" -#include "platform/win/HWndDC.h" +#include "SkFontMgr.h" +#include "SkTypeface.h" #include "wtf/HashMap.h" #include "wtf/text/StringHash.h" #include "wtf/text/WTFString.h" @@ -43,29 +44,48 @@ namespace WebCore { namespace { -bool isFontPresent(const UChar* fontName) +static inline bool isFontPresent(const UChar* fontName, SkFontMgr* fontManager) { - HFONT hfont = CreateFont(12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fontName); - if (!hfont) + String family = fontName; + RefPtr<SkTypeface> tf = adoptRef(fontManager->legacyCreateTypeface(family.utf8().data(), SkTypeface::kNormal)); + if (!tf) return false; - HWndDC dc(0); - HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont)); - WCHAR actualFontName[LF_FACESIZE]; - GetTextFace(dc, LF_FACESIZE, actualFontName); - actualFontName[LF_FACESIZE - 1] = 0; - SelectObject(dc, oldFont); - DeleteObject(hfont); - // We don't have to worry about East Asian fonts with locale-dependent - // names here for now. - // FIXME: Why not? - return !wcscmp(fontName, actualFontName); + + SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator(); + bool matchesRequestedFamily = false; + SkTypeface::LocalizedString actualFamily; + while (actualFamilies->next(&actualFamily)) { + if (equalIgnoringCase(family, AtomicString::fromUTF8(actualFamily.fString.c_str()))) { + matchesRequestedFamily = true; + break; + } + } + actualFamilies->unref(); + + return matchesRequestedFamily; } // 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) +void initializeScriptMonospaceFontMap(ScriptToFontMap& scriptFontMap, SkFontMgr* fontManager) +{ + struct FontMap { + UScriptCode script; + const UChar* family; + }; + + static const FontMap fontMap[] = { + { USCRIPT_HEBREW, L"courier new" }, + { USCRIPT_ARABIC, L"courier new" }, + }; + + for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i) + scriptFontMap[fontMap[i].script] = fontMap[i].family; +} + +void initializeScriptFontMap(ScriptToFontMap& scriptFontMap, SkFontMgr* fontManager) { struct FontMap { UScriptCode script; @@ -160,7 +180,7 @@ void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) scriptFontMap[script] = 0; const UChar** familyPtr = scriptToFontFamilies[i].families; while (*familyPtr) { - if (isFontPresent(*familyPtr)) { + if (isFontPresent(*familyPtr, fontManager)) { scriptFontMap[script] = *familyPtr; break; } @@ -251,17 +271,22 @@ UScriptCode getScript(int ucs4) // - Update script_font_cache in response to WM_FONTCHANGE const UChar* getFontFamilyForScript(UScriptCode script, - FontDescription::GenericFamilyType generic) + FontDescription::GenericFamilyType generic, + SkFontMgr* fontManager) { static ScriptToFontMap scriptFontMap; + static ScriptToFontMap scriptMonospaceFontMap; static bool initialized = false; if (!initialized) { - initializeScriptFontMap(scriptFontMap); + initializeScriptFontMap(scriptFontMap, fontManager); + initializeScriptMonospaceFontMap(scriptMonospaceFontMap, fontManager); initialized = true; } if (script == USCRIPT_INVALID_CODE) return 0; ASSERT(script < USCRIPT_CODE_LIMIT); + if (generic == FontDescription::MonospaceFamily && scriptMonospaceFontMap[script]) + return scriptMonospaceFontMap[script]; return scriptFontMap[script]; } @@ -275,7 +300,8 @@ const UChar* getFontFamilyForScript(UScriptCode script, // font can cover) need to be taken into account const UChar* getFallbackFamily(UChar32 character, FontDescription::GenericFamilyType generic, - UScriptCode* scriptChecked) + UScriptCode* scriptChecked, + SkFontMgr* fontManager) { ASSERT(character); UScriptCode script = getScript(character); @@ -290,7 +316,7 @@ const UChar* getFallbackFamily(UChar32 character, if (script == USCRIPT_COMMON) script = getScriptBasedOnUnicodeBlock(character); - const UChar* family = getFontFamilyForScript(script, generic); + const UChar* family = getFontFamilyForScript(script, generic, fontManager); // Another lame work-around to cover non-BMP characters. // If the font family for script is not found or the character is // not in BMP (> U+FFFF), we resort to the hard-coded list of @@ -322,27 +348,4 @@ const UChar* getFallbackFamily(UChar32 character, return family; } - -const UChar* getFallbackFamilyForFirstNonCommonCharacter(const UChar* characters, - int length, - FontDescription::GenericFamilyType generic) -{ - 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) { - U16_NEXT(characters, i, length, ucs4); - script = getScript(ucs4); - } - - const UChar* family = getFallbackFamily(ucs4, generic, 0); - - return family; -} - } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.h b/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.h index 232b2e2ee90..75e62187858 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.h +++ b/chromium/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.h @@ -28,11 +28,6 @@ * 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 FontFallbackWin_h #define FontFallbackWin_h @@ -43,14 +38,9 @@ #include <wchar.h> #include <windows.h> -namespace WebCore { +class SkFontMgr; -// Return a font family that can render |characters| based on -// what script characters belong to. -// FIXME: This function needs a total overhaul. -PLATFORM_EXPORT const UChar* getFallbackFamilyForFirstNonCommonCharacter(const UChar* characters, - int length, - FontDescription::GenericFamilyType); +namespace WebCore { // Return a font family that can render |character| based on what script // that characters belong to. @@ -58,7 +48,8 @@ PLATFORM_EXPORT const UChar* getFallbackFamilyForFirstNonCommonCharacter(const U // the family is returned. PLATFORM_EXPORT const UChar* getFallbackFamily(UChar32 character, FontDescription::GenericFamilyType, - UScriptCode* scriptChecked); + UScriptCode* scriptChecked, + SkFontMgr* fontManager); } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp index e9eb7c1ab3a..a93e44c87bd 100644 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp +++ b/chromium/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp @@ -32,417 +32,123 @@ #include "config.h" #include "platform/fonts/FontPlatformData.h" +#include "SkTypeface.h" #include "platform/LayoutTestSupport.h" #include "platform/fonts/FontCache.h" -#if USE(HARFBUZZ) -#include "platform/fonts/harfbuzz/HarfBuzzFace.h" -#endif -#include "platform/fonts/skia/SkiaFontWin.h" #include "platform/graphics/GraphicsContext.h" -#include "platform/win/HWndDC.h" -#include "public/platform/Platform.h" -#include "public/platform/win/WebSandboxSupport.h" -#include "wtf/PassOwnPtr.h" -#include "wtf/StdLibExtras.h" -#include <mlang.h> -#include <objidl.h> #include <windows.h> namespace WebCore { +// Maximum font size, in pixels, at which embedded bitmaps will be used +// if available. +const float kMaxSizeForEmbeddedBitmap = 24.0f; + void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const { const float ts = m_textSize >= 0 ? m_textSize : 12; paint->setTextSize(SkFloatToScalar(m_textSize)); paint->setTypeface(typeface()); - paint->setFakeBoldText(m_fakeBold); - paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0); - paint->setSubpixelText(m_useSubpixelPositioning); - - int textFlags = paintTextFlags(); - // Only set painting flags when we're actually painting. - if (context && !context->couldUseLCDRenderedText()) { - textFlags &= ~SkPaint::kLCDRenderText_Flag; - // If we *just* clear our request for LCD, then GDI seems to - // sometimes give us AA text, and sometimes give us BW text. Since the - // original intent was LCD, we want to force AA (rather than BW), so we - // add a special bit to tell Skia to do its best to avoid the BW: by - // drawing LCD offscreen and downsampling that to AA. - textFlags |= SkPaint::kGenA8FromLCD_Flag; - } + paint->setFakeBoldText(m_syntheticBold); + paint->setTextSkewX(m_syntheticItalic ? -SK_Scalar1 / 4 : 0); + uint32_t textFlags = paintTextFlags(); + uint32_t flags = paint->getFlags(); static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag | SkPaint::kGenA8FromLCD_Flag; - - SkASSERT(!(textFlags & ~textFlagsMask)); - uint32_t flags = paint->getFlags(); flags &= ~textFlagsMask; - flags |= textFlags; + + if (ts <= kMaxSizeForEmbeddedBitmap) + flags |= SkPaint::kEmbeddedBitmapText_Flag; + + if (ts >= m_minSizeForAntiAlias) { + if (m_useSubpixelPositioning) + flags |= SkPaint::kSubpixelText_Flag; + + // Only set painting flags when we're actually painting. + if (context && !context->couldUseLCDRenderedText()) { + textFlags &= ~SkPaint::kLCDRenderText_Flag; + // If we *just* clear our request for LCD, then GDI seems to + // sometimes give us AA text, and sometimes give us BW text. Since the + // original intent was LCD, we want to force AA (rather than BW), so we + // add a special bit to tell Skia to do its best to avoid the BW: by + // drawing LCD offscreen and downsampling that to AA. + textFlags |= SkPaint::kGenA8FromLCD_Flag; + } + SkASSERT(!(textFlags & ~textFlagsMask)); + flags |= textFlags; + } + paint->setFlags(flags); } // Lookup the current system settings for font smoothing. // We cache these values for performance, but if the browser has a way to be // notified when these change, we could re-query them at that time. -static uint32_t getDefaultGDITextFlags() +static uint32_t getSystemTextFlags() { static bool gInited; static uint32_t gFlags; if (!gInited) { BOOL enabled; gFlags = 0; - if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) { - gFlags |= SkPaint::kAntiAlias_Flag; - - UINT smoothType; - if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) { - if (FE_FONTSMOOTHINGCLEARTYPE == smoothType) - gFlags |= SkPaint::kLCDRenderText_Flag; + if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0)) { + if (enabled) { + gFlags |= SkPaint::kAntiAlias_Flag; + + UINT smoothType; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) { + if (FE_FONTSMOOTHINGCLEARTYPE == smoothType) + gFlags |= SkPaint::kLCDRenderText_Flag; + } } + } else { + // SystemParametersInfo will fail only under full sandbox lockdown on Win8+. + // So, we default to settings we know are supported and look good. + // FIXME(eae): We should be querying the DirectWrite settings directly + // so we can respect the settings for users who turn off smoothing. + gFlags = SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag; } gInited = true; } return gFlags; } -static bool isWebFont(const LOGFONT& lf) +static bool isWebFont(const String& familyName) { - // web-fonts have artifical names constructed to always be + // Web-fonts have artifical names constructed to always be: // 1. 24 characters, followed by a '\0' // 2. the last two characters are '==' - return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24]; + return familyName.length() == 24 + && '=' == familyName[22] && '=' == familyName[23]; } -static int computePaintTextFlags(const LOGFONT& lf) +static int computePaintTextFlags(String fontFamilyName) { - int textFlags = 0; - switch (lf.lfQuality) { - case NONANTIALIASED_QUALITY: - textFlags = 0; - break; - case ANTIALIASED_QUALITY: - textFlags = SkPaint::kAntiAlias_Flag; - break; - case CLEARTYPE_QUALITY: - textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag); - break; - default: - textFlags = getDefaultGDITextFlags(); - break; - } + if (isRunningLayoutTest()) + return isFontAntialiasingEnabledForTest() ? SkPaint::kAntiAlias_Flag : 0; - // only allow features that SystemParametersInfo allows - textFlags &= getDefaultGDITextFlags(); + int textFlags = getSystemTextFlags(); - /* - * FontPlatformData(...) will read our logfont, and try to honor the the lfQuality - * setting (computing the corresponding SkPaint flags for AA and LCD). However, it - * will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean - * we end up drawing the text in BW, even though our lfQuality requested antialiasing. - * - * Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW. - * In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA, - * even when the System (getDefaultGDITextFlags) tells us to draw only in BW. - */ - if (isWebFont(lf) && !isRunningLayoutTest()) + // Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW. + // In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA, + // even when the System (getSystemTextFlags) tells us to draw only in BW. + if (isWebFont(fontFamilyName)) textFlags |= SkPaint::kAntiAlias_Flag; - return textFlags; -} - -#if !USE(HARFBUZZ) -PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags) -{ - LOGFONT info; - GetObject(hfont, sizeof(info), &info); - if (size) { - int height = info.lfHeight; - if (height < 0) - height = -height; - *size = height; - } - if (paintTextFlags) - *paintTextFlags = computePaintTextFlags(info); - return adoptRef(SkCreateTypefaceFromLOGFONT(info)); -} -#endif - -FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType) - : m_textSize(-1) - , m_fakeBold(false) - , m_fakeItalic(false) - , m_orientation(Horizontal) - , m_typeface(adoptRef(SkTypeface::RefDefault())) - , m_paintTextFlags(0) - , m_isHashTableDeletedValue(true) - , m_useSubpixelPositioning(false) -{ -#if !USE(HARFBUZZ) - m_font = 0; - m_scriptCache = 0; -#endif -} - -FontPlatformData::FontPlatformData() - : m_textSize(0) - , m_fakeBold(false) - , m_fakeItalic(false) - , m_orientation(Horizontal) - , m_typeface(adoptRef(SkTypeface::RefDefault())) - , m_paintTextFlags(0) - , m_isHashTableDeletedValue(false) - , m_useSubpixelPositioning(false) -{ -#if !USE(HARFBUZZ) - m_font = 0; - m_scriptCache = 0; -#endif -} - -#if ENABLE(GDI_FONTS_ON_WINDOWS) && !USE(HARFBUZZ) -FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation) - : m_font(RefCountedHFONT::create(font)) - , m_textSize(size) - , m_fakeBold(false) - , m_fakeItalic(false) - , m_orientation(orientation) - , m_scriptCache(0) - , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags)) - , m_isHashTableDeletedValue(false) - , m_useSubpixelPositioning(false) -{ -} -#endif - -// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much -FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) - : m_textSize(size) - , m_fakeBold(false) - , m_fakeItalic(false) - , m_orientation(Horizontal) - , m_typeface(adoptRef(SkTypeface::RefDefault())) - , m_paintTextFlags(0) - , m_isHashTableDeletedValue(false) - , m_useSubpixelPositioning(false) -{ -#if !USE(HARFBUZZ) - m_font = 0; - m_scriptCache = 0; -#endif -} - -FontPlatformData::FontPlatformData(const FontPlatformData& data) - : m_textSize(data.m_textSize) - , m_fakeBold(data.m_fakeBold) - , m_fakeItalic(data.m_fakeItalic) - , m_orientation(data.m_orientation) - , m_typeface(data.m_typeface) - , m_paintTextFlags(data.m_paintTextFlags) - , m_isHashTableDeletedValue(false) - , m_useSubpixelPositioning(data.m_useSubpixelPositioning) -{ -#if !USE(HARFBUZZ) - m_font = data.m_font; - m_scriptCache = 0; -#endif -} - -FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize) - : m_textSize(textSize) - , m_fakeBold(data.m_fakeBold) - , m_fakeItalic(data.m_fakeItalic) - , m_orientation(data.m_orientation) - , m_typeface(data.m_typeface) - , m_paintTextFlags(data.m_paintTextFlags) - , m_isHashTableDeletedValue(false) - , m_useSubpixelPositioning(data.m_useSubpixelPositioning) -{ -#if !USE(HARFBUZZ) - m_font = data.m_font; - m_scriptCache = 0; -#endif -} - -FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family, - float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation, - bool useSubpixelPositioning) - : m_textSize(textSize) - , m_fakeBold(fakeBold) - , m_fakeItalic(fakeItalic) - , m_orientation(orientation) - , m_typeface(tf) - , m_isHashTableDeletedValue(false) - , m_useSubpixelPositioning(useSubpixelPositioning) -{ - // FIXME: This can be removed together with m_font once the last few - // uses of hfont() has been eliminated. - LOGFONT logFont; - SkLOGFONTFromTypeface(m_typeface.get(), &logFont); - logFont.lfHeight = -textSize; - m_paintTextFlags = computePaintTextFlags(logFont); - -#if !USE(HARFBUZZ) - HFONT hFont = CreateFontIndirect(&logFont); - m_font = hFont ? RefCountedHFONT::create(hFont) : 0; - m_scriptCache = 0; -#endif -} - -FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data) -{ - if (this != &data) { - m_textSize = data.m_textSize; - m_fakeBold = data.m_fakeBold; - m_fakeItalic = data.m_fakeItalic; - m_orientation = data.m_orientation; - m_typeface = data.m_typeface; - m_paintTextFlags = data.m_paintTextFlags; - -#if !USE(HARFBUZZ) - m_font = data.m_font; - // The following fields will get re-computed if necessary. - ScriptFreeCache(&m_scriptCache); - m_scriptCache = 0; - m_scriptFontProperties.clear(); -#endif - } - return *this; -} - -FontPlatformData::~FontPlatformData() -{ -#if !USE(HARFBUZZ) - ScriptFreeCache(&m_scriptCache); - m_scriptCache = 0; -#endif -} - -String FontPlatformData::fontFamilyName() const -{ -#if ENABLE(GDI_FONTS_ON_WINDOWS) - HWndDC dc(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); - return String(name, resultLength); -#else - // FIXME: This returns the requested name, perhaps a better solution would be to - // return the list of names provided by SkTypeface::createFamilyNameIterator. - ASSERT(typeface()); - SkString familyName; - typeface()->getFamilyName(&familyName); - return String::fromUTF8(familyName.c_str()); -#endif -} - -bool FontPlatformData::isFixedPitch() const -{ -#if ENABLE(GDI_FONTS_ON_WINDOWS) - // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. - HWndDC dc(0); - HGDIOBJ oldFont = SelectObject(dc, 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 (ensureFontLoaded(hfont())) { - // Retry GetTextMetrics. - // FIXME: Handle gracefully the error if this call also fails. - // See http://crbug.com/6401. - if (!GetTextMetrics(dc, &textMetric)) - WTF_LOG_ERROR("Unable to get the text metrics after second attempt"); - } - } - - bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH); - - SelectObject(dc, oldFont); - - return treatAsFixedPitch; -#else - return typeface() && typeface()->isFixedPitch(); -#endif -} - -bool FontPlatformData::operator==(const FontPlatformData& a) const -{ - return SkTypeface::Equal(m_typeface.get(), a.m_typeface.get()) - && m_textSize == a.m_textSize - && m_fakeBold == a.m_fakeBold - && m_fakeItalic == a.m_fakeItalic - && m_orientation == a.m_orientation - && m_isHashTableDeletedValue == a.m_isHashTableDeletedValue; -} - -#if USE(HARFBUZZ) -HarfBuzzFace* FontPlatformData::harfBuzzFace() const -{ - if (!m_harfBuzzFace) - m_harfBuzzFace = HarfBuzzFace::create(const_cast<FontPlatformData*>(this), uniqueID()); - - return m_harfBuzzFace.get(); -} -#else -FontPlatformData::RefCountedHFONT::~RefCountedHFONT() -{ - DeleteObject(m_hfont); + return textFlags; } -SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const -{ - if (!m_scriptFontProperties) { - m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES); - memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES)); - m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES); - HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get()); - if (result == E_PENDING) { - HWndDC dc(0); - HGDIOBJ oldFont = SelectObject(dc, hfont()); - HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get()); - if (S_OK != hr) { - if (FontPlatformData::ensureFontLoaded(hfont())) { - // FIXME: Handle gracefully the error if this call also fails. - hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get()); - if (S_OK != hr) { - WTF_LOG_ERROR("Unable to get the font properties after second attempt"); - } - } - } - - SelectObject(dc, oldFont); - } - } - return m_scriptFontProperties.get(); -} -bool FontPlatformData::ensureFontLoaded(HFONT font) +void FontPlatformData::querySystemForRenderStyle(bool) { - blink::WebSandboxSupport* sandboxSupport = blink::Platform::current()->sandboxSupport(); - // if there is no sandbox, then we can assume the font - // was able to be loaded successfully already - return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true; + m_paintTextFlags = computePaintTextFlags(fontFamilyName()); } -#endif bool FontPlatformData::defaultUseSubpixelPositioning() { -#if OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS) return FontCache::fontCache()->useSubpixelPositioning(); -#else - return false; -#endif -} - -#ifndef NDEBUG -String FontPlatformData::description() const -{ - return String(); } -#endif } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.h b/chromium/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.h deleted file mode 100644 index 3b3e9736e1e..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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 FontPlatformDataChromiumWin_h -#define FontPlatformDataChromiumWin_h - -#include "SkPaint.h" -#include "SkTypeface.h" -#include "SkTypeface_win.h" -#include "platform/SharedBuffer.h" -#include "platform/fonts/FontOrientation.h" -#include "platform/fonts/opentype/OpenTypeVerticalData.h" -#include "wtf/Forward.h" -#include "wtf/HashTableDeletedValueType.h" -#include "wtf/OwnPtr.h" -#include "wtf/PassRefPtr.h" -#include "wtf/RefCounted.h" -#include "wtf/RefPtr.h" -#include "wtf/text/StringImpl.h" - -#include <usp10.h> - -typedef struct HFONT__ *HFONT; - -namespace WebCore { - -// Return a typeface associated with the hfont, and return its size and -// lfQuality from the hfont's LOGFONT. -PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT, int* size, int* paintTextFlags); - -class FontDescription; -class GraphicsContext; -class HarfBuzzFace; - -class PLATFORM_EXPORT 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(); -#if ENABLE(GDI_FONTS_ON_WINDOWS) - // This constructor takes ownership of the HFONT - FontPlatformData(HFONT, float size, FontOrientation); -#endif - FontPlatformData(float size, bool bold, bool oblique); - FontPlatformData(const FontPlatformData&); - FontPlatformData(const FontPlatformData&, float textSize); - FontPlatformData(PassRefPtr<SkTypeface>, const char* name, float textSize, bool fakeBold, bool fakeItalic, FontOrientation = Horizontal, bool useSubpixelPositioning = defaultUseSubpixelPositioning()); - - void setupPaint(SkPaint*, GraphicsContext* = 0) const; - - FontPlatformData& operator=(const FontPlatformData&); - - bool isHashTableDeletedValue() const { return m_isHashTableDeletedValue; } - - ~FontPlatformData(); - - bool isFixedPitch() const; - float size() const { return m_textSize; } -#if USE(HARFBUZZ) - HarfBuzzFace* harfBuzzFace() const; -#else - HFONT hfont() const { return m_font ? m_font->hfont() : 0; } -#endif - SkTypeface* typeface() const { return m_typeface.get(); } - SkFontID uniqueID() const { return m_typeface->uniqueID(); } - int paintTextFlags() const { return m_paintTextFlags; } - - String fontFamilyName() const; - - FontOrientation orientation() const { return m_orientation; } - void setOrientation(FontOrientation orientation) { m_orientation = orientation; } - -#if ENABLE(GDI_FONTS_ON_WINDOWS) - unsigned hash() const - { - return m_font ? m_font->hash() : NULL; - } -#else - unsigned hash() const; -#endif - - bool operator==(const FontPlatformData&) const; - -#if ENABLE(OPENTYPE_VERTICAL) - PassRefPtr<OpenTypeVerticalData> verticalData() const; - PassRefPtr<SharedBuffer> openTypeTable(uint32_t table) const; -#endif - -#ifndef NDEBUG - String description() const; -#endif - -#if !USE(HARFBUZZ) - SCRIPT_FONTPROPERTIES* scriptFontProperties() const; - SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; } - static bool ensureFontLoaded(HFONT); -#endif - -private: - bool static defaultUseSubpixelPositioning(); - -#if !USE(HARFBUZZ) - // 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 StringHasher::hashMemory<sizeof(HFONT)>(&m_hfont); - } - - 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; - }; - - RefPtr<RefCountedHFONT> m_font; -#endif // !USE(HARFBUZZ) - float m_textSize; // Point size of the font in pixels. - FontOrientation m_orientation; - bool m_fakeBold; - bool m_fakeItalic; - - RefPtr<SkTypeface> m_typeface; - int m_paintTextFlags; - -#if USE(HARFBUZZ) - mutable RefPtr<HarfBuzzFace> m_harfBuzzFace; -#else - mutable SCRIPT_CACHE m_scriptCache; - mutable OwnPtr<SCRIPT_FONTPROPERTIES> m_scriptFontProperties; -#endif - - bool m_isHashTableDeletedValue; - bool m_useSubpixelPositioning; -}; - -} // WebCore - -#endif // FontPlatformDataChromiumWin_h diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/FontWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/FontWin.cpp deleted file mode 100644 index 605d129ee89..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/FontWin.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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 "platform/fonts/Font.h" - -#include "platform/NotImplemented.h" -#include "platform/fonts/FontFallbackList.h" -#include "platform/fonts/GlyphBuffer.h" -#include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/skia/SkiaFontWin.h" -#include "platform/fonts/win/FontPlatformDataWin.h" -#include "platform/fonts/win/UniscribeHelperTextRun.h" -#include "platform/graphics/GraphicsContext.h" - -#include <windows.h> - -using namespace std; - -namespace WebCore { - -bool Font::canReturnFallbackFontsForComplexText() -{ - return false; -} - -bool Font::canExpandAroundIdeographsInComplexText() -{ - return false; -} - -void Font::drawGlyphs(GraphicsContext* graphicsContext, - const SimpleFontData* font, const GlyphBuffer& glyphBuffer, - unsigned from, unsigned numGlyphs, const FloatPoint& point, - const FloatRect& textRect) const -{ - SkColor color = graphicsContext->effectiveFillColor(); - unsigned char alpha = SkColorGetA(color); - // Skip 100% transparent text; no need to draw anything. - if (!alpha && graphicsContext->strokeStyle() == NoStroke && !graphicsContext->hasShadow()) - return; - - // We draw the glyphs in chunks to avoid having to do a heap allocation for - // the arrays of characters and advances. - const unsigned kMaxBufferLength = 256; - Vector<int, kMaxBufferLength> advances; - unsigned glyphIndex = 0; // The starting glyph of the current chunk. - - float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph. - -#if ENABLE(OPENTYPE_VERTICAL) - const OpenTypeVerticalData* verticalData = font->verticalData(); - if (verticalData) { - Vector<FloatPoint, kMaxBufferLength> translations; - Vector<GOFFSET, kMaxBufferLength> offsets; - - // Skia doesn't have matrix for glyph coordinate space, so we rotate back the CTM. - AffineTransform savedMatrix = graphicsContext->getCTM(); - graphicsContext->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y())); - graphicsContext->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y())); - - const FontMetrics& metrics = font->fontMetrics(); - SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline)); - while (glyphIndex < numGlyphs) { - // How many chars will be in this chunk? - unsigned curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); - - const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex); - translations.resize(curLen); - verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], curLen, reinterpret_cast<float*>(&translations[0])); - // To position glyphs vertically, we use offsets instead of advances. - advances.resize(curLen); - advances.fill(0); - offsets.resize(curLen); - float currentWidth = 0; - for (unsigned i = 0; i < curLen; ++i, ++glyphIndex) { - offsets[i].du = lroundf(translations[i].x()); - offsets[i].dv = -lroundf(currentWidth - translations[i].y()); - currentWidth += glyphBuffer.advanceAt(from + glyphIndex); - } - SkPoint origin; - origin.set(verticalOriginX, SkFloatToScalar(point.y() + horizontalOffset - point.x())); - horizontalOffset += currentWidth; - paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], &offsets[0], origin, SkRect(textRect)); - } - - graphicsContext->setCTM(savedMatrix); - return; - } -#endif - - // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position - // of each glyph in floating point units and rounds to integer advances at the last possible moment. - - int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered. - Vector<WORD, kMaxBufferLength> glyphs; - while (glyphIndex < numGlyphs) { - // How many chars will be in this chunk? - unsigned curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); - glyphs.resize(curLen); - advances.resize(curLen); - - float currentWidth = 0; - for (unsigned i = 0; i < curLen; ++i, ++glyphIndex) { - glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); - horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex); - advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded; - lastHorizontalOffsetRounded += advances[i]; - currentWidth += glyphBuffer.advanceAt(from + glyphIndex); - - // Bug 26088 - very large positive or negative runs can fail to - // render so we clamp the size here. In the specs, negative - // letter-spacing is implementation-defined, so this should be - // fine, and it matches Safari's implementation. The call actually - // seems to crash if kMaxNegativeRun is set to somewhere around - // -32830, so we give ourselves a little breathing room. - const int maxNegativeRun = -32768; - const int maxPositiveRun = 32768; - if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) - advances[i] = 0; - } - - SkPoint origin = point; - origin.fX += SkFloatToScalar(horizontalOffset - point.x() - currentWidth); - paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], 0, origin, SkRect(textRect)); - } -} - -FloatRect Font::selectionRectForComplexText(const TextRun& run, - const FloatPoint& 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, point.y(), - right - left, static_cast<float>(h)); - - return FloatRect(right, point.y(), - left - right, static_cast<float>(h)); -} - -void Font::drawComplexText(GraphicsContext* graphicsContext, - const TextRunPaintInfo& runInfo, - const FloatPoint& point) const -{ - UniscribeHelperTextRun state(runInfo.run, *this); - - SkColor color = graphicsContext->effectiveFillColor(); - unsigned char alpha = SkColorGetA(color); - // Skip 100% transparent text; no need to draw anything. - if (!alpha && graphicsContext->strokeStyle() == NoStroke) - return; - - HDC hdc = 0; - // Uniscribe counts the coordinates from the upper left, while WebKit uses - // the baseline, so we have to subtract off the ascent. - state.draw(graphicsContext, primaryFont()->platformData(), hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), runInfo.bounds, runInfo.from, runInfo.to); -} - -void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRunPaintInfo& /* runInfo */, const AtomicString& /* mark */, const FloatPoint& /* point */) const -{ - notImplemented(); -} - -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow* /* glyphOverflow */) const -{ - UniscribeHelperTextRun state(run, *this); - return static_cast<float>(state.width()); -} - -int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, - bool includePartialGlyphs) const -{ - // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers - // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem. - int x = static_cast<int>(xFloat); - - // 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/chromium/third_party/WebKit/Source/platform/fonts/win/GlyphPageTreeNodeWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/GlyphPageTreeNodeWin.cpp deleted file mode 100644 index a33515f252a..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/GlyphPageTreeNodeWin.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2012 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 <windows.h> -#include "config.h" -#include <vector> - -#include "platform/fonts/Font.h" -#include "platform/fonts/GlyphPageTreeNode.h" -#include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/win/FontPlatformDataWin.h" -#include "platform/fonts/win/UniscribeHelperTextRun.h" -#include "platform/win/HWndDC.h" -#include "platform/win/SystemInfo.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); -} - -// Convert characters to glyph ids by GetGlyphIndices(), during which, we -// ensure the font is loaded in memory to make it work in a sandboxed process. -static bool getGlyphIndices(HFONT font, HDC dc, const UChar* characters, unsigned charactersLength, WORD* glyphBuffer, DWORD flag) -{ - if (GetGlyphIndices(dc, characters, charactersLength, glyphBuffer, flag) != GDI_ERROR) - return true; - if (FontPlatformData::ensureFontLoaded(font)) { - if (GetGlyphIndices(dc, characters, charactersLength, glyphBuffer, flag) != GDI_ERROR) - return true; - // FIXME: Handle gracefully the error if this call also fails. - // See http://crbug.com/6401 - WTF_LOG_ERROR("Unable to get the glyph indices after second attempt"); - } - return false; -} - -// Initializes space glyph -static bool initSpaceGlyph(HFONT font, HDC dc, Glyph* spaceGlyph) -{ - static wchar_t space = ' '; - return getGlyphIndices(font, dc, &space, 1, spaceGlyph, 0); -} - -// 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) -{ - HWndDC dc(0); - HGDIOBJ oldFont = SelectObject(dc, fontData->platformData().hfont()); - - TEXTMETRIC tm = {0}; - if (!GetTextMetrics(dc, &tm)) { - if (FontPlatformData::ensureFontLoaded(fontData->platformData().hfont())) { - if (!GetTextMetrics(dc, &tm)) { - // FIXME: Handle gracefully the error if this call also fails. - // See http://crbug.com/6401 - WTF_LOG_ERROR("Unable to get the text metrics after second attempt"); - - SelectObject(dc, oldFont); - fillEmptyGlyphs(page); - return false; - } - } else { - SelectObject(dc, oldFont); - 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. - if (!getGlyphIndices(fontData->platformData().hfont(), dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS)) { - SelectObject(dc, oldFont); - fillEmptyGlyphs(page); - return false; - } - - // Copy the output to the GlyphPage - bool haveGlyphs = false; - int invalidGlyph = 0xFFFF; - const DWORD cffTableTag = 0x20464643; // 4-byte identifier for OpenType CFF table ('CFF '). - if (!isWindowsVistaOrGreater() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE) && (GetFontData(dc, cffTableTag, 0, 0, 0) == GDI_ERROR)) - invalidGlyph = 0x1F; - - Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled. - bool spaceGlyphInitialized = false; - - 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. - if (!spaceGlyphInitialized) { - // If initSpaceGlyph fails, spaceGlyph stays 0 (= glyph is not present). - initSpaceGlyph(fontData->platformData().hfont(), dc, &spaceGlyph); - spaceGlyphInitialized = true; - if (spaceGlyph) - haveGlyphs = true; - } - glyph = spaceGlyph; - } 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 - haveGlyphs = true; - page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData); - } - - SelectObject(dc, oldFont); - 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->platformData().hfont(), - fontData->platformData().scriptCache(), - fontData->platformData().scriptFontProperties()); - state.setInhibitLigate(true); - state.setDisableFontFallback(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); - - 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/chromium/third_party/WebKit/Source/platform/fonts/win/SimpleFontDataWin.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/SimpleFontDataWin.cpp deleted file mode 100644 index bc1d367140f..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/SimpleFontDataWin.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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 "platform/fonts/SimpleFontData.h" - -#include <mlang.h> -#include <objidl.h> -#include <unicode/uchar.h> -#include <unicode/unorm.h> -#include "platform/fonts/Font.h" -#include "platform/fonts/FontCache.h" -#include "platform/fonts/FontDescription.h" -#include "platform/fonts/win/FontPlatformDataWin.h" -#include "platform/geometry/FloatRect.h" -#include "platform/win/HWndDC.h" -#include "wtf/MathExtras.h" - -namespace WebCore { - -void SimpleFontData::platformInit() -{ - if (!m_platformData.size()) { - m_fontMetrics.reset(); - m_avgCharWidth = 0; - m_maxCharWidth = 0; - return; - } - - HWndDC dc(0); - HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); - - TEXTMETRIC textMetric = {0}; - if (!GetTextMetrics(dc, &textMetric)) { - if (FontPlatformData::ensureFontLoaded(m_platformData.hfont())) { - // Retry GetTextMetrics. - // FIXME: Handle gracefully the error if this call also fails. - // See http://crbug.com/6401. - if (!GetTextMetrics(dc, &textMetric)) - WTF_LOG_ERROR("Unable to get the text metrics after second attempt"); - } - } - - m_avgCharWidth = textMetric.tmAveCharWidth; - m_maxCharWidth = textMetric.tmMaxCharWidth; - - // FIXME: Access ascent/descent/lineGap with floating point precision. - float ascent = textMetric.tmAscent; - float descent = textMetric.tmDescent; - float lineGap = textMetric.tmExternalLeading; - float xHeight = ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. - - OUTLINETEXTMETRIC outlineTextMetric; - if (GetOutlineTextMetrics(dc, sizeof(outlineTextMetric), &outlineTextMetric) > 0) { - m_fontMetrics.setUnitsPerEm(outlineTextMetric.otmEMSquare); - - // 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) - xHeight = static_cast<float>(glyphMetrics.gmBlackBoxY); - } - - m_fontMetrics.setAscent(ascent); - m_fontMetrics.setDescent(descent); - m_fontMetrics.setLineGap(lineGap); - m_fontMetrics.setXHeight(xHeight); - m_fontMetrics.setLineSpacing(ascent + descent + lineGap); - - SelectObject(dc, oldFont); -} - -void SimpleFontData::platformCharWidthInit() -{ - // charwidths are set in platformInit. -} - -void SimpleFontData::platformDestroy() -{ -} - -PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const FontDescription& fontDescription, float scaleFactor) const -{ - LOGFONT winFont; - GetObject(m_platformData.hfont(), sizeof(LOGFONT), &winFont); - float scaledSize = scaleFactor * fontDescription.computedSize(); - winFont.lfHeight = -lroundf(scaledSize); - HFONT hfont = CreateFontIndirect(&winFont); - return SimpleFontData::create(FontPlatformData(hfont, scaledSize, m_platformData.orientation()), isCustomFont() ? CustomFontData::create(false) : 0); -} - -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() -{ - m_treatAsFixedPitch = platformData().isFixedPitch(); -} - -FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const -{ - HWndDC hdc(0); - SetGraphicsMode(hdc, GM_ADVANCED); - HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); - - GLYPHMETRICS gdiMetrics; - static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; - if (GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity) == -1) { - if (FontPlatformData::ensureFontLoaded(m_platformData.hfont())) { - // Retry GetTextMetrics. - // FIXME: Handle gracefully the error if this call also fails. - // See http://crbug.com/6401. - if (GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity) == -1) - WTF_LOG_ERROR("Unable to get the glyph metrics after second attempt"); - } - } - - SelectObject(hdc, oldFont); - - return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y, - gdiMetrics.gmBlackBoxX, gdiMetrics.gmBlackBoxY); -} - -float SimpleFontData::platformWidthForGlyph(Glyph glyph) const -{ - if (!m_platformData.size()) - return 0; - - HWndDC dc(0); - HGDIOBJ oldFont = SelectObject(dc, m_platformData.hfont()); - - int width = 0; - if (!GetCharWidthI(dc, glyph, 1, 0, &width)) { - // Ask the browser to preload the font and retry. - if (FontPlatformData::ensureFontLoaded(m_platformData.hfont())) { - // FIXME: Handle gracefully the error if this call also fails. - // See http://crbug.com/6401. - if (!GetCharWidthI(dc, glyph, 1, 0, &width)) - WTF_LOG_ERROR("Unable to get the char width after second attempt"); - } - } - - SelectObject(dc, oldFont); - - return static_cast<float>(width); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelper.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelper.cpp deleted file mode 100644 index f65ab128408..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelper.cpp +++ /dev/null @@ -1,1208 +0,0 @@ -/* - * Copyright (c) 2006, 2007, 2008, 2009, 2012 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 "platform/fonts/win/UniscribeHelper.h" - -#include "platform/fonts/Font.h" -#include "platform/fonts/skia/SkiaFontWin.h" -#include "platform/fonts/FontFallbackWin.h" -#include "platform/graphics/GraphicsContext.h" -#include "platform/win/HWndDC.h" -#include "third_party/skia/include/core/SkPoint.h" -#include "wtf/Assertions.h" - -namespace WebCore { - -// The function types for ScriptItemizeOpenType() and ScriptShapeOpenType(). -// We want to use these functions for OpenType feature support, but we can't -// call them directly because usp10.dll does not always have them. -// Instead, we use GetProcAddress() to check whether we can actually use these -// function. If we can't use these functions, we substitute ScriptItemze() and -// ScriptShape(). -typedef HRESULT (WINAPI *ScriptItemizeOpenTypeFunc)(const WCHAR*, int, int, - const SCRIPT_CONTROL*, - const SCRIPT_STATE*, - SCRIPT_ITEM*, - OPENTYPE_TAG*, int*); -typedef HRESULT (WINAPI *ScriptShapeOpenTypeFunc)(HDC, SCRIPT_CACHE*, - SCRIPT_ANALYSIS*, - OPENTYPE_TAG, OPENTYPE_TAG, - int*, TEXTRANGE_PROPERTIES**, - int, const WCHAR*, int, int, - WORD*, SCRIPT_CHARPROP*, - WORD*, SCRIPT_GLYPHPROP*, - int*); - -static ScriptItemizeOpenTypeFunc gScriptItemizeOpenTypeFunc = 0; -static ScriptShapeOpenTypeFunc gScriptShapeOpenTypeFunc = 0; -static bool gOpenTypeFunctionsLoaded = false; - -static void loadOpenTypeFunctions() -{ - HMODULE hModule = GetModuleHandle(L"usp10"); - if (hModule) { - gScriptItemizeOpenTypeFunc = reinterpret_cast<ScriptItemizeOpenTypeFunc>(GetProcAddress(hModule, "ScriptItemizeOpenType")); - gScriptShapeOpenTypeFunc = reinterpret_cast<ScriptShapeOpenTypeFunc>(GetProcAddress(hModule, "ScriptShapeOpenType")); - } - if (!gScriptItemizeOpenTypeFunc || !gScriptShapeOpenTypeFunc) { - gScriptItemizeOpenTypeFunc = 0; - gScriptShapeOpenTypeFunc = 0; - } - gOpenTypeFunctionsLoaded = true; -} - -enum { - FontStyleNormal = 0, - FontStyleBold = 1, - FontStyleItalic = 2, - FontStyleUnderlined = 4 -}; - -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); -} - - -// 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); -} - -// This memory DC will NOT be released but it's OK -// since we want to keep it for the whole life span of the process. -HDC UniscribeHelper::m_cachedDC = 0; - -static bool canUseGlyphIndex(const SCRIPT_ITEM& run) -{ - // On early version of Uniscribe, ScriptShape() sets run.a.fNoGlyphIndex - // to TRUE when it can't shape the run with glyph indexes. This could - // occur when we use CFF webfonts(See http://crbug.com/39017). - // We don't use the font in that case and try to use fallback fonts. - return !run.a.fNoGlyphIndex; -} - -UniscribeHelper::UniscribeHelper(const UChar* input, - int inputLength, - bool isRtl, - HFONT hfont, - SCRIPT_CACHE* scriptCache, - SCRIPT_FONTPROPERTIES* fontProperties, - WORD spaceGlyph) - : m_input(input) - , m_inputLength(inputLength) - , m_isRtl(isRtl) - , m_hfont(hfont) - , m_scriptCache(scriptCache) - , m_fontProperties(fontProperties) - , m_spaceGlyph(spaceGlyph) - , m_directionalOverride(false) - , m_inhibitLigate(false) - , m_letterSpacing(0) - , m_spaceWidth(0) - , m_wordSpacing(0) - , m_ascent(0) - , m_disableFontFallback(false) - -{ - m_logfont.lfFaceName[0] = 0; - if (!gOpenTypeFunctionsLoaded) - loadOpenTypeFunctions(); -} - -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. - int minKashida; - // Disable kashida justification based on - // http://blogs.msdn.com/b/michkap/archive/2010/08/31/10056140.aspx. - for (int i = 0; i < totalGlyphs; ++i) { - if (visualAttributes[i].uJustification == SCRIPT_JUSTIFY_ARABIC_KASHIDA) - visualAttributes[i].uJustification = SCRIPT_JUSTIFY_NONE; - } - minKashida = 0; - 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(GraphicsContext* graphicsContext, - const FontPlatformData& fontPlatformData, HDC dc, int x, int y, - const FloatRect& textRect, 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 preceding 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]; - - const int* advances = shaping.m_justify.size() ? - &shaping.m_justify[fromGlyph] - : &shaping.m_advance[fromGlyph]; - - // Fonts with different ascents can be used to render different - // runs. 'Across-runs' y-coordinate correction needs to be - // adjusted for each font. - bool textOutOk = false; - for (int executions = 0; executions < 2; ++executions) { - SkPoint origin; - origin.fX = curX + + innerOffset; - origin.fY = y + m_ascent; - paintSkiaText(graphicsContext, - fontPlatformData, - shaping.m_hfont, - glyphCount, - &shaping.m_glyphs[fromGlyph], - advances, - &shaping.m_offsets[fromGlyph], - origin, - textRect); - textOutOk = true; - - if (!textOutOk && 0 == executions) { - // If TextOut 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; - } - } - - 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(cUniscribeHelperStackRuns); - m_scriptTags.resize(cUniscribeHelperStackRuns); - - 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. - if (gScriptItemizeOpenTypeFunc) { - hr = gScriptItemizeOpenTypeFunc(m_input, m_inputLength, - static_cast<int>(m_runs.size()) - 1, - &inputControl, &inputState, - &m_runs[0], &m_scriptTags[0], - &numberOfItems); - - if (SUCCEEDED(hr)) { - // Pack consecutive runs, the script tag of which are - // SCRIPT_TAG_UNKNOWN, to reduce the number of runs. - for (int i = 0; i < numberOfItems; ++i) { - // Do not pack with whitespace characters at the head. - // Otherwise whole the run is rendered as a whitespace. - WCHAR ch = m_input[m_runs[i].iCharPos]; - if (m_scriptTags[i] == SCRIPT_TAG_UNKNOWN && !Font::treatAsSpace(ch) && !Font::treatAsZeroWidthSpace(ch)) { - int j = 1; - while (i + j < numberOfItems && m_scriptTags[i + j] == SCRIPT_TAG_UNKNOWN) - ++j; - if (--j) { - m_runs.remove(i + 1, j); - m_scriptTags.remove(i + 1, j); - numberOfItems -= j; - } - } - } - m_scriptTags.resize(numberOfItems); - } - } else { - 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); - m_scriptTags.resize(m_runs.size()); - } -} - -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) -{ - HWndDC dc(0); - HGDIOBJ oldFont = SelectObject(dc, hfont); - TEXTMETRIC tm; - BOOL gotMetrics = GetTextMetrics(dc, &tm); - SelectObject(dc, oldFont); - return gotMetrics ? tm.tmAscent : kUndefinedAscent; -} - -const WORD kUnsupportedGlyph = 0xffff; - -WORD getSpaceGlyph(HFONT hfont) -{ - HWndDC dc(0); - HGDIOBJ oldFont = SelectObject(dc, hfont); - WCHAR space = L' '; - WORD spaceGlyph = kUnsupportedGlyph; - GetGlyphIndices(dc, &space, 1, &spaceGlyph, GGI_MARK_NONEXISTING_GLYPHS); - SelectObject(dc, oldFont); - return spaceGlyph; -} - -struct ShaperFontData { - ShaperFontData() - : hfont(0) - , ascent(kUndefinedAscent) - , scriptCache(0) - , spaceGlyph(0) - { - } - - HFONT hfont; - int ascent; - mutable SCRIPT_CACHE scriptCache; - WORD spaceGlyph; -}; - -// 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, ShaperFontData> ShaperFontDataCache; - -// Derive a new HFONT by replacing lfFaceName of LOGFONT with |family|, -// calculate the ascent for the derived HFONT, and initialize SCRIPT_CACHE -// in ShaperFontData. -// |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 |ShaperFontData| is set to kUndefinedAscent. -// Be aware that this is not thread-safe. -// FIXME: Instead of having three out params, we'd better have one -// (|*ShaperFontData|), 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. -// Be aware that this is not thread-safe. -static bool getDerivedFontData(const UChar* family, int style, LOGFONT* logfont, - int* ascent, HFONT* hfont, SCRIPT_CACHE** scriptCache, WORD* spaceGlyph) -{ - ASSERT(logfont); - ASSERT(family); - ASSERT(*family); - - // It does not matter that we leak font data when we exit. - static ShaperFontDataCache* gFontDataCache = 0; - if (!gFontDataCache) - gFontDataCache = new ShaperFontDataCache(); - - // 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); - ShaperFontDataCache::iterator iter = gFontDataCache->find(fontKey); - ShaperFontData* derived; - if (iter == gFontDataCache->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) - ShaperFontDataCache::AddResult entry = gFontDataCache->add(fontKey, ShaperFontData()); - derived = &entry.iterator->value; - 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); - derived->spaceGlyph = getSpaceGlyph(derived->hfont); - } else { - derived = &iter->value; - // Last time, getAscent or getSpaceGlyph 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); - if (kUnsupportedGlyph == derived->spaceGlyph) - derived->spaceGlyph = getSpaceGlyph(derived->hfont); - } - *hfont = derived->hfont; - *ascent = derived->ascent; - *scriptCache = &(derived->scriptCache); - *spaceGlyph = derived->spaceGlyph; - return *ascent != kUndefinedAscent && *spaceGlyph != kUnsupportedGlyph; -} - -bool UniscribeHelper::shape(const UChar* input, - int itemLength, - int numGlyphs, - SCRIPT_ITEM& run, - OPENTYPE_TAG scriptTag, - Shaping& shaping) -{ - HFONT hfont = m_hfont; - SCRIPT_CACHE* scriptCache = m_scriptCache; - SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; - Vector<SCRIPT_CHARPROP, cUniscribeHelperStackChars> charProps; - Vector<SCRIPT_GLYPHPROP, cUniscribeHelperStackChars> glyphProps; - int ascent = m_ascent; - WORD spaceGlyph = m_spaceGlyph; - HRESULT hr; - // When used to fill up glyph pages for simple scripts in non-BMP, - // we don't want any font fallback in this class. The simple script - // font path can take care of font fallback. - bool lastFallbackTried = m_disableFontFallback; - 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); - charProps.resize(itemLength); - glyphProps.resize(numGlyphs); - run.a.fNoGlyphIndex = FALSE; - -#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 - // If our DC is already created, select the font in it so we can use it now. - // Otherwise, we'll create it as needed afterward... - if (m_cachedDC) - SelectObject(m_cachedDC, hfont); - - // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true - // here. Is that what we want? It will display control characters. - if (gScriptShapeOpenTypeFunc) { - TEXTRANGE_PROPERTIES* rangeProps = m_featureRecords.size() ? &m_rangeProperties : 0; - hr = gScriptShapeOpenTypeFunc(m_cachedDC, scriptCache, &run.a, - scriptTag, 0, &itemLength, - &rangeProps, rangeProps ? 1 : 0, - input, itemLength, numGlyphs, - &shaping.m_logs[0], &charProps[0], - &shaping.m_glyphs[0], &glyphProps[0], - &generatedGlyphs); - if (SUCCEEDED(hr)) { - // If we use ScriptShapeOpenType(), visual attributes - // information for each characters are stored in - // |glyphProps[i].sva|. - for (int i = 0; i < generatedGlyphs; ++i) - memcpy(&shaping.m_visualAttributes[i], &glyphProps[i].sva, sizeof(SCRIPT_VISATTR)); - } - } else { - hr = ScriptShape(m_cachedDC, scriptCache, input, itemLength, - numGlyphs, &run.a, - &shaping.m_glyphs[0], &shaping.m_logs[0], - &shaping.m_visualAttributes[0], &generatedGlyphs); - } - // We receive E_PENDING when we need to try again with a Drawing Context, - // but we don't want to retry again if we already tried with non-zero DC. - if (hr == E_PENDING && !m_cachedDC) { - EnsureCachedDCCreated(); - continue; - } - if (hr == E_OUTOFMEMORY) { - numGlyphs *= 2; - continue; - } - if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(shaping, run, fontProperties) && canUseGlyphIndex(run))) - break; - - // The current font can't render this run, try next font. - if (!m_disableFontFallback && - nextWinFontData(hfont, scriptCache, fontProperties, ascent, spaceGlyph)) { - // 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 = getFallbackFamilyForFirstNonCommonCharacter(input, itemLength, - FontDescription::StandardFamily); - bool fontOk = getDerivedFontData(family, m_style, &m_logfont, - &ascent, &hfont, &scriptCache, - &spaceGlyph); - - - 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, - &spaceGlyph); - 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; - shaping.m_spaceGlyph = spaceGlyph; - - // 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); - - // On failure, our logs don't mean anything, so zero those out. - if (!result) - shaping.m_logs.clear(); - - return result; -} - -void UniscribeHelper::EnsureCachedDCCreated() -{ - if (m_cachedDC) - return; - // Allocate a memory DC that is compatible with the Desktop DC since we don't have any window, - // and we don't want to use the Desktop DC directly since it can have nasty side effects - // as identified in Chrome Issue http://crbug.com/59315. - HWndDC screenDC(0); - m_cachedDC = ::CreateCompatibleDC(screenDC); - ASSERT(m_cachedDC); -} - -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 < cUniscribeHelperStackChars) { - // 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 = cUniscribeHelperStackChars; - } 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], m_scriptTags[i], shaping)) - continue; - - // At the moment, the only time m_disableFontFallback is set is - // when we look up glyph indices for non-BMP code ranges. So, - // we can skip the glyph placement. When that becomes not the case - // any more, we have to add a new flag to control glyph placement. - if (m_disableFontFallback) - continue; - - // Compute placements. Note that offsets is documented incorrectly - // and is actually an array. - EnsureCachedDCCreated(); - SelectObject(m_cachedDC, shaping.m_hfont); - shaping.m_prePadding = 0; - if (FAILED(ScriptPlace(m_cachedDC, 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))) { - // 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_scriptTags.clear(); - m_shapes.clear(); - m_screenOrder.clear(); - } - } - - 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]; - - // FIXME: This loop is not UTF-16-safe. Unicode 6.0 has a couple - // of complex script blocks in Plane 1. - for (int i = 0; i < shaping.charLength(); i++) { - UChar c = m_input[m_runs[run].iCharPos + i]; - bool treatAsSpace = Font::treatAsSpace(c); - if (!treatAsSpace && !Font::treatAsZeroWidthSpaceInComplexScript(c)) - continue; - - int glyphIndex = shaping.m_logs[i]; - int currentAdvance = shaping.m_advance[glyphIndex]; - - shaping.m_glyphs[glyphIndex] = shaping.m_spaceGlyph; - - if (treatAsSpace) { - // currentAdvance does not include additional letter-spacing, - // but m_spaceWidth does. Here we find out how off we are from - // the correct width (spaceWidthWithoutLetterSpacing) and - // 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; - continue; - } - - // For characters treated as zero-width space in complex - // scripts, set the advance width to zero, adjust - // |abcB| of the current run accordingly and set - // the glyph to m_spaceGlyph (invisible). - shaping.m_advance[glyphIndex] = 0; - shaping.m_abc.abcB -= currentAdvance; - shaping.m_offsets[glyphIndex].du = 0; - shaping.m_offsets[glyphIndex].dv = 0; - } - } -} - -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 (!Font::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; -} - -// 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. -// However, we should not subject zero-width characters to this test. - -bool UniscribeHelper::containsMissingGlyphs(const Shaping& shaping, - const SCRIPT_ITEM& run, - const SCRIPT_FONTPROPERTIES* properties) const -{ - for (int i = 0; i < shaping.charLength(); i++) { - UChar c = m_input[run.iCharPos + i]; - // Skip zero-width space characters because they're not considered to - // be missing in a font. - if (Font::treatAsZeroWidthSpaceInComplexScript(c)) - continue; - int glyphIndex = shaping.m_logs[i]; - WORD glyph = shaping.m_glyphs[glyphIndex]; - // Note on the thrid condition: Windows Vista sometimes returns glyphs - // equal to wgBlank (instead of wgDefault), with fZeroWidth set. Treat - // such cases as having missing glyphs if the corresponding character - // is not a zero width whitespace. - if (glyph == properties->wgDefault - || (glyph == properties->wgInvalid && glyph != properties->wgBlank) - || (glyph == properties->wgBlank && shaping.m_visualAttributes[glyphIndex].fZeroWidth && !Font::treatAsZeroWidthSpace(c))) - return true; - } - return false; -} - -static OPENTYPE_TAG convertFeatureTag(const String& tag) -{ - return ((tag[0] & 0xFF) | ((tag[1] & 0xFF) << 8) | ((tag[2] & 0xFF) << 16) | ((tag[3] & 0xFF) << 24)); -} - -void UniscribeHelper::setRangeProperties(const FontFeatureSettings* featureSettings) -{ - if (!featureSettings || !featureSettings->size()) { - m_featureRecords.resize(0); - return; - } - - m_featureRecords.resize(featureSettings->size()); - for (unsigned i = 0; i < featureSettings->size(); ++i) { - m_featureRecords[i].lParameter = featureSettings->at(i).value(); - m_featureRecords[i].tagFeature = convertFeatureTag(featureSettings->at(i).tag()); - } - m_rangeProperties.potfRecords = &m_featureRecords[0]; - m_rangeProperties.cotfRecords = m_featureRecords.size(); -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelper.h b/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelper.h deleted file mode 100644 index 8a724c6d608..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelper.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * 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 { - -class FloatRect; -class FontFeatureSettings; -class FontPlatformData; -class GraphicsContext; - -const unsigned cUniscribeHelperStackRuns = 8; -const unsigned cUniscribeHelperStackChars = 32; -const unsigned cUniscribeHelperFeatures = 4; - -// 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*, - WORD); - - 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; - } - - // When set to true, this class is used only to look up glyph - // indices for a range of Unicode characters without glyph placement. - // By default, it's false. This should be set to true when this - // class is used for glyph index look-up for non-BMP characters - // in GlyphPageNodeChromiumWin.cpp. - void setDisableFontFallback(bool disableFontFallback) - { - m_disableFontFallback = true; - } - - // Set TEXTRANGE_PROPERTIES structure which contains - // OpenType feature records generated from FontFeatureSettings. - void setRangeProperties(const FontFeatureSettings*); - - // 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(GraphicsContext*, const FontPlatformData&, HDC, - int x, int y, const FloatRect& textRect, - 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) {} - - // Let our subclasses provide the input lazily in case they can't compute - // it in their constructors. Once we have input, however, we don't let - // our subclasses change it. - void setInput(const UChar* input) { ASSERT(!m_input); m_input = input; } - -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_spaceGlyph(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, cUniscribeHelperStackChars> 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, cUniscribeHelperStackChars> m_logs; - - // Flags and such for each glyph. - Vector<SCRIPT_VISATTR, cUniscribeHelperStackChars> m_visualAttributes; - - // Horizontal advances for each glyph listed above, this is basically - // how wide each glyph is. - Vector<int, cUniscribeHelperStackChars> 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, cUniscribeHelperStackChars> 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, cUniscribeHelperStackChars> 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; - - WORD m_spaceGlyph; - }; - - // 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; - - bool containsMissingGlyphs(const Shaping&, - const SCRIPT_ITEM&, - const SCRIPT_FONTPROPERTIES*) 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, OPENTYPE_TAG, 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&, WORD&) - { - 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() {} - - // If m_cachedDC is 0, creates one that is compatible with the screen DC. - void EnsureCachedDCCreated(); - - // 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; - // We cache the DC to use with ScriptShape/ScriptPlace. - static HDC m_cachedDC; - SCRIPT_CACHE* m_scriptCache; - SCRIPT_FONTPROPERTIES* m_fontProperties; - int m_ascent; - LOGFONT m_logfont; - int m_style; - WORD m_spaceGlyph; - - // Options, see the getters/setters above. - bool m_directionalOverride; - bool m_inhibitLigate; - int m_letterSpacing; - int m_spaceWidth; - int m_wordSpacing; - bool m_disableFontFallback; - - // 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, cUniscribeHelperStackRuns> m_runs; - - Vector<Shaping, cUniscribeHelperStackRuns> m_shapes; - Vector<OPENTYPE_TAG, cUniscribeHelperStackRuns> m_scriptTags; - - // 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, cUniscribeHelperStackRuns> m_screenOrder; - - // This contains Uniscribe's OpenType feature settings. This structure - // is filled by using WebKit's |FontFeatureSettings|. - TEXTRANGE_PROPERTIES m_rangeProperties; - Vector<OPENTYPE_FEATURE_RECORD, cUniscribeHelperFeatures> m_featureRecords; -}; - -} // namespace WebCore - -#endif // UniscribeHelper_h diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelperTextRun.cpp b/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelperTextRun.cpp deleted file mode 100644 index 9ae1680992d..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelperTextRun.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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 "platform/fonts/win/UniscribeHelperTextRun.h" - -#include "platform/fonts/Font.h" -#include "platform/fonts/SimpleFontData.h" -#include "platform/fonts/win/FontPlatformDataWin.h" -#include "platform/text/TextRun.h" - -namespace WebCore { - -UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run, - const Font& font) - : UniscribeHelper(0, run.length(), run.rtl(), - font.primaryFont()->platformData().hfont(), - font.primaryFont()->platformData().scriptCache(), - font.primaryFont()->platformData().scriptFontProperties(), - font.primaryFont()->spaceGlyph()) - , m_font(&font) - , m_fontIndex(0) -{ - if (run.is8Bit()) { - m_stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length()); - setInput(m_stringFor8BitRun.characters16()); - } else { - setInput(run.characters16()); - } - - setDirectionalOverride(run.directionalOverride()); - setLetterSpacing(font.letterSpacing()); - setSpaceWidth(font.spaceWidth()); - setWordSpacing(font.wordSpacing()); - setAscent(font.fontMetrics().ascent()); - setRangeProperties(font.fontDescription().featureSettings()); - - init(); - - // Expansion is the amount to add to make justification happen. This - // should be done after Init() so all the runs are already measured. - if (run.expansion() > 0) - justify(run.expansion()); -} - -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, 0) - , 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. - FontPlatformData::ensureFontLoaded(font); -} - -bool UniscribeHelperTextRun::nextWinFontData( - HFONT& hfont, - SCRIPT_CACHE*& scriptCache, - SCRIPT_FONTPROPERTIES*& fontProperties, - int& ascent, - WORD& spaceGlyph) -{ - // 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 - // blink::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->fontMetrics().ascent()); - m_spaceGlyphs.append(simpleFontData->spaceGlyph()); - } - - hfont = m_hfonts[m_fontIndex - 1]; - scriptCache = m_scriptCaches[m_fontIndex - 1]; - fontProperties = m_fontProperties[m_fontIndex - 1]; - ascent = m_ascents[m_fontIndex - 1]; - spaceGlyph = m_spaceGlyphs[m_fontIndex - 1]; - return true; -} - -void UniscribeHelperTextRun::resetFontIndex() -{ - m_fontIndex = 0; -} - -} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelperTextRun.h b/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelperTextRun.h deleted file mode 100644 index f033f3431c7..00000000000 --- a/chromium/third_party/WebKit/Source/platform/fonts/win/UniscribeHelperTextRun.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 "platform/fonts/win/UniscribeHelper.h" -#include "wtf/text/WTFString.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, WORD& spaceGlyph); - virtual void resetFontIndex(); - - // Reference to blink::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; - - // When we have an 8 bit TestRun, we store the buffer of upconverted characters - // in this string. - String m_stringFor8BitRun; - - // 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; - Vector<WORD> m_spaceGlyphs; - - // Index of the fallback font we're currently using for NextWinFontData. - int m_fontIndex; -}; - -} // namespace WebCore - -#endif // UniscribeHelperTextRun_h |