diff options
author | Ben Murdoch <benm@google.com> | 2009-08-11 17:01:47 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2009-08-11 18:21:02 +0100 |
commit | 0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5 (patch) | |
tree | 2943df35f62d885c89d01063cc528dd73b480fea /WebCore/platform/graphics/wince | |
parent | 7e7a70bfa49a1122b2597a1e6367d89eb4035eca (diff) | |
download | external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.zip external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.gz external_webkit-0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5.tar.bz2 |
Merge in WebKit r47029.
Diffstat (limited to 'WebCore/platform/graphics/wince')
-rw-r--r-- | WebCore/platform/graphics/wince/FontCacheWince.cpp | 352 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/FontCustomPlatformData.cpp | 79 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/FontCustomPlatformData.h | 55 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/FontPlatformData.cpp | 532 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/FontPlatformData.h | 90 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/FontWince.cpp | 333 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp | 79 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/GraphicsContextWince.cpp | 1930 | ||||
-rw-r--r-- | WebCore/platform/graphics/wince/SimpleFontDataWince.cpp | 161 |
9 files changed, 3611 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/wince/FontCacheWince.cpp b/WebCore/platform/graphics/wince/FontCacheWince.cpp new file mode 100644 index 0000000..f67f1b4 --- /dev/null +++ b/WebCore/platform/graphics/wince/FontCacheWince.cpp @@ -0,0 +1,352 @@ +/* +* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. +* Copyright (C) 2007-2009 Torch Mobile, Inc. +* +* 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 "FontCache.h" + +#include "Font.h" +#include "FontData.h" +#include "SimpleFontData.h" +#include "UnicodeRange.h" +#include "wtf/OwnPtr.h" + +#include <windows.h> +#include <mlang.h> + +namespace WebCore { + +extern HDC g_screenDC; + +static IMultiLanguage *multiLanguage = 0; + +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) +static IMLangFontLink2* langFontLink = 0; +#else +static IMLangFontLink* langFontLink = 0; +#endif + +IMultiLanguage* getMultiLanguageInterface() +{ + if (!multiLanguage) + CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&multiLanguage); + + return multiLanguage; +} + +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) +IMLangFontLink2* FontCache::getFontLinkInterface() +#else +IMLangFontLink* FontCache::getFontLinkInterface() +#endif +{ + if (!langFontLink) { + if (IMultiLanguage* mli = getMultiLanguageInterface()) + mli->QueryInterface(&langFontLink); + } + + return langFontLink; +} + +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) +static bool currentFontContainsCharacter(IMLangFontLink2* langFontLink, HDC hdc, UChar character) +{ + UINT unicodeRanges; + if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, 0)) + return false; + + static Vector<UNICODERANGE, 64> glyphsetBuffer; + glyphsetBuffer.resize(unicodeRanges); + + if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, glyphsetBuffer.data())) + return false; + + // FIXME: Change this to a binary search. (Yong Li: That's easy. But, is it guaranteed that the ranges are sorted?) + for (Vector<UNICODERANGE, 64>::const_iterator i = glyphsetBuffer.begin(); i != glyphsetBuffer.end(); ++i) { + if (i->wcTo >= character) + return i->wcFrom <= character; + } + + return false; +} +#else +static bool currentFontContainsCharacter(IMLangFontLink* langFontLink, HDC hdc, HFONT hfont, UChar character, const wchar_t* faceName) +{ + DWORD fontCodePages = 0, charCodePages = 0; + HRESULT result = langFontLink->GetFontCodePages(hdc, hfont, &fontCodePages); + if (result != S_OK) + return false; + result = langFontLink->GetCharCodePages(character, &charCodePages); + if (result != S_OK) + return false; + + fontCodePages |= FontPlatformData::getKnownFontCodePages(faceName); + if (fontCodePages & charCodePages) + return true; + + return false; +} +#endif + +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) +static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0) +{ + HFONT mlangFont; + if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &mlangFont))) + return mlangFont; + + return 0; +} +#else +static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask) +{ + HFONT mlangFont; + LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont); + + return result == S_OK ? mlangFont : 0; +} +#endif + +static const Vector<DWORD, 4>& getCJKCodePageMasks() +{ + // The default order in which we look for a font for a CJK character. If the user's default code page is + // one of these, we will use it first. + static const UINT CJKCodePages[] = { + 932, /* Japanese */ + 936, /* Simplified Chinese */ + 950, /* Traditional Chinese */ + 949 /* Korean */ + }; + + static Vector<DWORD, 4> codePageMasks; + static bool initialized; + if (!initialized) { + initialized = true; +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface(); +#else + IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface(); +#endif + if (!langFontLink) + return codePageMasks; + + UINT defaultCodePage; + DWORD defaultCodePageMask = 0; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage))) + langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask); + + if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3]) + codePageMasks.append(defaultCodePageMask); + for (unsigned i = 0; i < 4; ++i) { + if (defaultCodePage != CJKCodePages[i]) { + DWORD codePageMask; + langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask); + codePageMasks.append(codePageMask); + } + } + } + return codePageMasks; +} + + +struct TraitsInFamilyProcData { + TraitsInFamilyProcData(const AtomicString& familyName) + : m_familyName(familyName) + { + } + + const AtomicString& m_familyName; + HashSet<unsigned> m_traitsMasks; +}; + +static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) +{ + TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); + + unsigned traitsMask = 0; + traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; + traitsMask |= FontVariantNormalMask; + LONG weight = FontPlatformData::adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName); + traitsMask |= weight == FW_THIN ? FontWeight100Mask : + weight == FW_EXTRALIGHT ? FontWeight200Mask : + weight == FW_LIGHT ? FontWeight300Mask : + weight == FW_NORMAL ? FontWeight400Mask : + weight == FW_MEDIUM ? FontWeight500Mask : + weight == FW_SEMIBOLD ? FontWeight600Mask : + weight == FW_BOLD ? FontWeight700Mask : + weight == FW_EXTRABOLD ? FontWeight800Mask : + FontWeight900Mask; + procData->m_traitsMasks.add(traitsMask); + return 1; +} + +void FontCache::platformInit() +{ +} + +void FontCache::comInitialize() +{ +} + +void FontCache::comUninitialize() +{ + if (langFontLink) { + langFontLink->Release(); + langFontLink = 0; + } + if (multiLanguage) { + multiLanguage->Release(); + multiLanguage = 0; + } +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + String familyName; + WCHAR name[LF_FACESIZE]; + + UChar character = characters[0]; + const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData(); + unsigned unicodeRange = findCharUnicodeRange(character); + +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + if (IMLangFontLink2* langFontLink = getFontLinkInterface()) { +#else + if (IMLangFontLink* langFontLink = getFontLinkInterface()) { +#endif + HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT); + HFONT hfont = 0; + DWORD codePages = 0; + UINT codePage = 0; + // Try MLang font linking first. + langFontLink->GetCharCodePages(character, &codePages); + if (codePages && unicodeRange == cRangeSetCJK) { + // The CJK character may belong to multiple code pages. We want to + // do font linking against a single one of them, preferring the default + // code page for the user's locale. + const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks(); + unsigned numCodePages = CJKCodePageMasks.size(); + for (unsigned i = 0; i < numCodePages; ++i) { +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + hfont = createMLangFont(langFontLink, g_screenDC, CJKCodePageMasks[i]); +#else + hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]); +#endif + if (!hfont) + continue; + + SelectObject(g_screenDC, hfont); + GetTextFace(g_screenDC, LF_FACESIZE, name); + + if (hfont && !(codePages & CJKCodePageMasks[i])) { + // We asked about a code page that is not one of the code pages + // returned by MLang, so the font might not contain the character. +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + if (!currentFontContainsCharacter(langFontLink, g_screenDC, character)) { +#else + if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) { +#endif + SelectObject(g_screenDC, oldFont); + langFontLink->ReleaseFont(hfont); + hfont = 0; + continue; + } + } + break; + } + } else { +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + hfont = createMLangFont(langFontLink, g_screenDC, codePages, character); +#else + hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages); +#endif + SelectObject(g_screenDC, hfont); + GetTextFace(g_screenDC, LF_FACESIZE, name); + } + SelectObject(g_screenDC, oldFont); + + if (hfont) { + familyName = name; + langFontLink->ReleaseFont(hfont); + } else + FontPlatformData::mapKnownFont(codePages, familyName); + } + + if (familyName.isEmpty()) + familyName = FontPlatformData::defaultFontFamily(); + + if (!familyName.isEmpty()) { + // FIXME: temporary workaround for Thai font problem + FontDescription fontDescription(font.fontDescription()); + if (unicodeRange == cRangeThai && fontDescription.weight() > FontWeightNormal) + fontDescription.setWeight(FontWeightNormal); + + FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName); + if (result && result->hash() != origFont.hash()) { + if (SimpleFontData* fontData = getCachedFontData(result)) + return fontData; + } + } + + return 0; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDesc) +{ + // 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. + return getCachedFontPlatformData(fontDesc, FontPlatformData::defaultFontFamily()); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + FontPlatformData* result = new FontPlatformData(fontDescription, family); + return result; +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +{ + LOGFONT logFont; + logFont.lfCharSet = DEFAULT_CHARSET; + unsigned familyLength = std::min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1)); + memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); + logFont.lfFaceName[familyLength] = 0; + logFont.lfPitchAndFamily = 0; + + TraitsInFamilyProcData procData(familyName); + EnumFontFamiliesEx(g_screenDC, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); + copyToVector(procData.m_traitsMasks, traitsMasks); +} + +} + diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp new file mode 100644 index 0000000..7c6853c --- /dev/null +++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "Base64.h" +#include "CachedFont.h" +#include "FontPlatformData.h" +#include <wtf/RandomNumber.h> + +namespace WebCore { + +static CustomFontCache* g_customFontCache = 0; + +bool renameFont(SharedBuffer* fontData, const String& fontName); + +FontCustomPlatformData::~FontCustomPlatformData() +{ + if (g_customFontCache && !m_name.isEmpty()) + g_customFontCache->unregisterFont(m_name); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode renderingMode) +{ + FontDescription fontDesc; + fontDesc.setComputedSize(size); + fontDesc.setSpecifiedSize(size); + fontDesc.setItalic(italic); + fontDesc.setWeight(bold ? FontWeightBold : FontWeightNormal); + return FontPlatformData(fontDesc, m_name, false); +} + +// Creates a unique and unpredictable font name, in order to avoid collisions and to +// not allow access from CSS. +static String createUniqueFontName() +{ + Vector<char> fontUuid(sizeof(GUID)); + + unsigned int* ptr = reinterpret_cast<unsigned int*>(fontUuid.data()); + for (int i = 0; i < sizeof(GUID) / sizeof(int) ; ++i) + *(ptr + i) = static_cast<unsigned int>(WTF::randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)); + + Vector<char> fontNameVector; + base64Encode(fontUuid, fontNameVector); + ASSERT(fontNameVector.size() < LF_FACESIZE); + String fontName(fontNameVector.data(), fontNameVector.size()); + return fontName.replace('/', '_'); +} + +FontCustomPlatformData* createFontCustomPlatformData(CachedFont* cachedFont) +{ + if (g_customFontCache && cachedFont->CachedResource::data()) { + String fontName = createUniqueFontName(); + if (renameFont(cachedFont->CachedResource::data(), fontName) && g_customFontCache->registerFont(fontName, cachedFont)) + return new FontCustomPlatformData(fontName); + } + return 0; +} + +} diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/WebCore/platform/graphics/wince/FontCustomPlatformData.h new file mode 100644 index 0000000..b1f64a0 --- /dev/null +++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include "FontRenderingMode.h" +#include "PlatformString.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + + class FontPlatformData; + class CachedFont; + + class CustomFontCache { + public: + virtual bool registerFont(const String& fontName, CachedFont*) = 0; + virtual void unregisterFont(const String& fontName) = 0; + }; + + struct FontCustomPlatformData : Noncopyable { + FontCustomPlatformData(const String& name) + : m_name(name) + { + } + + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); + String m_name; + }; + + FontCustomPlatformData* createFontCustomPlatformData(CachedFont*); + +} + +#endif diff --git a/WebCore/platform/graphics/wince/FontPlatformData.cpp b/WebCore/platform/graphics/wince/FontPlatformData.cpp new file mode 100644 index 0000000..f0db2ff --- /dev/null +++ b/WebCore/platform/graphics/wince/FontPlatformData.cpp @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2007-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 "FontPlatformData.h" + +#include "Font.h" +#include "FontCache.h" +#include "FontData.h" +#include "PlatformString.h" +#include "SimpleFontData.h" +#include "UnicodeRange.h" +#include "wtf/OwnPtr.h" + +#include <windows.h> +#include <mlang.h> + +namespace WebCore { + +extern HDC g_screenDC; + +static wchar_t songTiStr[] = { 0x5b8b, 0x4f53, 0 }; +static wchar_t heiTiStr[] = { 0x9ed1, 0x4f53, 0 }; + +class FontFamilyCodePageInfo { +public: + FontFamilyCodePageInfo() + : m_codePage(0), m_codePages(0) + { + } + FontFamilyCodePageInfo(const wchar_t* family, UINT codePage) + : m_family(family), m_codePage(codePage), m_codePages(0) + { + } + DWORD codePages() const + { + if (!m_codePages) { +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) + langFontLink->CodePageToCodePages(m_codePage, &m_codePages); +#else + if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) + langFontLink->CodePageToCodePages(m_codePage, &m_codePages); +#endif + } + return m_codePages; + } + + String m_family; + UINT m_codePage; +private: + mutable DWORD m_codePages; +}; + +class FontFamilyChecker { +public: + FontFamilyChecker(const wchar_t* family) + : m_exists(false) + { + EnumFontFamilies(g_screenDC, family, enumFontFamProc, (LPARAM)this); + } + bool isSupported() const { return m_exists; } +private: + bool m_exists; + static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam); +}; + +class ValidFontFamilyFinder { +public: + ValidFontFamilyFinder() + { + EnumFontFamilies(g_screenDC, 0, enumFontFamProc, (LPARAM)this); + } + const String& family() const { return m_family; } +private: + String m_family; + static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam); +}; + +class FixedSizeFontData: public RefCounted<FixedSizeFontData> { +public: + LOGFONT m_font; + OwnPtr<HFONT> m_hfont; + TEXTMETRIC m_metrics; + DWORD m_codePages; + unsigned m_weight; + bool m_italic; + + static PassRefPtr<FixedSizeFontData> create(const AtomicString& family, unsigned weight, bool italic); +private: + FixedSizeFontData() + : m_codePages(0) + , m_weight(0) + , m_italic(false) + { + memset(&m_font, 0, sizeof(m_font)); + memset(&m_metrics, 0, sizeof(m_metrics)); + } +}; + +struct FixedSizeFontDataKey { + FixedSizeFontDataKey(const AtomicString& family = AtomicString(), unsigned weight = 0, bool italic = false) + : m_family(family) + , m_weight(weight) + , m_italic(italic) + { + } + + FixedSizeFontDataKey(WTF::HashTableDeletedValueType) : m_weight(-2) { } + bool isHashTableDeletedValue() const { return m_weight == -2; } + + bool operator==(const FixedSizeFontDataKey& other) const + { + return equalIgnoringCase(m_family, other.m_family) + && m_weight == other.m_weight + && m_italic == other.m_italic; + } + + AtomicString m_family; + unsigned m_weight; + bool m_italic; +}; + +struct FixedSizeFontDataKeyHash { + static unsigned hash(const FixedSizeFontDataKey& font) + { + unsigned hashCodes[] = { + CaseFoldingHash::hash(font.m_family), + font.m_weight, + // static_cast<unsigned>(font.m_italic); + }; + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + } + + static bool equal(const FixedSizeFontDataKey& a, const FixedSizeFontDataKey& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +struct FixedSizeFontDataKeyTraits : WTF::GenericHashTraits<FixedSizeFontDataKey> { + static const bool emptyValueIsZero = true; + static const FixedSizeFontDataKey& emptyValue() + { + DEFINE_STATIC_LOCAL(FixedSizeFontDataKey, key, (nullAtom)); + return key; + } + static void constructDeletedValue(FixedSizeFontDataKey& slot) + { + new (&slot) FixedSizeFontDataKey(WTF::HashTableDeletedValue); + } + static bool isDeletedValue(const FixedSizeFontDataKey& value) + { + return value.isHashTableDeletedValue(); + } +}; + +int CALLBACK FontFamilyChecker::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam) +{ + ((FontFamilyChecker*)lParam)->m_exists = true; + return 0; +} + +int CALLBACK ValidFontFamilyFinder::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam) +{ + if (lpelf->lfCharSet != SYMBOL_CHARSET) { + ((ValidFontFamilyFinder*)lParam)->m_family = String(lpelf->lfFaceName); + return 0; + } + return 1; +} + +typedef Vector<FontFamilyCodePageInfo> KnownFonts; +static KnownFonts& knownFonts() +{ + static KnownFonts fonts; + static bool firstTime = true; + if (firstTime) { + firstTime = false; + if (FontPlatformData::isSongTiSupported()) + fonts.append(FontFamilyCodePageInfo(songTiStr, 936)); + } + return fonts; +} + +static String getDefaultFontFamily() +{ + if (FontFamilyChecker(L"Tahoma").isSupported()) + return String(L"Tahoma"); + + bool good = false; + String family; + HKEY key; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\GDI\\SysFnt", 0, 0, &key) == ERROR_SUCCESS) { + DWORD maxlen, type; + if (RegQueryValueEx(key, L"Nm", 0, &type, 0, &maxlen) == ERROR_SUCCESS && type == REG_SZ) { + ++maxlen; + if (wchar_t* buffer = new wchar_t[maxlen]) { + if (RegQueryValueEx(key, L"Nm", 0, &type, (LPBYTE)buffer, &maxlen) == ERROR_SUCCESS) { + family = String(buffer, maxlen); + good = true; + } + delete[] buffer; + } + } + RegCloseKey(key); + } + if (good) + return family; + + return ValidFontFamilyFinder().family(); +} + +typedef HashMap<FixedSizeFontDataKey, RefPtr<FixedSizeFontData>, FixedSizeFontDataKeyHash, FixedSizeFontDataKeyTraits> FixedSizeFontCache; +FixedSizeFontCache g_fixedSizeFontCache; + +PassRefPtr<FixedSizeFontData> FixedSizeFontData::create(const AtomicString& family, unsigned weight, bool italic) +{ + FixedSizeFontData* fontData = new FixedSizeFontData(); + + fontData->m_weight = weight; + fontData->m_italic = italic; + + LOGFONT& winFont = fontData->m_font; + // The size here looks unusual. The negative number is intentional. + winFont.lfHeight = -72; + winFont.lfWidth = 0; + winFont.lfEscapement = 0; + winFont.lfOrientation = 0; + winFont.lfUnderline = false; + winFont.lfStrikeOut = false; + winFont.lfCharSet = DEFAULT_CHARSET; + winFont.lfOutPrecision = OUT_DEFAULT_PRECIS; + winFont.lfQuality = CLEARTYPE_QUALITY; //DEFAULT_QUALITY; + winFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + winFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + winFont.lfItalic = italic; + winFont.lfWeight = FontPlatformData::adjustedGDIFontWeight(weight, family); + + int len = std::min(family.length(), (unsigned int)LF_FACESIZE - 1); + wmemcpy(winFont.lfFaceName, family.characters(), len); + winFont.lfFaceName[len] = L'\0'; + + fontData->m_hfont.set(CreateFontIndirect(&winFont)); + + HGDIOBJ oldFont = SelectObject(g_screenDC, fontData->m_hfont.get()); + + GetTextMetrics(g_screenDC, &fontData->m_metrics); + +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) { +#else + if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) { +#endif + langFontLink->GetFontCodePages(g_screenDC, fontData->m_hfont.get(), &fontData->m_codePages); + fontData->m_codePages |= FontPlatformData::getKnownFontCodePages(winFont.lfFaceName); + } + + SelectObject(g_screenDC, oldFont); + + return adoptRef(fontData); +} + +static PassRefPtr<FixedSizeFontData> createFixedSizeFontData(const AtomicString& family, unsigned weight, bool italic) +{ + FixedSizeFontDataKey key(family, weight, italic); + pair<FixedSizeFontCache::iterator, bool> result = g_fixedSizeFontCache.add(key, RefPtr<FixedSizeFontData>()); + if (result.second) + result.first->second = FixedSizeFontData::create(family, weight, italic); + + return result.first->second; +} + +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]; +} + +class FontPlatformPrivateData { +public: + int m_reference; + RefPtr<FixedSizeFontData> m_rootFontData; + AtomicString m_family; + FontDescription m_fontDescription; + OwnPtr<HFONT> m_hfontScaled; + int m_size; + long m_fontScaledWidth; + long m_fontScaledHeight; + bool m_disabled; + FontPlatformPrivateData(int size, unsigned weight) + : m_reference(1) + , m_family(FontPlatformData::defaultFontFamily()) + , m_size(size) + , m_fontScaledWidth(0) + , m_fontScaledHeight(0) + , m_disabled(false) + { + m_rootFontData = createFixedSizeFontData(m_family, weight, false); + } + FontPlatformPrivateData(const FontDescription& fontDescription, const AtomicString& family) + : m_reference(1) + , m_size(fontDescription.computedPixelSize()) + , m_fontDescription(fontDescription) + , m_family(family) + , m_fontScaledWidth(0) + , m_fontScaledHeight(0) + , m_disabled(!fontDescription.specifiedSize()) + { + m_rootFontData = FixedSizeFontData::create(family, toGDIFontWeight(fontDescription.weight()), fontDescription.italic()); + } +}; + +FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& desiredFamily, bool useDefaultFontIfNotPresent) +{ + String family(desiredFamily); + if (!equalIgnoringCase(family, defaultFontFamily()) && !FontFamilyChecker(family.charactersWithNullTermination()).isSupported()) { + if (equalIgnoringCase(family, String(heiTiStr)) && isSongTiSupported()) + family = String(songTiStr); + else if (useDefaultFontIfNotPresent) + family = defaultFontFamily(); + } + + m_private = new FontPlatformPrivateData(fontDescription, family); +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) +{ + if (!size) + m_private = 0; + else + m_private = new FontPlatformPrivateData((int)(size + 0.5), bold ? FW_BOLD : FW_NORMAL); +} + +FontPlatformData::~FontPlatformData() +{ + if (isValid() && !--m_private->m_reference) { + if (m_private->m_rootFontData->refCount() == 2) { + FixedSizeFontDataKey key(m_private->m_family, m_private->m_rootFontData->m_weight, m_private->m_rootFontData->m_italic); + g_fixedSizeFontCache.remove(key); + } + delete m_private; + } +} + +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& o) +{ + if (isValid() && !--m_private->m_reference) + delete m_private; + + if (m_private = o.m_private) + ++m_private->m_reference; + + return *this; +} + +HFONT FontPlatformData::hfont() const +{ + if (!isValid()) + return 0; + + if (m_private->m_disabled) + return 0; + + if (!m_private->m_rootFontData->m_hfont) + m_private->m_rootFontData->m_hfont.set(CreateFontIndirect(&m_private->m_rootFontData->m_font)); + + return m_private->m_rootFontData->m_hfont.get(); +} + +HFONT FontPlatformData::getScaledFontHandle(int height, int width) const +{ + if (!isValid() || m_private->m_disabled) + return 0; + + if (!m_private->m_hfontScaled || m_private->m_fontScaledHeight != height || m_private->m_fontScaledWidth != width) { + m_private->m_fontScaledHeight = height; + m_private->m_fontScaledWidth = width; + LOGFONT font = m_private->m_rootFontData->m_font; + font.lfHeight = -height; + font.lfWidth = width; + m_private->m_hfontScaled.set(CreateFontIndirect(&font)); + } + + return m_private->m_hfontScaled.get(); +} + +bool FontPlatformData::discardFontHandle() +{ + if (!isValid()) + return false; + + if (m_private->m_rootFontData->m_hfont) { + m_private->m_rootFontData->m_hfont.set(0); + return true; + } + + if (m_private->m_hfontScaled) { + m_private->m_hfontScaled.set(0); + return true; + } + return false; +} + +const TEXTMETRIC& FontPlatformData::metrics() const +{ + return m_private->m_rootFontData->m_metrics; +} + +bool FontPlatformData::isSystemFont() const +{ + return false; +} + +int FontPlatformData::size() const +{ + return m_private->m_size; +} + +const FontDescription& FontPlatformData::fontDescription() const +{ + return m_private->m_fontDescription; +} + +const AtomicString& FontPlatformData::family() const +{ + return m_private->m_family; +} + +const LOGFONT& FontPlatformData::logFont() const +{ + return m_private->m_rootFontData->m_font; +} + +int FontPlatformData::averageCharWidth() const +{ + return (m_private->m_rootFontData->m_metrics.tmAveCharWidth * size() + 36) / 72; +} + +bool FontPlatformData::isDisabled() const +{ + return !isValid() || m_private->m_disabled; +} + +DWORD FontPlatformData::codePages() const +{ + return m_private->m_rootFontData->m_codePages; +} + +bool FontPlatformData::isSongTiSupported() +{ + static bool exists = FontFamilyChecker(songTiStr).isSupported(); + return exists; +} + +bool FontPlatformData::mapKnownFont(DWORD codePages, String& family) +{ + KnownFonts& fonts = knownFonts(); + for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) { + if (i->codePages() & codePages) { + family = i->m_family; + return true; + } + } + return false; +} + +DWORD FontPlatformData::getKnownFontCodePages(const wchar_t* family) +{ + KnownFonts& fonts = knownFonts(); + for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) { + if (equalIgnoringCase(i->m_family, String(family))) + return i->codePages(); + } + return 0; +} + +const String& FontPlatformData::defaultFontFamily() +{ + static String family(getDefaultFontFamily()); + return family; +} + +LONG FontPlatformData::adjustedGDIFontWeight(LONG gdiFontWeight, const String& family) +{ + static AtomicString lucidaStr("Lucida Grande"); + if (equalIgnoringCase(family, lucidaStr)) { + if (gdiFontWeight == FW_NORMAL) + return FW_MEDIUM; + if (gdiFontWeight == FW_BOLD) + return FW_SEMIBOLD; + } + return gdiFontWeight; +} + +#ifndef NDEBUG +String FontPlatformData::description() const +{ + return String(); +} +#endif + +} diff --git a/WebCore/platform/graphics/wince/FontPlatformData.h b/WebCore/platform/graphics/wince/FontPlatformData.h new file mode 100644 index 0000000..77803d3 --- /dev/null +++ b/WebCore/platform/graphics/wince/FontPlatformData.h @@ -0,0 +1,90 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006, 2007 Apple Inc. + * Copyright (C) 2007-2008 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. + * + */ + +#ifndef FontPlatformDataWince_H +#define FontPlatformDataWince_H + +#include "FontDescription.h" +#include "StringImpl.h" +#include <wtf/Noncopyable.h> + +typedef struct tagTEXTMETRICW TEXTMETRIC; +typedef struct tagLOGFONTW LOGFONT; + +namespace WebCore { + + class FontPlatformPrivateData; + class String; + + class FontPlatformData { + + public: + + FontPlatformData(): m_private(0) {} + FontPlatformData(float size, bool bold, bool oblique); + + // Used for deleted values in the font cache's hash tables. + FontPlatformData(WTF::HashTableDeletedValueType) : m_private((FontPlatformPrivateData*)1) {} + bool isHashTableDeletedValue() const { return (unsigned)m_private == 1; } + + FontPlatformData(const FontDescription& fontDescription, const AtomicString& family, bool useDefaultFontIfNotPresent = true); + + ~FontPlatformData(); + + FontPlatformData(const FontPlatformData& o) : m_private(0) { operator=(o); } + FontPlatformData& operator=(const FontPlatformData& o); + + int isValid() const { return reinterpret_cast<unsigned>(m_private) & ~1; } + HFONT hfont() const; + const TEXTMETRIC& metrics() const; + bool isSystemFont() const; + int size() const; + unsigned hash() const { return (unsigned)m_private; } + const FontDescription& fontDescription() const; + const AtomicString& family() const; + bool operator==(const FontPlatformData& other) const { return m_private == other.m_private; } + HFONT getScaledFontHandle(int height, int width) const; + const LOGFONT& logFont() const; + int averageCharWidth() const; + bool isDisabled() const; + bool discardFontHandle(); + DWORD codePages() const; + + static bool isSongTiSupported(); + static bool mapKnownFont(DWORD codePages, String& family); + static DWORD getKnownFontCodePages(const wchar_t* family); + static const String& defaultFontFamily(); + static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family); + +#ifndef NDEBUG + String description() const; +#endif + + private: + FontPlatformPrivateData* m_private; + }; + +} + +#endif diff --git a/WebCore/platform/graphics/wince/FontWince.cpp b/WebCore/platform/graphics/wince/FontWince.cpp new file mode 100644 index 0000000..d00336b --- /dev/null +++ b/WebCore/platform/graphics/wince/FontWince.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2008 Holger Hans Peter Freyther + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "FloatRect.h" +#include "FontCache.h" +#include "FontData.h" +#include "FontFallbackList.h" +#include "GlyphBuffer.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "TransformationMatrix.h" +#include "WidthIterator.h" +#include <wtf/MathExtras.h> +#include <wtf/OwnPtr.h> +#include <wtf/unicode/Unicode.h> + +#include <windows.h> + +using namespace WTF::Unicode; + +namespace WebCore { + +HDC g_screenDC = GetDC(0); + +class ScreenDcReleaser { +public: + ~ScreenDcReleaser() + { + ReleaseDC(0, g_screenDC); + } +}; + +ScreenDcReleaser releaseScreenDc; + +void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, + int from, int numGlyphs, const FloatPoint& point) const +{ + graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point); +} + +class TextRunComponent { +public: + TextRunComponent() : m_textRun(0, 0) {} + TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset); + TextRunComponent(int spaces, const Font &font, int offset); + ~TextRunComponent() { m_textRun; } + + bool isSpace() const { return m_spaces; } + int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); } + + TextRun m_textRun; + float m_width; + int m_offset; + int m_spaces; +}; + +TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o) + : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0 + , parentTextRun.rtl() + , parentTextRun.directionalOverride() + , parentTextRun.applyRunRounding() + , parentTextRun.applyWordRounding()) + , m_offset(o) + , m_spaces(0) +{ + WidthIterator it(&font, m_textRun); + it.advance(m_textRun.length(), 0); + m_width = it.m_runWidthSoFar; +} + +TextRunComponent::TextRunComponent(int s, const Font &font, int o) + : m_textRun(0, 0) + , m_offset(o) + , m_spaces(s) +{ + m_width = s * font.primaryFont()->widthForGlyph(' '); +} + +typedef Vector<TextRunComponent, 128> TextRunComponents; + +static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run) +{ + int letterSpacing = font.letterSpacing(); + int wordSpacing = font.wordSpacing(); + int padding = run.padding(); + int numSpaces = 0; + if (padding) { + for (int i = 0; i < run.length(); i++) + if (Font::treatAsSpace(run[i])) + ++numSpaces; + } + + int offset = 0; + if (letterSpacing) { + // need to draw every letter on it's own + int start = 0; + if (Font::treatAsSpace(run[0])) { + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, font, offset)); + offset += add + letterSpacing + components->last().m_width; + start = 1; + } + for (int i = 1; i < run.length(); ++i) { + uint ch = run[i]; + if (isHighSurrogate(ch) && isLowSurrogate(run[i-1])) + ch = surrogateToUcs4(ch, run[i-1]); + if (isLowSurrogate(ch) || category(ch) == Mark_NonSpacing) + continue; + if (Font::treatAsSpace(run[i])) { + int add = 0; + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run, font, offset)); + offset += components->last().m_width + letterSpacing; + } + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, font, offset)); + offset += wordSpacing + add + components->last().m_width + letterSpacing; + start = i + 1; + continue; + } + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run, + font, offset)); + offset += components->last().m_width + letterSpacing; + } + start = i; + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run, + font, offset)); + offset += components->last().m_width; + } + offset += letterSpacing; + } else { + int start = 0; + for (int i = 0; i < run.length(); ++i) { + if (Font::treatAsSpace(run[i])) { + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run, + font, offset)); + offset += components->last().m_width; + } + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, font, offset)); + offset += add + components->last().m_width; + if (i) + offset += wordSpacing; + start = i + 1; + } + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run, + font, offset)); + offset += components->last().m_width; + } + } + return offset; +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, + int from, int to) const +{ + if (to < 0) + to = run.length(); + if (from < 0) + from = 0; + + TextRunComponents components; + int w = generateComponents(&components, *this, run); + + int curPos = 0; + for (int i = 0; i < (int)components.size(); ++i) { + const TextRunComponent& comp = components.at(i); + int len = comp.textLength(); + int curEnd = curPos + len; + if (curPos < to && from < curEnd && !comp.isSpace()) { + FloatPoint pt = point; + if (run.rtl()) + pt.setX(point.x() + w - comp.m_offset - comp.m_width); + else + pt.setX(point.x() + comp.m_offset); + drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos); + } + curPos += len; + if (from < curPos) + from = curPos; + } +} + +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +{ + TextRunComponents components; + int w = generateComponents(&components, *this, run); + return w; +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const +{ + TextRunComponents components; + int w = generateComponents(&components, *this, run); + + if (position >= w) + return run.length(); + + int offset = 0; + if (run.rtl()) { + for (size_t i = 0; i < components.size(); ++i) { + const TextRunComponent& comp = components.at(i); + int xe = w - comp.m_offset; + int xs = xe - comp.m_width; + if (position >= xs) + return offset + (comp.isSpace() + ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) + : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); + + offset += comp.textLength(); + } + } else { + for (size_t i = 0; i < components.size(); ++i) { + const TextRunComponent& comp = components.at(i); + int xs = comp.m_offset; + int xe = xs + comp.m_width; + if (position <= xe) { + if (position - xs >= xe) + return offset + comp.textLength(); + return offset + (comp.isSpace() + ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5) + : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs)); + } + offset += comp.textLength(); + } + } + return run.length(); +} + + +static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor) +{ + int start = 0; + for (size_t i = 0; i < components.size(); ++i) { + const TextRunComponent& comp = components.at(i); + if (start + comp.textLength() <= cursor) { + start += comp.textLength(); + continue; + } + int xs = comp.m_offset; + if (rtl) + xs = width - xs - comp.m_width; + + int pos = cursor - start; + if (comp.isSpace()) { + if (rtl) + pos = comp.textLength() - pos; + return xs + pos * comp.m_width / comp.m_spaces; + } + WidthIterator it(font, comp.m_textRun); + it.advance(pos); + return xs + it.m_runWidthSoFar; + } + return width; +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, + int h, int from, int to) const +{ + TextRunComponents components; + int w = generateComponents(&components, *this, run); + + if (!from && to == run.length()) + return FloatRect(pt.x(), pt.y(), w, h); + + float x1 = cursorToX(this, components, w, run.rtl(), from); + float x2 = cursorToX(this, components, w, run.rtl(), to); + if (x2 < x1) + std::swap(x1, x2); + + return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); +} + +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + +} diff --git a/WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp b/WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp new file mode 100644 index 0000000..27c4e15 --- /dev/null +++ b/WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007-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 "GlyphPageTreeNode.h" + +#include "Font.h" +#include "FontCache.h" +#include "FontData.h" +#include "SimpleFontData.h" + +namespace WebCore { + +DWORD getKnownFontCodePages(const wchar_t* family); + +typedef unsigned (*funcGetCharCodePages)(unsigned short c, unsigned& lastPos); +funcGetCharCodePages getCharCodePages = 0; + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + if (length != bufferLength) + return false; + + if (fontData->platformData().hfont()) { + DWORD fontCodePages = fontData->platformData().codePages(); + if (fontCodePages) { + if (getCharCodePages) { + unsigned lastPos = 0; + for (unsigned i = 0; i < bufferLength; ++i) { + DWORD actualCodePages = getCharCodePages(buffer[i], lastPos); + if (!actualCodePages || (actualCodePages & fontCodePages)) + setGlyphDataForIndex(offset + i, buffer[i], fontData); + else + setGlyphDataForIndex(offset + i, buffer[i], 0); + } + return true; +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + } else if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) { +#else + } else if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) { +#endif + for (unsigned i = 0; i < bufferLength; ++i) { + DWORD actualCodePages; + langFontLink->GetCharCodePages(buffer[i], &actualCodePages); + if (!actualCodePages || (actualCodePages & fontCodePages)) + setGlyphDataForIndex(offset + i, buffer[i], fontData); + else + setGlyphDataForIndex(offset + i, buffer[i], 0); + } + return true; + } + } + } + + for (unsigned i = 0; i < length; ++i) + setGlyphDataForIndex(offset + i, buffer[i], fontData); + + return true; +} + +} + diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp new file mode 100644 index 0000000..c114c0e --- /dev/null +++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp @@ -0,0 +1,1930 @@ +/* + * Copyright (C) 2007-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 "GraphicsContext.h" + +#include "CharacterNames.h" +#include "GlyphBuffer.h" +#include "Gradient.h" +#include "GraphicsContextPrivate.h" +#include "NotImplemented.h" +#include "Path.h" +#include "PlatformPathWince.h" +#include "SharedBitmap.h" +#include "SimpleFontData.h" +#include "TransformationMatrix.h" +#include <wtf/OwnPtr.h> + +#include <windows.h> + +namespace WebCore { + +typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops); +typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops); +FuncGradientFillRectLinear g_linearGradientFiller = 0; +FuncGradientFillRectRadial g_radialGradientFiller = 0; + +static inline bool isZero(double d) +{ + return d > 0 ? d <= 1.E-10 : d >= -1.E-10; +} + +// stableRound rounds -0.5 to 0, where lround rounds -0.5 to -1. +static inline int stableRound(double d) +{ + if (d > 0) + return static_cast<int>(d + 0.5); + + int i = static_cast<int>(d); + return i - d > 0.5 ? i - 1 : i; +} + +// Unlike enclosingIntRect(), this function does strict rounding. +static inline IntRect roundRect(const FloatRect& r) +{ + return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.right()) - stableRound(r.x()), stableRound(r.bottom()) - stableRound(r.y())); +} + +// Rotation transformation +class RotationTransform { +public: + RotationTransform() + : m_cosA(1.) + , m_sinA(0.) + , m_preShiftX(0) + , m_preShiftY(0) + , m_postShiftX(0) + , m_postShiftY(0) + { + } + RotationTransform operator-() const + { + RotationTransform rtn; + rtn.m_cosA = m_cosA; + rtn.m_sinA = -m_sinA; + rtn.m_preShiftX = m_postShiftX; + rtn.m_preShiftY = m_postShiftY; + rtn.m_postShiftX = m_preShiftX; + rtn.m_postShiftY = m_preShiftY; + return rtn; + } + void map(double x1, double y1, double* x2, double* y2) const + { + x1 += m_preShiftX; + y1 += m_preShiftY; + *x2 = x1 * m_cosA + y1 * m_sinA + m_postShiftX; + *y2 = y1 * m_cosA - x1 * m_sinA + m_postShiftY; + } + void map(int x1, int y1, int* x2, int* y2) const + { + x1 += m_preShiftX; + y1 += m_preShiftY; + *x2 = stableRound(x1 * m_cosA + y1 * m_sinA) + m_postShiftX; + *y2 = stableRound(y1 * m_cosA - x1 * m_sinA) + m_postShiftY; + } + + double m_cosA; + double m_sinA; + int m_preShiftX; + int m_preShiftY; + int m_postShiftX; + int m_postShiftY; +}; + +template<class T> static inline IntPoint mapPoint(const IntPoint& p, const T& t) +{ + int x, y; + t.map(p.x(), p.y(), &x, &y); + return IntPoint(x, y); +} + +template<class T> static inline FloatPoint mapPoint(const FloatPoint& p, const T& t) +{ + double x, y; + t.map(p.x(), p.y(), &x, &y); + return FloatPoint(static_cast<float>(x), static_cast<float>(y)); +} + +template<class Transform, class Rect, class Value> static inline Rect mapRect(const Rect& rect, const Transform& transform) +{ + Value x[4], y[4]; + Value l, t, r, b; + r = rect.right() - 1; + b = rect.bottom() - 1; + transform.map(rect.x(), rect.y(), x, y); + transform.map(rect.x(), b, x + 1, y + 1); + transform.map(r, b, x + 2, y + 2); + transform.map(r, rect.y(), x + 3, y + 3); + l = r = x[3]; + t = b = y[3]; + for (int i = 0; i < 3; ++i) { + if (x[i] < l) + l = x[i]; + else if (x[i] > r) + r = x[i]; + + if (y[i] < t) + t = y[i]; + else if (y[i] > b) + b = y[i]; + } + + return IntRect(l, t, r - l + 1, b - t + 1); +} + +template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform) +{ + return mapRect<T, IntRect, int>(rect, transform); +} + +template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform) +{ + return mapRect<T, FloatRect, double>(rect, transform); +} + +class GraphicsContextPlatformPrivateData { +public: + GraphicsContextPlatformPrivateData() + : m_transform() + , m_opacity(1.0) + { + } + + TransformationMatrix m_transform; + float m_opacity; + Vector<Path> m_paths; +}; + +enum AlphaPaintType { + AlphaPaintNone, + AlphaPaintImage, + AlphaPaintOther, +}; + +class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData { +public: + GraphicsContextPlatformPrivate(HDC dc) + : m_dc(dc) + { + } + ~GraphicsContextPlatformPrivate() + { + while (!m_backupData.isEmpty()) + restore(); + } + + IntPoint origin() const + { + return IntPoint(stableRound(-m_transform.e()), stableRound(-m_transform.f())); + } + + void translate(float x, float y) + { + m_transform.translate(x, y); + } + + void scale(const FloatSize& size) + { + m_transform.scaleNonUniform(size.width(), size.height()); + } + + void rotate(float radians) + { + m_transform.rotate(rad2deg(radians)); + } + + void concatCTM(const TransformationMatrix& transform) + { + m_transform = transform * m_transform; + } + + IntRect mapRect(const IntRect& rect) const + { + return m_transform.mapRect(rect); + } + + FloatRect mapRect(const FloatRect& rect) const + { + return m_transform.mapRect(rect); + } + + IntPoint mapPoint(const IntPoint& point) const + { + return m_transform.mapPoint(point); + } + + FloatPoint mapPoint(const FloatPoint& point) const + { + return m_transform.mapPoint(point); + } + + FloatSize mapSize(const FloatSize& size) const + { + double w, h; + m_transform.map(size.width(), size.height(), w, h); + return FloatSize(static_cast<float>(w), static_cast<float>(h)); + } + + void save() + { + if (m_dc) + SaveDC(m_dc); + + m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this)); + } + + void restore() + { + if (m_backupData.isEmpty()) + return; + + if (m_dc) + RestoreDC(m_dc, -1); + + GraphicsContextPlatformPrivateData::operator=(m_backupData.last()); + m_backupData.removeLast(); + } + + bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); } + + PassRefPtr<SharedBitmap> getTransparentLayerBitmap(IntRect& origRect, AlphaPaintType alphaPaint, RECT& bmpRect, bool checkClipBox, bool force) const + { + if (m_opacity <= 0) + return 0; + + if (force || m_opacity < 1.) { + if (checkClipBox) { + RECT clipBox; + int clipType = GetClipBox(m_dc, &clipBox); + if (clipType == SIMPLEREGION || clipType == COMPLEXREGION) + origRect.intersect(clipBox); + if (origRect.isEmpty()) + return 0; + } + + RefPtr<SharedBitmap> bmp = SharedBitmap::createInstance(alphaPaint == AlphaPaintNone, origRect.width(), origRect.height(), false); + SetRect(&bmpRect, 0, 0, origRect.width(), origRect.height()); + if (bmp) { + switch (alphaPaint) { + case AlphaPaintNone: + case AlphaPaintImage: + { + SharedBitmap::DCHolder dc(bmp.get()); + if (dc.get()) { + BitBlt(dc.get(), 0, 0, origRect.width(), origRect.height(), m_dc, origRect.x(), origRect.y(), SRCCOPY); + if (bmp->is32bit() && (!m_bitmap || m_bitmap->is16bit())) { + // Set alpha channel + unsigned* pixels = (unsigned*)bmp->bytes(); + const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels(); + while (pixels < pixelsEnd) { + *pixels |= 0xFF000000; + ++pixels; + } + } + return bmp; + } + } + break; + //case AlphaPaintOther: + default: + memset(bmp->bytes(), 0xFF, bmp->bitmapInfo().numPixels() * 4); + return bmp; + break; + } + } + } + + bmpRect = origRect; + return 0; + } + + void paintBackTransparentLayerBitmap(HDC hdc, SharedBitmap* bmp, const IntRect& origRect, AlphaPaintType alphaPaint, const RECT& bmpRect) + { + if (hdc == m_dc) + return; + +#if !defined(NO_ALPHABLEND) + if (alphaPaint == AlphaPaintOther) { + ASSERT(bmp && bmp->bytes() && bmp->is32bit()); + unsigned* pixels = (unsigned*)bmp->bytes(); + const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels(); + while (pixels < pixelsEnd) { + *pixels ^= 0xFF000000; + ++pixels; + } + } + if (m_opacity < 1. || alphaPaint == AlphaPaintOther) { + const BLENDFUNCTION blend = { AC_SRC_OVER, 0 + , m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255) + , alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA }; + AlphaBlend(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend); + } else +#endif + StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY); + } + + HDC m_dc; + RefPtr<SharedBitmap> m_bitmap; + Vector<GraphicsContextPlatformPrivateData> m_backupData; +}; + +static HPEN createPen(const Color& col, double fWidth, StrokeStyle style) +{ + int width = stableRound(fWidth); + if (width < 1) + width = 1; + + int penStyle = PS_NULL; + switch (style) { + case SolidStroke: + penStyle = PS_SOLID; + break; + case DottedStroke: // not supported on Windows CE + case DashedStroke: + penStyle = PS_DASH; + width = 1; + break; + default: + break; + } + + return CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue())); +} + +static inline HGDIOBJ createBrush(const Color& col) +{ + return CreateSolidBrush(RGB(col.red(), col.green(), col.blue())); +} + +template <typename PixelType, bool Is16bit> static void _rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform) +{ + int destW = destBmp->width(); + int destH = destBmp->height(); + int sourceW = sourceBmp->width(); + int sourceH = sourceBmp->height(); + PixelType* dest = (PixelType*)destBmp->bytes(); + const PixelType* source = (const PixelType*)sourceBmp->bytes(); + int padding; + int paddedSourceW; + if (Is16bit) { + padding = destW & 1; + paddedSourceW = sourceW + (sourceW & 1); + } else { + padding = 0; + paddedSourceW = sourceW; + } + if (isZero(transform.m_sinA)) { + int cosA = transform.m_cosA > 0 ? 1 : -1; + for (int y = 0; y < destH; ++y) { + for (int x = 0; x < destW; ++x) { + int x1 = x + transform.m_preShiftX; + int y1 = y + transform.m_preShiftY; + int srcX = x1 * cosA + transform.m_postShiftX; + int srcY = y1 * cosA - transform.m_postShiftY; + if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH) + *dest++ = source[srcY * paddedSourceW + srcX] | 0xFF000000; + else + *dest++ |= 0xFF; + } + dest += padding; + } + } else if (isZero(transform.m_cosA)) { + int sinA = transform.m_sinA > 0 ? 1 : -1; + for (int y = 0; y < destH; ++y) { + for (int x = 0; x < destW; ++x) { + int x1 = x + transform.m_preShiftX; + int y1 = y + transform.m_preShiftY; + int srcX = y1 * sinA + transform.m_postShiftX; + int srcY = -x1 * sinA + transform.m_postShiftY; + if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH) + *dest++ = source[srcY * paddedSourceW + srcX]; + } + dest += padding; + } + } else { + for (int y = 0; y < destH; ++y) { + for (int x = 0; x < destW; ++x) { + // FIXME: for best quality, we should get weighted sum of four neighbours, + // but that will be too expensive + int srcX, srcY; + transform.map(x, y, &srcX, &srcY); + if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH) + *dest++ = source[srcY * paddedSourceW + srcX]; + } + dest += padding; + } + } +} + +static void rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform) +{ + ASSERT(destBmp->is16bit() == sourceBmp->is16bit()); + if (destBmp->is16bit()) + _rotateBitmap<unsigned short, true>(destBmp, sourceBmp, transform); + else + _rotateBitmap<unsigned, false>(destBmp, sourceBmp, transform); +} + +class TransparentLayerDC : Noncopyable { +public: + TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform = 0, int alpha = 255, bool paintImage = false); + ~TransparentLayerDC(); + + HDC hdc() const { return m_memDc; } + const RECT& rect() const { return m_bmpRect; } + IntSize toShift() const { return IntSize(m_bmpRect.left - m_origRect.x(), m_bmpRect.top - m_origRect.y()); } + void fillAlphaChannel(); + +private: + GraphicsContextPlatformPrivate* m_data; + IntRect m_origRect; + IntRect m_rotatedOrigRect; + HDC m_memDc; + RefPtr<SharedBitmap> m_bitmap; + RefPtr<SharedBitmap> m_rotatedBitmap; + RECT m_bmpRect; + unsigned m_key1; + unsigned m_key2; + RotationTransform m_rotation; + float m_oldOpacity; + AlphaPaintType m_alphaPaintType; +}; + +TransparentLayerDC::TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform, int alpha, bool paintImage) +: m_data(data) +, m_origRect(origRect) +, m_oldOpacity(data->m_opacity) +// m_key1 and m_key2 are not initalized here. They are used only in the case that +// SharedBitmap::getDC() is called, I.E., when m_bitmap is not null. +{ + m_data->m_opacity *= alpha / 255.; + bool mustCreateLayer; + if (!m_data->hasAlpha()) { + mustCreateLayer = false; + m_alphaPaintType = AlphaPaintNone; + } else { + mustCreateLayer = true; + m_alphaPaintType = paintImage ? AlphaPaintImage : AlphaPaintOther; + } + if (rectBeforeTransform && !isZero(m_data->m_transform.b())) { + m_rotatedOrigRect = origRect; + m_rotatedBitmap = m_data->getTransparentLayerBitmap(m_rotatedOrigRect, m_alphaPaintType, m_bmpRect, false, true); + if (m_rotatedBitmap) { + double a = m_data->m_transform.a(); + double b = m_data->m_transform.b(); + double c = _hypot(a, b); + m_rotation.m_cosA = a / c; + m_rotation.m_sinA = b / c; + + int centerX = origRect.x() + origRect.width() / 2; + int centerY = origRect.y() + origRect.height() / 2; + m_rotation.m_preShiftX = -centerX; + m_rotation.m_preShiftY = -centerY; + m_rotation.m_postShiftX = centerX; + m_rotation.m_postShiftY = centerY; + + m_origRect = mapRect(m_rotatedOrigRect, m_rotation); + + m_rotation.m_preShiftX += m_rotatedOrigRect.x(); + m_rotation.m_preShiftY += m_rotatedOrigRect.y(); + m_rotation.m_postShiftX -= m_origRect.x(); + m_rotation.m_postShiftY -= m_origRect.y(); + + FloatPoint topLeft = m_data->m_transform.mapPoint(FloatPoint(rectBeforeTransform->topLeft())); + FloatPoint topRight(rectBeforeTransform->right() - 1, rectBeforeTransform->y()); + topRight = m_data->m_transform.mapPoint(topRight); + FloatPoint bottomLeft(rectBeforeTransform->x(), rectBeforeTransform->bottom() - 1); + bottomLeft = m_data->m_transform.mapPoint(bottomLeft); + FloatSize sideTop = topRight - topLeft; + FloatSize sideLeft = bottomLeft - topLeft; + float width = _hypot(sideTop.width() + 1, sideTop.height() + 1); + float height = _hypot(sideLeft.width() + 1, sideLeft.height() + 1); + + origRect.inflateX(stableRound((width - origRect.width()) * 0.5)); + origRect.inflateY(stableRound((height - origRect.height()) * 0.5)); + + m_bitmap = SharedBitmap::createInstance(m_rotatedBitmap->is16bit(), m_origRect.width(), m_origRect.height(), true); + if (m_bitmap) + rotateBitmap(m_bitmap.get(), m_rotatedBitmap.get(), -m_rotation); + else + m_rotatedBitmap = 0; + } + } else + m_bitmap = m_data->getTransparentLayerBitmap(m_origRect, m_alphaPaintType, m_bmpRect, true, mustCreateLayer); + if (m_bitmap) + m_memDc = m_bitmap->getDC(&m_key1, &m_key2); + else + m_memDc = m_data->m_dc; +} + +TransparentLayerDC::~TransparentLayerDC() +{ + if (m_rotatedBitmap) { + m_bitmap->releaseDC(m_memDc, m_key1, m_key2); + m_key1 = m_key2 = 0; + rotateBitmap(m_rotatedBitmap.get(), m_bitmap.get(), m_rotation); + m_memDc = m_rotatedBitmap->getDC(&m_key1, &m_key2); + m_data->paintBackTransparentLayerBitmap(m_memDc, m_rotatedBitmap.get(), m_rotatedOrigRect, m_alphaPaintType, m_bmpRect); + m_rotatedBitmap->releaseDC(m_memDc, m_key1, m_key2); + } else if (m_bitmap) { + m_data->paintBackTransparentLayerBitmap(m_memDc, m_bitmap.get(), m_origRect, m_alphaPaintType, m_bmpRect); + m_bitmap->releaseDC(m_memDc, m_key1, m_key2); + } + m_data->m_opacity = m_oldOpacity; +} + +void TransparentLayerDC::fillAlphaChannel() +{ + if (!m_bitmap || !m_bitmap->is32bit()) + return; + + unsigned* pixels = (unsigned*)m_bitmap->bytes(); + const unsigned* const pixelsEnd = pixels + m_bitmap->bitmapInfo().numPixels(); + while (pixels < pixelsEnd) { + *pixels |= 0xFF000000; + ++pixels; + } +} + +class ScopeDCProvider : Noncopyable { +public: + explicit ScopeDCProvider(GraphicsContextPlatformPrivate* data) + : m_data(data) + { + if (m_data->m_bitmap) + m_data->m_dc = m_data->m_bitmap->getDC(&m_key1, &m_key2); + } + ~ScopeDCProvider() + { + if (m_data->m_bitmap) { + m_data->m_bitmap->releaseDC(m_data->m_dc, m_key1, m_key2); + m_data->m_dc = 0; + } + } +private: + GraphicsContextPlatformPrivate* m_data; + unsigned m_key1; + unsigned m_key2; +}; + + +GraphicsContext::GraphicsContext(PlatformGraphicsContext* dc) +: m_common(createGraphicsContextPrivate()) +, m_data(new GraphicsContextPlatformPrivate(dc)) +{ +} + +GraphicsContext::~GraphicsContext() +{ + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp) +{ + ASSERT(!m_data->m_dc); + m_data->m_bitmap = bmp; +} + +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + notImplemented(); + ASSERT_NOT_REACHED(); + return 0; +} + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + notImplemented(); + ASSERT_NOT_REACHED(); +} + +void GraphicsContext::savePlatformState() +{ + m_data->save(); +} + +void GraphicsContext::restorePlatformState() +{ + m_data->restore(); +} + +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (!m_data->m_opacity || paintingDisabled() || rect.isEmpty()) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect trRect = m_data->mapRect(rect); + TransparentLayerDC transparentDC(m_data, trRect, &rect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + HGDIOBJ brush = 0; + HGDIOBJ oldBrush; + if (fillColor().alpha()) { + brush = createBrush(fillColor()); + oldBrush = SelectObject(dc, brush); + } else + SelectObject(dc, GetStockObject(NULL_BRUSH)); + + HGDIOBJ pen = 0; + HGDIOBJ oldPen; + if (strokeStyle() != NoStroke) { + pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + oldPen = SelectObject(dc, pen); + } else + SelectObject(dc, GetStockObject(NULL_PEN)); + + if (!brush && !pen) + return; + + if (trRect.width() <= 0) + trRect.setWidth(1); + if (trRect.height() <= 0) + trRect.setHeight(1); + + Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + + if (pen) { + SelectObject(dc, oldPen); + DeleteObject(pen); + } + + if (brush) { + SelectObject(dc, oldBrush); + DeleteObject(brush); + } +} + +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || !strokeColor().alpha()) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntPoint trPoint1 = m_data->mapPoint(point1); + IntPoint trPoint2 = m_data->mapPoint(point2); + + IntRect lineRect(trPoint1, trPoint2 - trPoint1); + lineRect.setHeight(lineRect.height() + strokeThickness()); + TransparentLayerDC transparentDC(m_data, lineRect, 0, strokeColor().alpha()); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trPoint1 += transparentDC.toShift(); + trPoint2 += transparentDC.toShift(); + + HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen); + + MoveToEx(dc, trPoint1.x(), trPoint1.y(), 0); + LineTo(dc, trPoint2.x(), trPoint2.y()); + + SelectObject(dc, oldPen); + DeleteObject(pen); +} + +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (!m_data->m_opacity || paintingDisabled() || (!fillColor().alpha() && strokeStyle() == NoStroke)) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect trRect = m_data->mapRect(rect); + TransparentLayerDC transparentDC(m_data, trRect, &rect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + HGDIOBJ brush = 0; + HGDIOBJ oldBrush; + if (fillColor().alpha()) { + brush = createBrush(fillColor()); + oldBrush = SelectObject(dc, brush); + } else + SelectObject(dc, GetStockObject(NULL_BRUSH)); + HGDIOBJ pen = 0; + HGDIOBJ oldPen; + if (strokeStyle() != NoStroke) { + pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + oldPen = SelectObject(dc, pen); + } else + SelectObject(dc, GetStockObject(NULL_PEN)); + + Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + + if (pen) { + SelectObject(dc, oldPen); + DeleteObject(pen); + } + + if (brush) { + SelectObject(dc, oldBrush); + DeleteObject(brush); + } +} + +static inline bool equalAngle(double a, double b) +{ + return fabs(a - b) < 1E-5; +} + +void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y) +{ + while (angle < 0) + angle += 2 * piDouble; + while (angle >= 2 * piDouble) + angle -= 2 * piDouble; + + if (equalAngle(angle, 0) || equalAngle(angle, 2 * piDouble)) { + x = a; + y = 0; + } else if (equalAngle(angle, piDouble)) { + x = -a; + y = 0; + } else if (equalAngle(angle, .5 * piDouble)) { + x = 0; + y = b; + } else if (equalAngle(angle, 1.5 * piDouble)) { + x = 0; + y = -b; + } else { + double k = tan(angle); + double sqA = a * a; + double sqB = b * b; + double tmp = 1. / (1. / sqA + (k * k) / sqB); + tmp = tmp <= 0 ? 0 : sqrt(tmp); + if (angle > .5 * piDouble && angle < 1.5 * piDouble) + tmp = -tmp; + x = tmp; + + k = tan(.5 * piDouble - angle); + tmp = 1. / ((k * k) / sqA + 1 / sqB); + tmp = tmp <= 0 ? 0 : sqrt(tmp); + if (angle > piDouble) + tmp = -tmp; + y = tmp; + } +} + +void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) +{ + if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || rect.isEmpty()) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect trRect = m_data->mapRect(rect); + TransparentLayerDC transparentDC(m_data, trRect, &rect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen); + + double a = trRect.width() * 0.5; + double b = trRect.height() * 0.5; + int centerX = stableRound(trRect.x() + a); + int centerY = stableRound(trRect.y() + b); + float fstartX, fstartY, fendX, fendY; + int startX, startY, endX, endY; + getEllipsePointByAngle(deg2rad((double)startAngle), a, b, fstartX, fstartY); + getEllipsePointByAngle(deg2rad((double)startAngle + angleSpan), a, b, fendX, fendY); + startX = stableRound(fstartX); + startY = stableRound(fstartY); + endX = stableRound(fendX); + endY = stableRound(fendY); + + startX += centerX; + startY = centerY - startY; + endX += centerX; + endY = centerY - endY; + RECT clipRect; + if (startX < endX) { + clipRect.left = startX; + clipRect.right = endX; + } else { + clipRect.left = endX; + clipRect.right = startX; + } + if (startY < endY) { + clipRect.top = startY; + clipRect.bottom = endY; + } else { + clipRect.top = endY; + clipRect.bottom = startY; + } + + OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0)); + bool newClip; + if (GetClipRgn(dc, clipRgn.get()) <= 0) { + newClip = true; + clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom)); + SelectClipRgn(dc, clipRgn.get()); + } else { + newClip = false; + IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); + } + + HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); + Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + SelectObject(dc, oldBrush); + + if (newClip) + SelectClipRgn(dc, 0); + else + SelectClipRgn(dc, clipRgn.get()); + + SelectObject(dc, oldPen); + DeleteObject(pen); +} + +void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) +{ + if (!m_data->m_opacity || paintingDisabled() || npoints <= 1 || !points) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + Vector<POINT, 20> winPoints(npoints); + FloatPoint trPoint = m_data->mapPoint(points[0]); + winPoints[0].x = stableRound(trPoint.x()); + winPoints[0].y = stableRound(trPoint.y()); + RECT rect = { winPoints[0].x, winPoints[0].y, winPoints[0].x, winPoints[0].y }; + for (size_t i = 1; i < npoints; ++i) { + trPoint = m_data->mapPoint(points[i]); + winPoints[i].x = stableRound(trPoint.x()); + winPoints[i].y = stableRound(trPoint.y()); + if (rect.left > winPoints[i].x) + rect.left = winPoints[i].x; + else if (rect.right < winPoints[i].x) + rect.right = winPoints[i].x; + if (rect.top > winPoints[i].y) + rect.top = winPoints[i].y; + else if (rect.bottom < winPoints[i].y) + rect.bottom = winPoints[i].y; + } + rect.bottom += 1; + rect.right += 1; + + IntRect intRect(rect); + TransparentLayerDC transparentDC(m_data, intRect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + + for (size_t i = 0; i < npoints; ++i) { + winPoints[i].x += transparentDC.toShift().width(); + winPoints[i].y += transparentDC.toShift().height(); + } + + HGDIOBJ brush = 0; + HGDIOBJ oldBrush; + if (fillColor().alpha()) { + brush = createBrush(fillColor()); + oldBrush = SelectObject(dc, brush); + } else + SelectObject(dc, GetStockObject(NULL_BRUSH)); + + HGDIOBJ pen = 0; + HGDIOBJ oldPen; + if (strokeStyle() != NoStroke) { + pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + oldPen = SelectObject(dc, pen); + } else + SelectObject(dc, GetStockObject(NULL_PEN)); + + if (!brush && !pen) + return; + + Polygon(dc, winPoints.data(), npoints); + + if (pen) { + SelectObject(dc, oldPen); + DeleteObject(pen); + } + + if (brush) { + SelectObject(dc, oldBrush); + DeleteObject(brush); + } +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +{ + if (paintingDisabled() || !m_data->m_opacity) + return; + + int alpha = color.alpha(); + if (!alpha) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect intRect = enclosingIntRect(rect); + TransparentLayerDC transparentDC(m_data, m_data->mapRect(intRect), &intRect, alpha); + + if (!transparentDC.hdc()) + return; + + OwnPtr<HBRUSH> hbrush(CreateSolidBrush(RGB(color.red(), color.green(), color.blue()))); + FillRect(transparentDC.hdc(), &transparentDC.rect(), hbrush.get()); +} + +void GraphicsContext::clip(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + if (!m_data->m_dc) + return; + + IntRect trRect = enclosingIntRect(m_data->mapRect(rect)); + + OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0)); + if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0) + IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + else { + clipRgn.set(CreateRectRgn(trRect.x(), trRect.y(), trRect.right(), trRect.bottom())); + SelectClipRgn(m_data->m_dc, clipRgn.get()); + } +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + if (!m_data->m_dc) + return; + + IntRect trRect = m_data->mapRect(rect); + + ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (!m_data->m_opacity || paintingDisabled()) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + int radius = (focusRingWidth() - 1) / 2; + int offset = radius + focusRingOffset(); + + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + IntRect finalFocusRect; + for (unsigned i = 0; i < rectCount; i++) { + IntRect focusRect = rects[i]; + focusRect.inflate(offset); + finalFocusRect.unite(focusRect); + } + + IntRect intRect = finalFocusRect; + IntRect trRect = m_data->mapRect(finalFocusRect); + TransparentLayerDC transparentDC(m_data, trRect, &intRect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + RECT rect = trRect; + DrawFocusRect(dc, &rect); +} + +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +{ + if (paintingDisabled()) + return; + + StrokeStyle oldStyle = strokeStyle(); + setStrokeStyle(SolidStroke); + drawLine(origin, origin + IntSize(width, 0)); + setStrokeStyle(oldStyle); +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformFillColor(const Color& col) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& col) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformStrokeThickness(float strokeThickness) +{ + notImplemented(); +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ + notImplemented(); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + // We can only clip rectangles on WINCE + clip(rect); +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + if (m_data->hasAlpha()) { + IntRect trRect = enclosingIntRect(m_data->mapRect(rect)); + m_data->m_bitmap->clearPixels(trRect); + return; + } + + fillRect(rect, Color(Color::white)); +} + +void GraphicsContext::strokeRect(const FloatRect& rect, float width) +{ + if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect intRect = enclosingIntRect(rect); + IntRect trRect = m_data->mapRect(intRect); + TransparentLayerDC transparentDC(m_data, trRect, &intRect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen); + + int right = trRect.right() - 1; + int bottom = trRect.bottom() - 1; + const POINT intPoints[5] = + { + { trRect.x(), trRect.y() }, + { right, trRect.y() }, + { right, bottom }, + { trRect.x(), bottom }, + { trRect.x(), trRect.y() } + }; + + Polyline(dc, intPoints, 5); + + SelectObject(dc, oldPen); + DeleteObject(pen); +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + m_data->save(); + m_data->m_opacity *= opacity; +} + +void GraphicsContext::endTransparencyLayer() +{ + m_data->restore(); +} + +void GraphicsContext::concatCTM(const TransformationMatrix& transform) +{ + m_data->concatCTM(transform); +} + +TransformationMatrix& GraphicsContext::affineTransform() +{ + return m_data->m_transform; +} + +const TransformationMatrix& GraphicsContext::affineTransform() const +{ + return m_data->m_transform; +} + +void GraphicsContext::resetAffineTransform() +{ + m_data->m_transform.makeIdentity(); +} + +void GraphicsContext::translate(float x, float y) +{ + m_data->translate(x, y); +} + +void GraphicsContext::rotate(float radians) +{ + m_data->rotate(radians); +} + +IntPoint GraphicsContext::origin() +{ + return m_data->origin(); +} + +void GraphicsContext::scale(const FloatSize& size) +{ + m_data->scale(size); +} + +void GraphicsContext::setLineCap(LineCap lineCap) +{ + notImplemented(); +} + +void GraphicsContext::setLineJoin(LineJoin lineJoin) +{ + notImplemented(); +} + +void GraphicsContext::setMiterLimit(float miter) +{ + notImplemented(); +} + +void GraphicsContext::setAlpha(float alpha) +{ + m_data->m_opacity = alpha; +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + notImplemented(); +} + +void GraphicsContext::beginPath() +{ + m_data->m_paths.clear(); +} + +void GraphicsContext::addPath(const Path& path) +{ + m_data->m_paths.append(path); +} + +void GraphicsContext::clip(const Path& path) +{ + notImplemented(); +} + +void GraphicsContext::clipOut(const Path&) +{ + notImplemented(); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect&) +{ + notImplemented(); +} + +static inline IntPoint rectCenterPoint(const RECT& rect) +{ + return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); +} +void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c) +{ + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntSize shadowSize; + int shadowBlur = 0; + Color shadowColor; + + getShadow(shadowSize, shadowBlur, shadowColor); + + IntRect dstRect = fillRect; + + dstRect.move(shadowSize); + dstRect.inflate(shadowBlur); + dstRect = m_data->mapRect(dstRect); + + FloatSize newTopLeft(m_data->mapSize(topLeft)); + FloatSize newTopRight(m_data->mapSize(topRight)); + FloatSize newBottomLeft(m_data->mapSize(bottomLeft)); + FloatSize newBottomRight(m_data->mapSize(bottomRight)); + + TransparentLayerDC transparentDc(m_data, dstRect, &fillRect); + HDC dc = transparentDc.hdc(); + if (!dc) + return; + + dstRect.move(transparentDc.toShift()); + + RECT rectWin = dstRect; + + HGDIOBJ brush = createBrush(shadowColor); + HGDIOBJ oldBrush = SelectObject(dc, brush); + + SelectObject(dc, GetStockObject(NULL_PEN)); + + IntPoint centerPoint = rectCenterPoint(rectWin); + // Draw top left half + RECT clipRect(rectWin); + clipRect.right = centerPoint.x(); + clipRect.bottom = centerPoint.y(); + + OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0)); + bool needsNewClip = (GetClipRgn(dc, clipRgn.get()) <= 0); + + drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopLeft.width() * 2), stableRound(newTopLeft.height() * 2)); + + // Draw top right + clipRect = rectWin; + clipRect.left = centerPoint.x(); + clipRect.bottom = centerPoint.y(); + + drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopRight.width() * 2), stableRound(newTopRight.height() * 2)); + + // Draw bottom left + clipRect = rectWin; + clipRect.right = centerPoint.x(); + clipRect.top = centerPoint.y(); + + drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomLeft.width() * 2), stableRound(newBottomLeft.height() * 2)); + + // Draw bottom right + clipRect = rectWin; + clipRect.left = centerPoint.x(); + clipRect.top = centerPoint.y(); + + drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2)); + + SelectObject(dc, oldBrush); + DeleteObject(brush); +} + + +void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height) +{ + if (!dc) + return; + + OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0)); + if (needsNewClip) { + clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom)); + SelectClipRgn(dc, clipRgn.get()); + } else + IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); + + ::RoundRect(dc, rectWin.left , rectWin.top , rectWin.right , rectWin.bottom , width, height); + + SelectClipRgn(dc, needsNewClip ? 0 : clipRgn.get()); +} + + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +{ + notImplemented(); + return frect; +} + +Color gradientAverageColor(const Gradient* gradient) +{ + const Vector<Gradient::ColorStop>& stops = gradient->getStops(); + if (stops.isEmpty()) + return Color(); + + const Gradient::ColorStop& stop = stops.first(); + if (stops.size() == 1) + return Color(stop.red, stop.green, stop.blue, stop.alpha); + + const Gradient::ColorStop& lastStop = stops.last(); + return Color((stop.red + lastStop.red) * 0.5f + , (stop.green + lastStop.green) * 0.5f + , (stop.blue + lastStop.blue) * 0.5f + , (stop.alpha + lastStop.alpha) * 0.5f); +} + +void GraphicsContext::fillPath() +{ + Color c = m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient + ? gradientAverageColor(m_common->state.fillGradient.get()) + : fillColor(); + + if (!c.alpha() || !m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { + HGDIOBJ brush = createBrush(c); + for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) { + IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect())); + trRect.inflate(1); + TransparentLayerDC transparentDC(m_data, trRect); + HDC dc = transparentDC.hdc(); + if (!dc) + continue; + + TransformationMatrix tr = m_data->m_transform; + tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); + + SelectObject(dc, GetStockObject(NULL_PEN)); + HGDIOBJ oldBrush = SelectObject(dc, brush); + i->platformPath()->fillPath(dc, &tr); + SelectObject(dc, oldBrush); + } + DeleteObject(brush); + } else { + SelectObject(m_data->m_dc, GetStockObject(NULL_PEN)); + HGDIOBJ brush = createBrush(c); + HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush); + for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) + i->platformPath()->fillPath(m_data->m_dc, &m_data->m_transform); + SelectObject(m_data->m_dc, oldBrush); + DeleteObject(brush); + } +} + + +void GraphicsContext::strokePath() +{ + if (!m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { + HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) { + IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect())); + trRect.inflate(1); + TransparentLayerDC transparentDC(m_data, trRect); + HDC dc = transparentDC.hdc(); + if (!dc) + continue; + + TransformationMatrix tr = m_data->m_transform; + tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); + + SelectObject(dc, GetStockObject(NULL_BRUSH)); + HGDIOBJ oldPen = SelectObject(dc, pen); + i->platformPath()->strokePath(dc, &tr); + SelectObject(dc, oldPen); + } + DeleteObject(pen); + } else { + SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH)); + HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen); + for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) + i->platformPath()->strokePath(m_data->m_dc, &m_data->m_transform); + SelectObject(m_data->m_dc, oldPen); + DeleteObject(pen); + } +} + +void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient) +{ + if (!m_data->m_opacity) + return; + + const Vector<Gradient::ColorStop>& stops = gradient->getStops(); + if (stops.isEmpty()) + return; + + size_t numStops = stops.size(); + if (numStops == 1) { + const Gradient::ColorStop& stop = stops.first(); + Color color(stop.red, stop.green, stop.blue, stop.alpha); + fillRect(r, color); + return; + } + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect intRect = enclosingIntRect(r); + IntRect rect = m_data->mapRect(intRect); + TransparentLayerDC transparentDC(m_data, rect, &intRect, 255, true); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + + rect.move(transparentDC.toShift()); + FloatPoint fp0 = m_data->mapPoint(gradient->p0()); + FloatPoint fp1 = m_data->mapPoint(gradient->p1()); + IntPoint p0(stableRound(fp0.x()), stableRound(fp0.y())); + IntPoint p1(stableRound(fp1.x()), stableRound(fp1.y())); + p0 += transparentDC.toShift(); + p1 += transparentDC.toShift(); + + if (gradient->isRadial()) { + if (g_radialGradientFiller) { + // FIXME: don't support 2D scaling at this time + double scale = (m_data->m_transform.a() + m_data->m_transform.d()) * 0.5; + float r0 = gradient->r0() * scale; + float r1 = gradient->r1() * scale; + g_radialGradientFiller(dc, rect, p0, p1, r0, r1, gradient->getStops()); + return; + } + } else if (g_linearGradientFiller) { + g_linearGradientFiller(dc, rect, p0, p1, gradient->getStops()); + return; + } + + // Simple 1D linear solution that assumes p0 is on the top or left side, and p1 is on the right or bottom side + size_t numRects = (numStops - 1); + Vector<TRIVERTEX, 20> tv; + tv.resize(numRects * 2); + Vector<GRADIENT_RECT, 10> mesh; + mesh.resize(numRects); + int x = rect.x(); + int y = rect.y(); + int width = rect.width(); + int height = rect.height(); + FloatSize d = gradient->p1() - gradient->p0(); + bool vertical = abs(d.height()) > abs(d.width()); + for (size_t i = 0; i < numStops; ++i) { + const Gradient::ColorStop& stop = stops[i]; + int iTv = i ? 2 * i - 1 : 0; + tv[iTv].Red = stop.red * 0xFFFF; + tv[iTv].Green = stop.green * 0xFFFF; + tv[iTv].Blue = stop.blue * 0xFFFF; + tv[iTv].Alpha = stop.alpha * 0xFFFF; + if (i) { + tv[iTv].x = vertical ? x + width: x + width * stop.stop; + tv[iTv].y = vertical ? y + height * stop.stop : y + height; + mesh[i - 1].UpperLeft = iTv - 1; + mesh[i - 1].LowerRight = iTv; + } else { + tv[iTv].x = x; + tv[iTv].y = y; + } + + if (i && i < numRects) { + tv[iTv + 1] = tv[iTv]; + if (vertical) + tv[iTv + 1].x = x; + else + tv[iTv + 1].y = y; + } + } + + GradientFill(dc, tv.data(), tv.size(), mesh.data(), mesh.size(), vertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H); +} + +TransformationMatrix GraphicsContext::getCTM() const +{ + return m_data->m_transform; +} + +void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) +{ + notImplemented(); +} + +void GraphicsContext::fillRect(const FloatRect& rect) +{ + if (m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient) + fillRect(rect, m_common->state.fillGradient.get()); + else + fillRect(rect, fillColor()); +} + +void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&) +{ + notImplemented(); +} + +void GraphicsContext::clearPlatformShadow() +{ + notImplemented(); +} + +void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) +{ + notImplemented(); +} + +static inline bool isCharVisible(UChar c) +{ + return c && c != zeroWidthSpace; +} + +void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to) +{ + if (paintingDisabled() || !fillColor().alpha() || !m_data->m_opacity) + return; + + bool mustSupportAlpha = m_data->hasAlpha(); + + if (!mustSupportAlpha && fillColor().alpha() == 0xFF && m_data->m_opacity >= 1.0) { + font.drawText(this, run, point, from, to); + return; + } + + float oldOpacity = m_data->m_opacity; + m_data->m_opacity *= fillColor().alpha() / 255.0; + + FloatRect textRect = font.selectionRectForText(run, point, font.height(), from, to); + textRect.setY(textRect.y() - font.ascent()); + IntRect trRect = enclosingIntRect(m_data->mapRect(textRect)); + RECT bmpRect; + AlphaPaintType alphaPaintType = mustSupportAlpha ? AlphaPaintOther : AlphaPaintNone; + if (RefPtr<SharedBitmap> bmp = m_data->getTransparentLayerBitmap(trRect, alphaPaintType, bmpRect, true, mustSupportAlpha)) { + { + GraphicsContext gc(0); + gc.setBitmap(bmp); + gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d())); + font.drawText(&gc, run, IntPoint(0, font.ascent()), from, to); + } + unsigned key1, key2; + HDC memDC = bmp->getDC(&key1, &key2); + if (memDC) { + m_data->paintBackTransparentLayerBitmap(memDC, bmp.get(), trRect, alphaPaintType, bmpRect); + bmp->releaseDC(memDC, key1, key2); + } + } + + m_data->m_opacity = oldOpacity; +} + +void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, + int from, int numGlyphs, const FloatPoint& point) +{ + if (!m_data->m_opacity) + return; + + for (;;) { + if (!numGlyphs) + return; + if (isCharVisible(*glyphBuffer.glyphs(from))) + break; + ++from; + --numGlyphs; + } + + double scaleX = m_data->m_transform.a(); + double scaleY = m_data->m_transform.d(); + + int height = fontData->platformData().size() * scaleY; + int width = fontData->platformData().averageCharWidth() * scaleX; + + if (!height || !width) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + HFONT hFont = height > 1 + ? fontData->platformData().getScaledFontHandle(height, scaleX == scaleY ? 0 : width) + : 0; + + FloatPoint startPoint(point.x(), point.y() - fontData->ascent()); + FloatPoint trPoint = m_data->mapPoint(startPoint); + int y = stableRound(trPoint.y()); + + Color color = fillColor(); + if (!color.alpha()) + return; + + COLORREF fontColor = RGB(color.red(), color.green(), color.blue()); + + if (!hFont) { + double offset = trPoint.x(); + const GlyphBufferAdvance* advance = glyphBuffer.advances(from); + if (scaleX == 1.) + for (int i = 1; i < numGlyphs; ++i) + offset += *advance++; + else + for (int i = 1; i < numGlyphs; ++i) + offset += *advance++ * scaleX; + + offset += width; + + OwnPtr<HPEN> hPen(CreatePen(PS_DASH, 1, fontColor)); + HGDIOBJ oldPen = SelectObject(m_data->m_dc, hPen.get()); + + MoveToEx(m_data->m_dc, stableRound(trPoint.x()), y, 0); + LineTo(m_data->m_dc, stableRound(offset), y); + + SelectObject(m_data->m_dc, oldPen); + return; + } + + IntSize shadowSize; + int shadowBlur = 0; + Color shadowColor; + bool hasShadow = textDrawingMode() == cTextFill + && getShadow(shadowSize, shadowBlur, shadowColor) + && shadowColor.alpha(); + COLORREF shadowRGBColor; + FloatPoint trShadowPoint; + if (hasShadow) { + shadowRGBColor = RGB(shadowColor.red(), shadowColor.green(), shadowColor.blue()); + trShadowPoint = m_data->mapPoint(startPoint + shadowSize); + } + + HGDIOBJ hOldFont = SelectObject(m_data->m_dc, hFont); + COLORREF oldTextColor = GetTextColor(m_data->m_dc); + int oldTextAlign = GetTextAlign(m_data->m_dc); + SetTextAlign(m_data->m_dc, 0); + + int oldBkMode = GetBkMode(m_data->m_dc); + SetBkMode(m_data->m_dc, TRANSPARENT); + + if (numGlyphs > 1) { + double offset = trPoint.x(); + Vector<int, 256> glyphSpace(numGlyphs); + Vector<UChar, 256> text(numGlyphs); + int* curSpace = glyphSpace.data(); + UChar* curChar = text.data(); + const UChar* srcChar = glyphBuffer.glyphs(from); + const UChar* const srcCharEnd = srcChar + numGlyphs; + *curChar++ = *srcChar++; + int firstOffset = stableRound(offset); + int lastOffset = firstOffset; + const GlyphBufferAdvance* advance = glyphBuffer.advances(from); + // FIXME: ExtTextOut() can flip over each word for RTL languages, even when TA_RTLREADING is off. + // (this can be GDI bug or font driver bug?) + // We are not clear how it processes characters and handles specified spaces. On the other side, + // our glyph buffer is already in the correct order for rendering. So, the solution is that we + // call ExtTextOut() for each single character when the text contains any RTL character. + // This solution is not perfect as it is slower than calling ExtTextOut() one time for all characters. + // Drawing characters one by one may be too slow. + bool drawOneByOne = false; + if (scaleX == 1.) { + for (; srcChar < srcCharEnd; ++srcChar) { + offset += *advance++; + int offsetInt = stableRound(offset); + if (isCharVisible(*srcChar)) { + if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft) + drawOneByOne = true; + *curChar++ = *srcChar; + *curSpace++ = offsetInt - lastOffset; + lastOffset = offsetInt; + } + } + } else { + for (; srcChar < srcCharEnd; ++srcChar) { + offset += *advance++ * scaleX; + int offsetInt = stableRound(offset); + if (isCharVisible(*srcChar)) { + if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft) + drawOneByOne = true; + *curChar++ = *srcChar; + *curSpace++ = offsetInt - lastOffset; + lastOffset = offsetInt; + } + } + } + numGlyphs = curChar - text.data(); + if (hasShadow) { + SetTextColor(m_data->m_dc, shadowRGBColor); + if (drawOneByOne) { + int xShadow = firstOffset + stableRound(trShadowPoint.x() - trPoint.x()); + int yShadow = stableRound(trShadowPoint.y()); + for (int i = 0; i < numGlyphs; ++i) { + ExtTextOut(m_data->m_dc, xShadow, yShadow, 0, NULL, text.data() + i, 1, 0); + xShadow += glyphSpace[i]; + } + } else + ExtTextOut(m_data->m_dc, firstOffset + stableRound(trShadowPoint.x() - trPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, text.data(), numGlyphs, glyphSpace.data()); + } + SetTextColor(m_data->m_dc, fontColor); + if (drawOneByOne) { + int x = firstOffset; + for (int i = 0; i < numGlyphs; ++i) { + ExtTextOut(m_data->m_dc, x, y, 0, NULL, text.data() + i, 1, 0); + x += glyphSpace[i]; + } + } else + ExtTextOut(m_data->m_dc, firstOffset, y, 0, NULL, text.data(), numGlyphs, glyphSpace.data()); + } else { + UChar c = *glyphBuffer.glyphs(from); + if (hasShadow) { + SetTextColor(m_data->m_dc, shadowRGBColor); + ExtTextOut(m_data->m_dc, stableRound(trShadowPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, &c, 1, 0); + } + SetTextColor(m_data->m_dc, fontColor); + ExtTextOut(m_data->m_dc, stableRound(trPoint.x()), y, 0, NULL, &c, 1, 0); + } + + SetTextAlign(m_data->m_dc, oldTextAlign); + SetTextColor(m_data->m_dc, oldTextColor); + SetBkMode(m_data->m_dc, oldBkMode); + SelectObject(m_data->m_dc, hOldFont); +} + +void GraphicsContext::drawFrameControl(const IntRect& rect, unsigned type, unsigned state) +{ + if (!m_data->m_opacity) + return; + + const int boxWidthBest = 8; + const int boxHeightBest = 8; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect trRect = m_data->mapRect(rect); + TransparentLayerDC transparentDC(m_data, trRect, &rect, 255, true); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + RECT rectWin = trRect; + + if ((rectWin.right - rectWin.left) < boxWidthBest) { + RefPtr<SharedBitmap> bmp = SharedBitmap::createInstance(true, boxWidthBest, boxHeightBest, true); + SharedBitmap::DCHolder memDC(bmp.get()); + if (memDC.get()) { + RECT tempRect = {0, 0, boxWidthBest, boxHeightBest}; + DrawFrameControl(memDC.get(), &tempRect, type, state); + + ::StretchBlt(dc, rectWin.left, rectWin.top, rectWin.right - rectWin.left, rectWin.bottom - rectWin.top, memDC.get(), 0, 0, boxWidthBest, boxHeightBest, SRCCOPY); + return; + } + } + + DrawFrameControl(dc, &rectWin, type, state); +} + +void GraphicsContext::drawFocusRect(const IntRect& rect) +{ + if (!m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect trRect = m_data->mapRect(rect); + TransparentLayerDC transparentDC(m_data, trRect, &rect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + RECT rectWin = trRect; + DrawFocusRect(dc, &rectWin); +} + +void GraphicsContext::paintTextField(const IntRect& rect, unsigned state) +{ + if (!m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect trRect = m_data->mapRect(rect); + TransparentLayerDC transparentDC(m_data, trRect, &rect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + + RECT rectWin = trRect; + DrawEdge(dc, &rectWin, EDGE_ETCHED, BF_RECT | BF_ADJUST); + FillRect(dc, &rectWin, reinterpret_cast<HBRUSH>(((state & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1)); +} + +void GraphicsContext::drawBitmap(SharedBitmap* bmp, const IntRect& dstRectIn, const IntRect& srcRect, CompositeOperator compositeOp) +{ + if (!m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect dstRect = m_data->mapRect(dstRectIn); + TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + dstRect.move(transparentDC.toShift()); + + bmp->draw(dc, dstRect, srcRect, compositeOp); + + if (bmp->is16bit()) + transparentDC.fillAlphaChannel(); +} + +void GraphicsContext::drawBitmapPattern(SharedBitmap* bmp, const FloatRect& tileRectIn, const TransformationMatrix& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRectIn, const IntSize& origSourceSize) +{ + if (!m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect intDstRect = enclosingIntRect(destRectIn); + IntRect trRect = m_data->mapRect(intDstRect); + TransparentLayerDC transparentDC(m_data, trRect, &intDstRect, 255, true); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + trRect.move(transparentDC.toShift()); + FloatRect movedDstRect = m_data->m_transform.inverse().mapRect(FloatRect(trRect)); + FloatSize moved(movedDstRect.location() - destRectIn.location()); + TransformationMatrix transform = m_data->m_transform; + transform.translate(moved.width(), moved.height()); + + bmp->drawPattern(dc, transform, tileRectIn, patternTransform, phase, op, destRectIn, origSourceSize); + + if (!bmp->hasAlpha()) + transparentDC.fillAlphaChannel(); +} + +void GraphicsContext::drawIcon(HICON icon, const IntRect& dstRectIn, UINT flags) +{ + if (!m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + IntRect dstRect = m_data->mapRect(dstRectIn); + TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + dstRect.move(transparentDC.toShift()); + + DrawIconEx(dc, dstRect.x(), dstRect.y(), icon, dstRect.width(), dstRect.height(), 0, NULL, flags); +} + +void GraphicsContext::setPlatformShouldAntialias(bool) +{ + notImplemented(); +} + +void GraphicsContext::setLineDash(const DashArray&, float) +{ + notImplemented(); +} + +void GraphicsContext::clipPath(WindRule) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/wince/SimpleFontDataWince.cpp b/WebCore/platform/graphics/wince/SimpleFontDataWince.cpp new file mode 100644 index 0000000..1195294 --- /dev/null +++ b/WebCore/platform/graphics/wince/SimpleFontDataWince.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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 "SimpleFontData.h" + +#include "FloatRect.h" +#include "Font.h" +#include "FontCache.h" +#include "FontDescription.h" +#include <wtf/MathExtras.h> +#include <mlang.h> +#include <tchar.h> + +namespace WebCore { + +extern HDC g_screenDC; + +void SimpleFontData::platformInit() +{ + if (!m_platformData.isValid()) + return; + + const TEXTMETRIC& tm = m_platformData.metrics(); + m_isSystemFont = m_platformData.isSystemFont(); + + m_ascent = (tm.tmAscent * m_platformData.size() + 36) / 72; + m_descent = (tm.tmDescent * m_platformData.size() + 36) / 72; + m_lineGap = (tm.tmExternalLeading * m_platformData.size() + 36) / 72; + m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_xHeight = m_ascent * 0.56f; +} + +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; + m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + FontDescription fontDesc(fontDescription); + fontDesc.setComputedSize(lroundf(0.70f * fontDesc.computedSize())); + fontDesc.setSpecifiedSize(lroundf(0.70f * fontDesc.specifiedSize())); + fontDesc.setKeywordSize(lroundf(0.70f * fontDesc.keywordSize())); + FontPlatformData* result = fontCache()->getCachedFontPlatformData(fontDesc, m_platformData.family()); + if (result) + m_smallCapsFontData = new SimpleFontData(*result); + } + return m_smallCapsFontData; +} + +DWORD getKnownFontCodePages(const wchar_t* family); + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + if (m_platformData.isDisabled()) + return true; + + // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC + // merely by testing code page intersection. This seems suspect though. Can't a font only partially + // cover a given code page? + + // FIXME: in the case that we failed to get the interface, still use the font. +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface(); +#else + IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface(); +#endif + if (!langFontLink) + return true; + + DWORD fontCodePages = m_platformData.codePages(); + if (!fontCodePages) + return false; + + DWORD acpCodePages = 0; + langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages); + + DWORD actualCodePages; + long numCharactersProcessed; + while (length) { + langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed); + if (actualCodePages && !(actualCodePages & fontCodePages)) + return false; + + length -= numCharactersProcessed; + characters += numCharactersProcessed; + } + + return true; +} + +void SimpleFontData::determinePitch() +{ + if (!m_platformData.isValid()) + return; + + const TEXTMETRIC& tm = m_platformData.metrics(); + + // Yes, this looks backwards, but the fixed pitch bit is actually set if the font + // is *not* fixed pitch. Unbelievable but true. + m_treatAsFixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + if (m_platformData.isDisabled()) + return 0; + + HGDIOBJ hOldFont = SelectObject(g_screenDC, m_platformData.hfont()); + + SIZE fontSize; + wchar_t c = glyph; + GetTextExtentPoint32(g_screenDC, &c, 1, &fontSize); + + SelectObject(g_screenDC, hOldFont); + + return (float)fontSize.cx * (float)m_platformData.size() / 72.f; +} + + +void SimpleFontData::platformCharWidthInit() +{ + if (!m_platformData.isValid()) + return; + + const TEXTMETRIC& tm = m_platformData.metrics(); + m_avgCharWidth = (tm.tmAveCharWidth * m_platformData.size() + 36) / 72; + m_maxCharWidth = (tm.tmMaxCharWidth * m_platformData.size() + 36) / 72; +} + +} |