From cad810f21b803229eb11403f9209855525a25d57 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 6 May 2011 11:45:16 +0100 Subject: Merge WebKit at r75315: Initial merge by git. Change-Id: I570314b346ce101c935ed22a626b48c2af266b84 --- .../WebCore/platform/graphics/wince/ColorWinCE.cpp | 38 + .../platform/graphics/wince/FontCacheWinCE.cpp | 351 ++++ .../graphics/wince/FontCustomPlatformData.cpp | 91 + .../graphics/wince/FontCustomPlatformData.h | 59 + .../platform/graphics/wince/FontPlatformData.cpp | 534 ++++++ .../platform/graphics/wince/FontPlatformData.h | 93 + .../WebCore/platform/graphics/wince/FontWinCE.cpp | 342 ++++ .../graphics/wince/GlyphPageTreeNodeWinCE.cpp | 78 + .../platform/graphics/wince/GradientWinCE.cpp | 52 + .../graphics/wince/GraphicsContextWinCE.cpp | 1890 ++++++++++++++++++++ .../platform/graphics/wince/ImageBufferData.h | 34 + .../platform/graphics/wince/ImageBufferWinCE.cpp | 255 +++ .../WebCore/platform/graphics/wince/ImageWinCE.cpp | 195 ++ .../graphics/wince/MediaPlayerPrivateWinCE.h | 125 ++ .../platform/graphics/wince/MediaPlayerProxy.cpp | 145 ++ .../platform/graphics/wince/MediaPlayerProxy.h | 70 + .../WebCore/platform/graphics/wince/PathWinCE.cpp | 163 ++ .../platform/graphics/wince/PlatformPathWinCE.cpp | 772 ++++++++ .../platform/graphics/wince/PlatformPathWinCE.h | 182 ++ .../platform/graphics/wince/SharedBitmap.cpp | 615 +++++++ .../WebCore/platform/graphics/wince/SharedBitmap.h | 145 ++ .../graphics/wince/SimpleFontDataWinCE.cpp | 180 ++ .../platform/graphics/wince/WinCEGraphicsExtras.h | 39 + 23 files changed, 6448 insertions(+) create mode 100644 Source/WebCore/platform/graphics/wince/ColorWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp create mode 100644 Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h create mode 100644 Source/WebCore/platform/graphics/wince/FontPlatformData.cpp create mode 100644 Source/WebCore/platform/graphics/wince/FontPlatformData.h create mode 100644 Source/WebCore/platform/graphics/wince/FontWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/GradientWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/ImageBufferData.h create mode 100644 Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/ImageWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h create mode 100644 Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp create mode 100644 Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h create mode 100644 Source/WebCore/platform/graphics/wince/PathWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h create mode 100644 Source/WebCore/platform/graphics/wince/SharedBitmap.cpp create mode 100644 Source/WebCore/platform/graphics/wince/SharedBitmap.h create mode 100644 Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp create mode 100644 Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h (limited to 'Source/WebCore/platform/graphics/wince') diff --git a/Source/WebCore/platform/graphics/wince/ColorWinCE.cpp b/Source/WebCore/platform/graphics/wince/ColorWinCE.cpp new file mode 100644 index 0000000..820b9d2 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/ColorWinCE.cpp @@ -0,0 +1,38 @@ +/* + * 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. + * + */ + +#include "config.h" +#include "Color.h" + +#include "NotImplemented.h" + +namespace WebCore { + +Color focusRingColor() +{ + return Color(0, 0, 0); +} + +void setFocusRingColorChangeFunction(void (*)()) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp b/Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp new file mode 100644 index 0000000..ccfc063 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp @@ -0,0 +1,351 @@ +/* +* 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 +#include + +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* FontCache::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 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::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& 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 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(&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 m_traitsMasks; +}; + +static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) +{ + TraitsInFamilyProcData* procData = reinterpret_cast(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& 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; +} + +SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +SimpleFontData* 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 getCachedFontData(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& traitsMasks) +{ + LOGFONT logFont; + logFont.lfCharSet = DEFAULT_CHARSET; + unsigned familyLength = std::min(familyName.length(), static_cast(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(&procData), 0); + copyToVector(procData.m_traitsMasks, traitsMasks); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp new file mode 100644 index 0000000..f61ae8e --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp @@ -0,0 +1,91 @@ +/* + * 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 "SharedBuffer.h" +#include + +namespace WebCore { + +static CustomFontCache* g_customFontCache = 0; + +bool renameFont(SharedBuffer* fontData, const String& fontName); + +void setCustomFontCache(CustomFontCache* cache) +{ + g_customFontCache = cache; +} + +FontCustomPlatformData::~FontCustomPlatformData() +{ + if (g_customFontCache && !m_name.isEmpty()) + g_customFontCache->unregisterFont(m_name); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, 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 fontUuid(sizeof(GUID)); + + unsigned int* ptr = reinterpret_cast(fontUuid.data()); + for (int i = 0; i < sizeof(GUID) / sizeof(int) ; ++i) + *(ptr + i) = static_cast(randomNumber() * (std::numeric_limits::max() + 1.0)); + + Vector fontNameVector; + base64Encode(fontUuid, fontNameVector); + ASSERT(fontNameVector.size() < LF_FACESIZE); + String fontName(fontNameVector.data(), fontNameVector.size()); + return fontName.replace('/', '_'); +} + +FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer* buffer) +{ + if (g_customFontCache) { + String fontName = createUniqueFontName(); + RefPtr localBuffer = SharedBuffer::create(buffer->data(), buffer->size()); + if (renameFont(localBuffer.get(), fontName) && g_customFontCache->registerFont(fontName, localBuffer.get())) + return new FontCustomPlatformData(fontName); + } + return 0; +} + +bool FontCustomPlatformData::supportsFormat(const String& format) +{ + return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype"); +} + +} diff --git a/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h new file mode 100644 index 0000000..abdc0f2 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h @@ -0,0 +1,59 @@ +/* + * 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 "FontDescription.h" +#include "FontRenderingMode.h" +#include "PlatformString.h" +#include + +namespace WebCore { + + class FontPlatformData; + class CachedFont; + + class CustomFontCache { + public: + virtual bool registerFont(const String& fontName, const SharedBuffer*) = 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, FontOrientation fontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode); + + static bool supportsFormat(const String&); + + String m_name; + }; + + FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer*); + void setCustomFontCache(CustomFontCache*); +} + +#endif diff --git a/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp b/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp new file mode 100644 index 0000000..d9d8a72 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/FontPlatformData.cpp @@ -0,0 +1,534 @@ +/* + * 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 +#include + +#include +#include + +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 { +public: + LOGFONT m_font; + OwnPtr m_hfont; + TEXTMETRIC m_metrics; + DWORD m_codePages; + unsigned m_weight; + bool m_italic; + + static PassRefPtr 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(font.m_italic); + }; + return WTF::StringHasher::createBlobHash(hashCodes); + } + + static bool equal(const FixedSizeFontDataKey& a, const FixedSizeFontDataKey& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +struct FixedSizeFontDataKeyTraits : WTF::GenericHashTraits { + 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 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, FixedSizeFontDataKeyHash, FixedSizeFontDataKeyTraits> FixedSizeFontCache; +FixedSizeFontCache g_fixedSizeFontCache; + +PassRefPtr 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 createFixedSizeFontData(const AtomicString& family, unsigned weight, bool italic) +{ + FixedSizeFontDataKey key(family, weight, italic); + pair result = g_fixedSizeFontCache.add(key, RefPtr()); + 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 m_rootFontData; + AtomicString m_family; + FontDescription m_fontDescription; + OwnPtr 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/Source/WebCore/platform/graphics/wince/FontPlatformData.h b/Source/WebCore/platform/graphics/wince/FontPlatformData.h new file mode 100644 index 0000000..e73a7b2 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/FontPlatformData.h @@ -0,0 +1,93 @@ +/* + * 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 FontPlatformData_h +#define FontPlatformData_h + +#include "FontDescription.h" +#include "FontOrientation.h" +#include +#include +#include + +typedef struct tagTEXTMETRICW TEXTMETRIC; +typedef struct tagLOGFONTW LOGFONT; + +namespace WebCore { + + class FontPlatformPrivateData; + + 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(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); + + FontOrientation orientation() const { return Horizontal; } // FIXME: Implement. + +#ifndef NDEBUG + String description() const; +#endif + + private: + FontPlatformPrivateData* m_private; + }; + +} + +#endif diff --git a/Source/WebCore/platform/graphics/wince/FontWinCE.cpp b/Source/WebCore/platform/graphics/wince/FontWinCE.cpp new file mode 100644 index 0000000..d636517 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/FontWinCE.cpp @@ -0,0 +1,342 @@ +/* + * 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 "AffineTransform.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 "WidthIterator.h" +#include +#include +#include + +#include + +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 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; + } +} + +void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const +{ + notImplemented(); +} + +float Font::floatWidthForComplexText(const TextRun& run, HashSet* fallbackFonts, GlyphOverflow* glyphOverflow) const +{ + TextRunComponents components; + int w = generateComponents(&components, *this, run); + return w; +} + +int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const +{ + // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers + // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem. + int position = static_cast(xFloat); + + 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((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((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 FloatPoint& 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; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp b/Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp new file mode 100644 index 0000000..1c22f23 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp @@ -0,0 +1,78 @@ +/* + * 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; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/GradientWinCE.cpp b/Source/WebCore/platform/graphics/wince/GradientWinCE.cpp new file mode 100644 index 0000000..d735881 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/GradientWinCE.cpp @@ -0,0 +1,52 @@ +/* + * 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 "Gradient.h" + +#include "GraphicsContext.h" + +namespace WebCore { + +void Gradient::platformDestroy() +{ +} + +static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b) +{ + return a.stop < b.stop; +} + +const Vector& Gradient::getStops() const +{ + if (!m_stopsSorted) { + if (m_stops.size()) + std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); + m_stopsSorted = true; + } + return m_stops; +} + +void Gradient::fill(GraphicsContext* c, const FloatRect& r) +{ + c->fillRect(r, this); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp new file mode 100644 index 0000000..2def6ab --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp @@ -0,0 +1,1890 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile Inc. + * Copyright (C) 2010 Patrick Gansterer + * + * 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 "AffineTransform.h" +#include "CharacterNames.h" +#include "Font.h" +#include "GDIExtras.h" +#include "GlyphBuffer.h" +#include "Gradient.h" +#include "NotImplemented.h" +#include "Path.h" +#include "PlatformPathWinCE.h" +#include "SharedBitmap.h" +#include "SimpleFontData.h" +#include + +#include + +namespace WebCore { + +typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector& stops); +typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector& 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(d + 0.5); + + int i = static_cast(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 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 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(x), static_cast(y)); +} + +template 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 static inline IntRect mapRect(const IntRect& rect, const T& transform) +{ + return mapRect(rect, transform); +} + +template static inline FloatRect mapRect(const FloatRect& rect, const T& transform) +{ + return mapRect(rect, transform); +} + +class GraphicsContextPlatformPrivateData { +public: + GraphicsContextPlatformPrivateData() + : m_transform() + , m_opacity(1.0) + { + } + + AffineTransform m_transform; + float m_opacity; +}; + +enum AlphaPaintType { + AlphaPaintNone, + AlphaPaintImage, + AlphaPaintOther, +}; + +class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData { +public: + GraphicsContextPlatformPrivate(HDC dc) + : m_dc(dc) + { + } + ~GraphicsContextPlatformPrivate() + { + while (!m_backupData.isEmpty()) + restore(); + } + + 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 AffineTransform& 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(w), static_cast(h)); + } + + void save() + { + if (m_dc) + SaveDC(m_dc); + + m_backupData.append(*static_cast(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 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 bmp = SharedBitmap::create(origRect.size(), alphaPaint == AlphaPaintNone ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, 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 (alphaPaint == AlphaPaintOther && hasAlphaBlendSupport()) { + 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) && hasAlphaBlendSupport()) { + const BLENDFUNCTION blend = { AC_SRC_OVER, 0 + , m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255) + , alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA }; + bool success = alphaBlendIfSupported(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend); + ASSERT_UNUSED(success, success); + } else + StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY); + } + + HDC m_dc; + RefPtr m_bitmap; + Vector m_backupData; +}; + +static PassOwnPtr 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 adoptPtr(CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue()))); +} + +static inline PassOwnPtr createBrush(const Color& col) +{ + return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue()))); +} + +template 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(destBmp, sourceBmp, transform); + else + _rotateBitmap(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 m_bitmap; + RefPtr m_rotatedBitmap; + RECT m_bmpRect; + unsigned m_key; + 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::create(m_origRect.size(), m_rotatedBitmap->is16bit() ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, 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_key); + else + m_memDc = m_data->m_dc; +} + +TransparentLayerDC::~TransparentLayerDC() +{ + if (m_rotatedBitmap) { + m_bitmap->releaseDC(m_memDc, m_key); + m_key = 0; + rotateBitmap(m_rotatedBitmap.get(), m_bitmap.get(), m_rotation); + m_memDc = m_rotatedBitmap->getDC(&m_key); + m_data->paintBackTransparentLayerBitmap(m_memDc, m_rotatedBitmap.get(), m_rotatedOrigRect, m_alphaPaintType, m_bmpRect); + m_rotatedBitmap->releaseDC(m_memDc, m_key); + } else if (m_bitmap) { + m_data->paintBackTransparentLayerBitmap(m_memDc, m_bitmap.get(), m_origRect, m_alphaPaintType, m_bmpRect); + m_bitmap->releaseDC(m_memDc, m_key); + } + 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_key); + } + ~ScopeDCProvider() + { + if (m_data->m_bitmap) { + m_data->m_bitmap->releaseDC(m_data->m_dc, m_key); + m_data->m_dc = 0; + } + } +private: + GraphicsContextPlatformPrivate* m_data; + unsigned m_key; +}; + + +void GraphicsContext::platformInit(PlatformGraphicsContext* dc) +{ + m_data = new GraphicsContextPlatformPrivate(dc); +} + +void GraphicsContext::platformDestroy() +{ + delete m_data; +} + +void GraphicsContext::setBitmap(PassRefPtr bmp) +{ + ASSERT(!m_data->m_dc); + m_data->m_bitmap = bmp; +} + +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + // FIXME: Add support for AlphaBlend. + ASSERT(!supportAlphaBlend); + return m_data->m_dc; +} + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ +} + +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()); + + OwnPtr brush; + HGDIOBJ oldBrush; + if (fillColor().alpha()) { + brush = createBrush(fillColor()); + oldBrush = SelectObject(dc, brush.get()); + } else + oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); + + OwnPtr pen; + HGDIOBJ oldPen; + if (strokeStyle() != NoStroke) { + pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + oldPen = SelectObject(dc, pen.get()); + } else + oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); + + if (brush || pen) { + if (trRect.width() <= 0) + trRect.setWidth(1); + if (trRect.height() <= 0) + trRect.setHeight(1); + + Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + } + + SelectObject(dc, oldPen); + SelectObject(dc, oldBrush); +} + +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(); + + OwnPtr pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); + + MoveToEx(dc, trPoint1.x(), trPoint1.y(), 0); + LineTo(dc, trPoint2.x(), trPoint2.y()); + + SelectObject(dc, oldPen); +} + +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()); + + OwnPtr brush; + HGDIOBJ oldBrush; + if (fillColor().alpha()) { + brush = createBrush(fillColor()); + oldBrush = SelectObject(dc, brush.get()); + } else + oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); + + OwnPtr pen; + HGDIOBJ oldPen = 0; + if (strokeStyle() != NoStroke) { + pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + oldPen = SelectObject(dc, pen.get()); + } else + oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); + + if (brush || pen) + Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + + SelectObject(dc, oldPen); + SelectObject(dc, oldBrush); +} + +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()); + + OwnPtr pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); + + 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 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); +} + +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 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(); + } + + OwnPtr brush; + HGDIOBJ oldBrush; + if (fillColor().alpha()) { + brush = createBrush(fillColor()); + oldBrush = SelectObject(dc, brush.get()); + } else + oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); + + OwnPtr pen; + HGDIOBJ oldPen; + if (strokeStyle() != NoStroke) { + pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + oldPen = SelectObject(dc, pen.get()); + } else + oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); + + if (brush || pen) + Polygon(dc, winPoints.data(), npoints); + + SelectObject(dc, oldPen); + SelectObject(dc, oldBrush); +} + +void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased) +{ + if (paintingDisabled()) + return; + + if (numPoints <= 1) + return; + + // FIXME: IMPLEMENT!! +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) +{ + 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(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 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 Path& path, int width, int offset, const Color& color) +{ + // FIXME: implement +} + +void GraphicsContext::drawFocusRing(const Vector& rects, int width, int offset, const Color& color) +{ + if (!m_data->m_opacity || paintingDisabled()) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + int radius = (width - 1) / 2; + offset += radius; + + 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::drawLineForTextChecking(const IntPoint&, int width, TextCheckingLineStyle style) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) +{ + 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), ColorSpaceDeviceRGB); +} + +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()); + + OwnPtr pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); + + 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); +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + m_data->save(); + m_data->m_opacity *= opacity; +} + +void GraphicsContext::endTransparencyLayer() +{ + m_data->restore(); +} + +void GraphicsContext::concatCTM(const AffineTransform& transform) +{ + m_data->concatCTM(transform); +} + +AffineTransform& GraphicsContext::affineTransform() +{ + return m_data->m_transform; +} + +const AffineTransform& 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); +} + +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::setPlatformCompositeOperation(CompositeOperator op) +{ + notImplemented(); +} + +void GraphicsContext::clip(const Path& path) +{ + notImplemented(); +} + +void GraphicsContext::canvasClip(const Path& path) +{ + clip(path); +} + +void GraphicsContext::clipOut(const Path&) +{ + 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, ColorSpace colorSpace) +{ + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + FloatSize shadowOffset; + float shadowBlur = 0; + Color shadowColor; + ColorSpace shadowColorSpace; + + getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace); + + IntRect dstRect = fillRect; + + dstRect.move(stableRound(shadowOffset.width()), stableRound(shadowOffset.height())); + dstRect.inflate(stableRound(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; + + OwnPtr brush = createBrush(shadowColor); + HGDIOBJ oldBrush = SelectObject(dc, brush.get()); + + 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 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); +} + + +void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height) +{ + if (!dc) + return; + + OwnPtr 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& 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(const Path& path) +{ + Color c = m_state.fillGradient + ? gradientAverageColor(m_state.fillGradient.get()) + : fillColor(); + + if (!c.alpha() || !m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + OwnPtr brush = createBrush(c); + + if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { + IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect())); + trRect.inflate(1); + TransparentLayerDC transparentDC(m_data, trRect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + + AffineTransform tr = m_data->m_transform; + tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); + + SelectObject(dc, GetStockObject(NULL_PEN)); + HGDIOBJ oldBrush = SelectObject(dc, brush.get()); + path.platformPath()->fillPath(dc, &tr); + SelectObject(dc, oldBrush); + } else { + SelectObject(m_data->m_dc, GetStockObject(NULL_PEN)); + HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get()); + path.platformPath()->fillPath(m_data->m_dc, &m_data->m_transform); + SelectObject(m_data->m_dc, oldBrush); + } +} + + +void GraphicsContext::strokePath(const Path& path) +{ + if (!m_data->m_opacity) + return; + + ScopeDCProvider dcProvider(m_data); + if (!m_data->m_dc) + return; + + OwnPtr pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + + if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { + IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect())); + trRect.inflate(1); + TransparentLayerDC transparentDC(m_data, trRect); + HDC dc = transparentDC.hdc(); + if (!dc) + return; + + AffineTransform tr = m_data->m_transform; + tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); + + SelectObject(dc, GetStockObject(NULL_BRUSH)); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); + path.platformPath()->strokePath(dc, &tr); + SelectObject(dc, oldPen); + } else { + SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH)); + HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get()); + path.platformPath()->strokePath(m_data->m_dc, &m_data->m_transform); + SelectObject(m_data->m_dc, oldPen); + } +} + +void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient) +{ + if (!m_data->m_opacity) + return; + + const Vector& 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, ColorSpaceDeviceRGB); + 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->startRadius() * scale; + float r1 = gradient->endRadius() * 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 tv; + tv.resize(numRects * 2); + Vector 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 = fabs(d.height()) > fabs(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); +} + +AffineTransform GraphicsContext::getCTM() const +{ + return m_data->m_transform; +} + +void GraphicsContext::fillRect(const FloatRect& rect) +{ + savePlatformState(); + + if (m_state.fillGradient) + fillRect(rect, m_state.fillGradient.get()); + else + fillRect(rect, fillColor(), ColorSpaceDeviceRGB); + + restorePlatformState(); +} + +void GraphicsContext::setPlatformShadow(const FloatSize&, float, const Color&, ColorSpace) +{ + notImplemented(); +} + +void GraphicsContext::clearPlatformShadow() +{ + notImplemented(); +} + +InterpolationQuality GraphicsContext::imageInterpolationQuality() const +{ + notImplemented(); + return InterpolationDefault; +} + +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 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; + HDC memDC = bmp->getDC(&key1); + if (memDC) { + m_data->paintBackTransparentLayerBitmap(memDC, bmp.get(), trRect, alphaPaintType, bmpRect); + bmp->releaseDC(memDC, key1); + } + } + + 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(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; + } + + FloatSize shadowOffset; + float shadowBlur = 0; + Color shadowColor; + ColorSpace shadowColorSpace; + bool hasShadow = textDrawingMode() == TextModeFill + && getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace) + && shadowColor.alpha(); + COLORREF shadowRGBColor; + FloatPoint trShadowPoint; + if (hasShadow) { + shadowRGBColor = RGB(shadowColor.red(), shadowColor.green(), shadowColor.blue()); + trShadowPoint = m_data->mapPoint(startPoint + shadowOffset); + } + + 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 glyphSpace(numGlyphs); + Vector 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 bmp = SharedBitmap::create(IntSize(boxWidthBest, boxHeightBest), BitmapInfo::BitCount16, 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(((state & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1)); +} + +void GraphicsContext::drawBitmap(SharedBitmap* bmp, const IntRect& dstRectIn, const IntRect& srcRect, ColorSpace styleColorSpace, 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 AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, 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()); + AffineTransform transform = m_data->m_transform; + transform.translate(moved.width(), moved.height()); + + bmp->drawPattern(dc, transform, tileRectIn, patternTransform, phase, styleColorSpace, 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(const Path&, WindRule) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/ImageBufferData.h b/Source/WebCore/platform/graphics/wince/ImageBufferData.h new file mode 100644 index 0000000..01b7d06 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/ImageBufferData.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#ifndef ImageBufferData_h +#define ImageBufferData_h + +namespace WebCore { + + class IntSize; + class ImageBufferData { + public: + ImageBufferData(const IntSize& size); + RefPtr m_bitmap; + }; + +} // namespace WebCore + +#endif // ImageBufferData_h diff --git a/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp b/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp new file mode 100644 index 0000000..537d27d --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. 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 "ImageBuffer.h" + +#include "Base64.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "ImageData.h" +#include "NotImplemented.h" +#include "SharedBitmap.h" +#include "UnusedParam.h" +#include + +namespace WebCore { + +class BufferedImage: public Image { + +public: + BufferedImage(const ImageBufferData* data) + : m_data(data) + { + } + + virtual IntSize size() const { return IntSize(m_data->m_bitmap->width(), m_data->m_bitmap->height()); } + virtual void destroyDecodedData(bool destroyAll = true) {} + virtual unsigned decodedSize() const { return 0; } + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); + + const ImageBufferData* m_data; +}; + +void BufferedImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) +{ + IntRect intDstRect = enclosingIntRect(dstRect); + IntRect intSrcRect(srcRect); + m_data->m_bitmap->draw(ctxt, intDstRect, intSrcRect, styleColorSpace, compositeOp); +} + +void BufferedImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) +{ + m_data->m_bitmap->drawPattern(ctxt, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, size()); +} + +ImageBufferData::ImageBufferData(const IntSize& size) + : m_bitmap(SharedBitmap::create(size, BitmapInfo::BitCount32, false)) +{ + // http://www.w3.org/TR/2009/WD-html5-20090212/the-canvas-element.html#canvaspixelarray + // "When the canvas is initialized it must be set to fully transparent black." + m_bitmap->resetPixels(true); + m_bitmap->setHasAlpha(true); +} + +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, RenderingMode, bool& success) + : m_data(size) + , m_size(size) +{ + // FIXME: colorSpace is not used + UNUSED_PARAM(colorSpace); + + m_context.set(new GraphicsContext(0)); + m_context->setBitmap(m_data.m_bitmap); + success = true; +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + return m_context.get(); +} + +bool ImageBuffer::drawsUsingCopy() const +{ + return true; +} + +PassRefPtr ImageBuffer::copyImage() const +{ + return adoptRef(new BufferedImage(&m_data)); +} + +void ImageBuffer::clip(GraphicsContext*, const FloatRect&) const +{ + notImplemented(); +} + +void ImageBuffer::draw(GraphicsContext* context, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, + CompositeOperator op , bool useLowQualityScale) +{ + RefPtr imageCopy = copyImage(); + context->drawImage(imageCopy.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); +} + +void ImageBuffer::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) +{ + RefPtr imageCopy = copyImage(); + imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect); +} + +template +static PassRefPtr getImageData(const IntRect& rect, const SharedBitmap* bitmap) +{ + RefPtr imageData = ByteArray::create(rect.width() * rect.height() * 4); + + const unsigned char* src = static_cast(bitmap->bytes()); + if (!src) + return imageData.release(); + + IntRect sourceRect(0, 0, bitmap->width(), bitmap->height()); + sourceRect.intersect(rect); + if (sourceRect.isEmpty()) + return imageData.release(); + + unsigned char* dst = imageData->data(); + memset(dst, 0, imageData->length()); + src += (sourceRect.y() * bitmap->width() + sourceRect.x()) * 4; + dst += ((sourceRect.y() - rect.y()) * rect.width() + sourceRect.x() - rect.x()) * 4; + int bytesToCopy = sourceRect.width() * 4; + int srcSkip = (bitmap->width() - sourceRect.width()) * 4; + int dstSkip = (rect.width() - sourceRect.width()) * 4; + const unsigned char* dstEnd = dst + sourceRect.height() * rect.width() * 4; + while (dst < dstEnd) { + const unsigned char* dstRowEnd = dst + bytesToCopy; + while (dst < dstRowEnd) { + // Convert ARGB little endian to RGBA big endian + int blue = *src++; + int green = *src++; + int red = *src++; + int alpha = *src++; + if (premultiplied) { + *dst++ = static_cast((red * alpha + 254) / 255); + *dst++ = static_cast((green * alpha + 254) / 255); + *dst++ = static_cast((blue * alpha + 254) / 255); + *dst++ = static_cast(alpha); + } else { + *dst++ = static_cast(red); + *dst++ = static_cast(green); + *dst++ = static_cast(blue); + *dst++ = static_cast(alpha); + ++src; + } + } + src += srcSkip; + dst += dstSkip; + } + + return imageData.release(); +} + +PassRefPtr ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData(rect, m_data.m_bitmap.get()); +} + +PassRefPtr ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData(rect, m_data.m_bitmap.get()); +} + +template +static void putImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, SharedBitmap* bitmap) +{ + unsigned char* dst = (unsigned char*)bitmap->bytes(); + if (!dst) + return; + + IntRect destRect(destPoint, sourceRect.size()); + destRect.intersect(IntRect(0, 0, bitmap->width(), bitmap->height())); + + if (destRect.isEmpty()) + return; + + const unsigned char* src = source->data(); + dst += (destRect.y() * bitmap->width() + destRect.x()) * 4; + src += (sourceRect.y() * sourceSize.width() + sourceRect.x()) * 4; + int bytesToCopy = destRect.width() * 4; + int dstSkip = (bitmap->width() - destRect.width()) * 4; + int srcSkip = (sourceSize.width() - destRect.width()) * 4; + const unsigned char* dstEnd = dst + destRect.height() * bitmap->width() * 4; + while (dst < dstEnd) { + const unsigned char* dstRowEnd = dst + bytesToCopy; + while (dst < dstRowEnd) { + // Convert RGBA big endian to ARGB little endian + int red = *src++; + int green = *src++; + int blue = *src++; + int alpha = *src++; + if (premultiplied) { + *dst++ = static_cast(blue * 255 / alpha); + *dst++ = static_cast(green * 255 / alpha); + *dst++ = static_cast(red * 255 / alpha); + *dst++ = static_cast(alpha); + } else { + *dst++ = static_cast(blue); + *dst++ = static_cast(green); + *dst++ = static_cast(red); + *dst++ = static_cast(alpha); + } + } + src += srcSkip; + dst += dstSkip; + } +} + +void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData(source, sourceSize, sourceRect, destPoint, m_data.m_bitmap.get()); +} + +void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData(source, sourceSize, sourceRect, destPoint, m_data.m_bitmap.get()); +} + +void ImageBuffer::platformTransformColorSpace(const Vector& lookUpTable) +{ + UNUSED_PARAM(lookUpTable); + notImplemented(); +} + +String ImageBuffer::toDataURL(const String& mimeType, const double*) const +{ + if (!m_data.m_bitmap->bytes()) + return "data:,"; + + notImplemented(); + return String(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp b/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp new file mode 100644 index 0000000..c0b2b53 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/ImageWinCE.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile Inc. + * Copyright (C) 2010 Patrick Gansterer + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" + +#include "BitmapImage.h" +#include "GraphicsContext.h" +#include "ImageDecoder.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include "SharedBuffer.h" +#include "TransformationMatrix.h" +#include "WinceGraphicsExtras.h" +#include + +#include + +namespace WebCore { + +NativeImagePtr RGBA32Buffer::asNewNativeImage() const +{ + return SharedBitmap::create(m_backingStore, m_size, hasAlpha()); +} + +bool FrameData::clear(bool clearMetaData) +{ + if (clearMetaData) + m_haveMetadata = false; + + if (m_frame) { + m_frame = 0; + return true; + } + + return false; +} + +bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) +{ + if (!bmp) + return false; + + BITMAP bmpInfo; + GetObject(bmp, sizeof(BITMAP), &bmpInfo); + + ASSERT(bmpInfo.bmBitsPixel == 32); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + + OwnPtr hdc(CreateCompatibleDC(0)); + HGDIOBJ hOldBmp = SelectObject(hdc.get(), bmp); + + { + GraphicsContext gc(hdc.get()); + + IntSize imageSize = BitmapImage::size(); + if (size) + drawFrameMatchingSourceSize(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy); + else + draw(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0, 0, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy); + } + + SelectObject(hdc.get(), hOldBmp); + + return true; +} + +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) +{ + int frames = frameCount(); + for (int i = 0; i < frames; ++i) { + RefPtr bmp = frameAtIndex(i); + if (!bmp || bmp->height() != static_cast(srcSize.height()) || bmp->width() != static_cast(srcSize.width())) + continue; + + size_t currentFrame = m_currentFrame; + m_currentFrame = i; + draw(ctxt, dstRect, FloatRect(0, 0, srcSize.width(), srcSize.height()), styleColorSpace, compositeOp); + m_currentFrame = currentFrame; + return; + } + + // No image of the correct size was found, fallback to drawing the current frame + IntSize imageSize = BitmapImage::size(); + draw(ctxt, dstRect, FloatRect(0, 0, imageSize.width(), imageSize.height()), styleColorSpace, compositeOp); +} + +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRectIn, ColorSpace styleColorSpace, CompositeOperator compositeOp) +{ + if (!m_source.initialized()) + return; + + if (mayFillWithSolidColor()) + fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, compositeOp); + else { + IntRect intSrcRect(srcRectIn); + RefPtr bmp = frameAtIndex(m_currentFrame); + + if (bmp->width() != m_source.size().width()) { + double scaleFactor = static_cast(bmp->width()) / m_source.size().width(); + + intSrcRect.setX(stableRound(srcRectIn.x() * scaleFactor)); + intSrcRect.setWidth(stableRound(srcRectIn.width() * scaleFactor)); + intSrcRect.setY(stableRound(srcRectIn.y() * scaleFactor)); + intSrcRect.setHeight(stableRound(srcRectIn.height() * scaleFactor)); + } + bmp->draw(ctxt, enclosingIntRect(dstRect), intSrcRect, styleColorSpace, compositeOp); + } + + startAnimation(); +} + +void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) +{ + notImplemented(); +} + +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) +{ + RefPtr bmp = nativeImageForCurrentFrame(); + if (!bmp) + return; + + bmp->drawPattern(ctxt, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, m_source.size()); +} + +void BitmapImage::checkForSolidColor() +{ + if (m_checkedForSolidColor) + return; + + if (frameCount() != 1) { + m_isSolidColor = false; + m_checkedForSolidColor = true; + return; + } + + RefPtr bmp = frameAtIndex(0); + if (!bmp || !bmp->validHeight()) { + m_isSolidColor = false; + return; + } + + if (bmp->width() != 1 || bmp->validHeight() != 1) { + m_isSolidColor = false; + m_checkedForSolidColor = true; + return; + } + + m_isSolidColor = true; + + if (bmp->is16bit()) { + unsigned short c = ((unsigned short *)bmp->bytes())[0]; + int r = (c >> 7) & 0xF8; + int g = (c >> 2) & 0xF8; + int b = (c << 3) & 0xF8; + if (bmp->usesTransparentColor() && bmp->transparentColor() == RGB(r, g, b)) + m_solidColor = Color(r, g, b, 0); + else + m_solidColor = Color(r, g, b); + } else { + unsigned c = ((unsigned *)bmp->bytes())[0]; + m_solidColor = Color(c); + } + + if (bmp->validHeight() == bmp->height()) + m_checkedForSolidColor = true; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h b/Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h new file mode 100644 index 0000000..f49d8e2 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayerPrivateWinCE_h +#define MediaPlayerPrivateWinCE_h + +#if ENABLE(VIDEO) + +#include +#include "MediaPlayerPrivate.h" +#include "Timer.h" +#include + +namespace WebCore { + + class GraphicsContext; + class IntSize; + class IntRect; + + class MediaPlayerPrivate : public MediaPlayerPrivateInterface { + public: + static void registerMediaEngine(MediaEngineRegistrar); + + ~MediaPlayerPrivate(); + + IntSize naturalSize() const; + bool hasVideo() const; + + void load(const String& url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + + void setRate(float); + void setVolume(float); + + MediaPlayer::NetworkState networkState() const { return m_networkState; } + MediaPlayer::ReadyState readyState() const { return m_readyState; } + + PassRefPtr buffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setSize(const IntSize&); + + void loadStateChanged(); + void didEnd(); + + void paint(GraphicsContext*, const IntRect&); + + private: + MediaPlayerPrivate(MediaPlayer*); + + void updateStates(); + void doSeek(); + void cancelSeek(); + void seekTimerFired(Timer*); + float maxTimeLoaded() const; + void sawUnsupportedTracks(); +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + void setMediaPlayerProxy(WebMediaPlayerProxy*); + void setPoster(const String& url); + void deliverNotification(MediaPlayerProxyNotificationType); +#endif + + // engine support + static MediaPlayerPrivateInterface* create(MediaPlayer*); + static void getSupportedTypes(HashSet& types); + static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static bool isAvailable(); + + MediaPlayer* m_player; + float m_seekTo; + float m_endTime; + Timer m_seekTimer; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; + bool m_startedPlaying; + bool m_isStreaming; +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + WebMediaPlayerProxy* m_proxy; +#endif + }; + +} + +#endif // ENABLE(VIDEO) + +#endif // MediaPlayerPrivateWinCE_h diff --git a/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp new file mode 100644 index 0000000..6fb262d --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp @@ -0,0 +1,145 @@ +/* + * 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. + */ + +#if ENABLE(VIDEO) + +#include "config.h" +#include "MediaPlayerProxy.h" + +#include "Bridge.h" +#include "DocumentLoader.h" +#include "HTMLPlugInElement.h" +#include "HTMLVideoElement.h" +#include "JSDOMBinding.h" +#include "JSPluginElementFunctions.h" +#include "MediaPlayer.h" +#include "Node.h" +#include "PlatformString.h" +#include "PluginView.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "Widget.h" +#include "c_class.h" +#include "c_instance.h" +#include "c_runtime.h" +#include "npruntime_impl.h" +#include + +using namespace JSC; + +namespace WebCore { + +using namespace Bindings; +using namespace HTMLNames; + +WebMediaPlayerProxy::WebMediaPlayerProxy(MediaPlayer* player) + : m_mediaPlayer(player) + , m_init(false) + , m_hasSentResponseToPlugin(false) +{ + if (!m_init) + initEngine(); +} + +WebMediaPlayerProxy::~WebMediaPlayerProxy() +{ + m_instance.release(); +} + +ScriptInstance WebMediaPlayerProxy::pluginInstance() +{ + if (!m_instance) { + RenderObject* r = element()->renderer(); + if (!r || !r->isWidget()) + return 0; + + Frame* frame = element()->document()->frame(); + + RenderWidget* renderWidget = static_cast(element()->renderer()); + if (renderWidget && renderWidget->widget()) + m_instance = frame->script()->createScriptInstanceForWidget(renderWidget->widget()); + } + + return m_instance; +} + +void WebMediaPlayerProxy::load(const String& url) +{ + if (!m_init) + initEngine(); + if (m_init) + invokeMethod("play"); +} + +void WebMediaPlayerProxy::initEngine() +{ + HTMLMediaElement* element = static_cast(m_mediaPlayer->mediaPlayerClient()); + String url = element->initialURL(); + + if (url.isEmpty()) + return; + + Frame* frame = element->document()->frame(); + Vector paramNames; + Vector paramValues; + String serviceType; + + // add all attributes set on the embed object + if (NamedNodeMap* attributes = element->attributes()) { + for (unsigned i = 0; i < attributes->length(); ++i) { + Attribute* it = attributes->attributeItem(i); + paramNames.append(it->name().localName().string()); + paramValues.append(it->value().string()); + } + } + serviceType = "application/x-mplayer2"; + frame->loader()->subframeLoader()->requestObject(static_cast(element->renderer()), url, nullAtom, serviceType, paramNames, paramValues); + m_init = true; + +} + +HTMLMediaElement* WebMediaPlayerProxy::element() +{ + return static_cast(m_mediaPlayer->mediaPlayerClient()); + +} + +void WebMediaPlayerProxy::invokeMethod(const String& methodName) +{ + Frame* frame = element()->document()->frame(); + RootObject *root = frame->script()->bindingRootObject(); + if (!root) + return; + ExecState *exec = root->globalObject()->globalExec(); + Instance* instance = pluginInstance().get(); + if (!instance) + return; + + instance->begin(); + Class *aClass = instance->getClass(); + Identifier iden(exec, methodName); + MethodList methodList = aClass->methodsNamed(iden, instance); + ArgList args; + instance->invokeMethod(exec, methodList , args); + instance->end(); +} + +} + +#endif diff --git a/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h new file mode 100644 index 0000000..b02e0f4 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + + +#ifndef MediaPlayerProxy_h +#define MediaPlayerProxy_h + +#if ENABLE(VIDEO) + +#include +#include "ScriptInstance.h" + +namespace WebCore { + + class IntRect; + class IntSize; + class MediaPlayer; + class PluginView; + class HTMLMediaElement; + + enum MediaPlayerProxyNotificationType { + MediaPlayerNotificationPlayPauseButtonPressed, + Idle, + Loading, + Loaded, + FormatError, + NetworkError, + DecodeError + }; + + class WebMediaPlayerProxy { + public: + WebMediaPlayerProxy(MediaPlayer* player); + ~WebMediaPlayerProxy(); + + MediaPlayer* mediaPlayer() {return m_mediaPlayer;} + void initEngine(); + void load(const String& url); + HTMLMediaElement* element(); + void invokeMethod(const String& methodName); + ScriptInstance pluginInstance(); + + private: + MediaPlayer* m_mediaPlayer; + bool m_init; + WebCore::PluginView* m_pluginView; + bool m_hasSentResponseToPlugin; + ScriptInstance m_instance; + }; + +} +#endif // ENABLE(VIDEO) + +#endif diff --git a/Source/WebCore/platform/graphics/wince/PathWinCE.cpp b/Source/WebCore/platform/graphics/wince/PathWinCE.cpp new file mode 100644 index 0000000..fa4c8fb --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/PathWinCE.cpp @@ -0,0 +1,163 @@ +/* + * 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 "Path.h" + +#include "AffineTransform.h" +#include "FloatRect.h" +#include "NotImplemented.h" +#include "PlatformPathWinCE.h" +#include "PlatformString.h" +#include + +namespace WebCore { + +Path::Path() + : m_path(new PlatformPath()) +{ +} + +Path::Path(const Path& other) + : m_path(new PlatformPath(*other.m_path)) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path& Path::operator=(const Path& other) +{ + if (&other != this) { + delete m_path; + m_path = new PlatformPath(*other.m_path); + } + return *this; +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + return m_path->contains(point, rule); +} + +void Path::translate(const FloatSize& size) +{ + m_path->translate(size); +} + +FloatRect Path::boundingRect() const +{ + return m_path->boundingRect(); +} + +void Path::moveTo(const FloatPoint& point) +{ + m_path->moveTo(point); +} + +void Path::addLineTo(const FloatPoint& point) +{ + m_path->addLineTo(point); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + m_path->addQuadCurveTo(cp, p); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + m_path->addBezierCurveTo(cp1, cp2, p); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + m_path->addArcTo(p1, p2, radius); +} + +void Path::closeSubpath() +{ + m_path->closeSubpath(); +} + +void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise) +{ + m_path->addEllipse(p, r, r, sar, ear, anticlockwise); +} + +void Path::addRect(const FloatRect& r) +{ + m_path->addRect(r); +} + +void Path::addEllipse(const FloatRect& r) +{ + m_path->addEllipse(r); +} + +void Path::clear() +{ + m_path->clear(); +} + +bool Path::isEmpty() const +{ + return m_path->isEmpty(); +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + m_path->apply(info, function); +} + +void Path::transform(const AffineTransform& t) +{ + m_path->transform(t); +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier *) +{ + notImplemented(); + return FloatRect(); +} + +bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const +{ + notImplemented(); + return false; +} + +bool Path::hasCurrentPoint() const +{ + // Not sure if this is correct. At the meantime, we do what other ports + // do. + // See https://bugs.webkit.org/show_bug.cgi?id=27266, + // https://bugs.webkit.org/show_bug.cgi?id=27187, and + // http://trac.webkit.org/changeset/45873 + return !isEmpty(); +} + +FloatPoint Path::currentPoint() const +{ + return m_path->lastPoint(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp new file mode 100644 index 0000000..8534f89 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp @@ -0,0 +1,772 @@ +/* + * 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 "PlatformPathWinCE.h" + +#include "AffineTransform.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Path.h" +#include "PlatformString.h" +#include "WinCEGraphicsExtras.h" +#include +#include + +#include + +namespace WebCore { + +// Implemented in GraphicsContextWinCE.cpp +void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y); + +static void quadCurve(int segments, Vector& pts, const PathPoint* control) +{ + const float step = 1.0 / segments; + register float tA = 0.0; + register float tB = 1.0; + + float c1x = control[0].x(); + float c1y = control[0].y(); + float c2x = control[1].x(); + float c2y = control[1].y(); + float c3x = control[2].x(); + float c3y = control[2].y(); + + const int offset = pts.size(); + pts.resize(offset + segments); + PathPoint pp; + pp.m_x = c1x; + pp.m_y = c1y; + + for (int i = 1; i < segments; ++i) { + tA += step; + tB -= step; + + const float a = tB * tB; + const float b = 2.0 * tA * tB; + const float c = tA * tA; + + pp.m_x = c1x * a + c2x * b + c3x * c; + pp.m_y = c1y * a + c2y * b + c3y * c; + + pts[offset + i - 1] = pp; + } + + pp.m_x = c3x; + pp.m_y = c3y; + pts[offset + segments - 1] = pp; +} + +static inline void bezier(int segments, Vector& pts, const PathPoint* control) +{ + const float step = 1.0 / segments; + register float tA = 0.0; + register float tB = 1.0; + + float c1x = control[0].x(); + float c1y = control[0].y(); + float c2x = control[1].x(); + float c2y = control[1].y(); + float c3x = control[2].x(); + float c3y = control[2].y(); + float c4x = control[3].x(); + float c4y = control[3].y(); + + const int offset = pts.size(); + pts.resize(offset + segments); + PathPoint pp; + pp.m_x = c1x; + pp.m_y = c1y; + + for (int i = 1; i < segments; ++i) { + tA += step; + tB -= step; + const float tAsq = tA * tA; + const float tBsq = tB * tB; + + const float a = tBsq * tB; + const float b = 3.0 * tA * tBsq; + const float c = 3.0 * tB * tAsq; + const float d = tAsq * tA; + + pp.m_x = c1x * a + c2x * b + c3x * c + c4x * d; + pp.m_y = c1y * a + c2y * b + c3y * c + c4y * d; + + pts[offset + i - 1] = pp; + } + + pp.m_x = c4x; + pp.m_y = c4y; + pts[offset + segments - 1] = pp; +} + +static bool containsPoint(const FloatRect& r, const FloatPoint& p) +{ + return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.right() && p.y() < r.bottom(); +} + +static void normalizeAngle(float& angle) +{ + angle = fmod(angle, 2 * piFloat); + if (angle < 0) + angle += 2 * piFloat; + if (angle < 0.00001f) + angle = 0; +} + +static void transformArcPoint(float& x, float& y, const FloatPoint& c) +{ + x += c.x(); + y += c.y(); +} + +static void inflateRectToContainPoint(FloatRect& r, float x, float y) +{ + if (r.isEmpty()) { + r.setX(x); + r.setY(y); + r.setSize(FloatSize(1, 1)); + return; + } + if (x < r.x()) { + r.setWidth(r.right() - x); + r.setX(x); + } else { + float w = x - r.x() + 1; + if (w > r.width()) + r.setWidth(w); + } + if (y < r.y()) { + r.setHeight(r.bottom() - y); + r.setY(y); + } else { + float h = y - r.y() + 1; + if (h > r.height()) + r.setHeight(h); + } +} + +// return 0-based value: 0 - first Quadrant ( 0 - 90 degree) +static inline int quadrant(const PathPoint& point, const PathPoint& origin) +{ + return point.m_x < origin.m_x ? + (point.m_y < origin.m_y ? 2 : 1) + : (point.m_y < origin.m_y ? 3 : 0); +} + +static inline bool isQuadrantOnLeft(int q) { return q == 1 || q == 2; } +static inline bool isQuadrantOnRight(int q) { return q == 0 || q == 3; } +static inline bool isQuadrantOnTop(int q) { return q == 2 || q == 3; } +static inline bool isQuadrantOnBottom(int q) { return q == 0 || q == 1; } + +static inline int nextQuadrant(int q) { return q == 3 ? 0 : q + 1; } +static inline int quadrantDiff(int q1, int q2) +{ + int d = q1 - q2; + while (d < 0) + d += 4; + return d; +} + +struct PathVector { + float m_x; + float m_y; + + PathVector() : m_x(0), m_y(0) {} + PathVector(float x, float y) : m_x(x), m_y(y) {} + double angle() const { return atan2(m_y, m_x); } + operator double () const { return angle(); } + double length() const { return _hypot(m_x, m_y); } +}; + +PathVector operator-(const PathPoint& p1, const PathPoint& p2) +{ + return PathVector(p1.m_x - p2.m_x, p1.m_y - p2.m_y); +} + +static void addArcPoint(PathPolygon& poly, const PathPoint& center, const PathPoint& radius, double angle) +{ + PathPoint p; + getEllipsePointByAngle(angle, radius.m_x, radius.m_y, p.m_x, p.m_y); + transformArcPoint(p.m_x, p.m_y, center); + if (poly.isEmpty() || poly.last() != p) + poly.append(p); +} + +static void addArcPoints(PathPolygon& poly, const PlatformPathElement::ArcTo& data) +{ + const PathPoint& startPoint = poly.last(); + double curAngle = startPoint - data.m_center; + double endAngle = data.m_end - data.m_center; + double angleStep = 2. / std::max(data.m_radius.m_x, data.m_radius.m_y); + if (data.m_clockwise) { + if (endAngle <= curAngle || startPoint == data.m_end) + endAngle += 2 * piDouble; + } else { + angleStep = -angleStep; + if (endAngle >= curAngle || startPoint == data.m_end) + endAngle -= 2 * piDouble; + } + + for (curAngle += angleStep; data.m_clockwise ? curAngle < endAngle : curAngle > endAngle; curAngle += angleStep) + addArcPoint(poly, data.m_center, data.m_radius, curAngle); + + if (poly.isEmpty() || poly.last() != data.m_end) + poly.append(data.m_end); +} + +static void drawPolygons(HDC dc, const Vector& polygons, bool fill, const AffineTransform* transformation) +{ + for (Vector::const_iterator i = polygons.begin(); i != polygons.end(); ++i) { + int npoints = i->size(); + if (!npoints) + continue; + + POINT* winPoints = 0; + if (fill) { + if (npoints > 2) + winPoints = new POINT[npoints + 1]; + } else + winPoints = new POINT[npoints]; + + if (winPoints) { + if (transformation) { + for (int i2 = 0; i2 < npoints; ++i2) { + FloatPoint trPoint = transformation->mapPoint(i->at(i2)); + winPoints[i2].x = stableRound(trPoint.x()); + winPoints[i2].y = stableRound(trPoint.y()); + } + } else { + for (int i2 = 0; i2 < npoints; ++i2) { + winPoints[i2].x = stableRound(i->at(i2).x()); + winPoints[i2].y = stableRound(i->at(i2).y()); + } + } + + if (fill && winPoints[npoints - 1] != winPoints[0]) { + winPoints[npoints].x = winPoints[0].x; + winPoints[npoints].y = winPoints[0].y; + ++npoints; + } + + if (fill) + ::Polygon(dc, winPoints, npoints); + else + ::Polyline(dc, winPoints, npoints); + delete[] winPoints; + } + } +} + + +int PlatformPathElement::numControlPoints() const +{ + switch (m_type) { + case PathMoveTo: + case PathLineTo: + return 1; + case PathQuadCurveTo: + case PathArcTo: + return 2; + case PathBezierCurveTo: + return 3; + default: + ASSERT(m_type == PathCloseSubpath); + return 0; + } +} + +int PlatformPathElement::numPoints() const +{ + switch (m_type) { + case PathMoveTo: + case PathLineTo: + case PathArcTo: + return 1; + case PathQuadCurveTo: + return 2; + case PathBezierCurveTo: + return 3; + default: + ASSERT(m_type == PathCloseSubpath); + return 0; + } +} + +void PathPolygon::move(const FloatSize& offset) +{ + for (Vector::iterator i = begin(); i < end(); ++i) + i->move(offset); +} + +void PathPolygon::transform(const AffineTransform& t) +{ + for (Vector::iterator i = begin(); i < end(); ++i) + *i = t.mapPoint(*i); +} + +bool PathPolygon::contains(const FloatPoint& point) const +{ + if (size() < 3) + return false; + + // Test intersections between the polygon and the vertical line: x = point.x() + + int intersected = 0; + const PathPoint* point1 = &last(); + Vector::const_iterator last = end(); + // wasNegative: -1 means unknown, 0 means false, 1 means true. + int wasNegative = -1; + for (Vector::const_iterator i = begin(); i != last; ++i) { + const PathPoint& point2 = *i; + if (point1->x() != point.x()) { + if (point2.x() == point.x()) { + // We are getting on the vertical line + wasNegative = point1->x() < point.x() ? 1 : 0; + } else if (point2.x() < point.x() != point1->x() < point.x()) { + float y = (point2.y() - point1->y()) / (point2.x() - point1->x()) * (point.x() - point1->x()) + point1->y(); + if (y >= point.y()) + ++intersected; + } + } else { + // We were on the vertical line + + // handle special case + if (point1->y() == point.y()) + return true; + + if (point1->y() > point.y()) { + if (point2.x() == point.x()) { + // see if the point is on this segment + if (point2.y() <= point.y()) + return true; + + // We are still on the line + } else { + // We are leaving the line now. + // We have to get back to see which side we come from. If we come from + // the same side we are leaving, no intersection should be counted + if (wasNegative < 0) { + Vector::const_iterator jLast = i; + Vector::const_iterator j = i; + do { + if (j == begin()) + j = last; + else + --j; + if (j->x() != point.x()) { + if (j->x() > point.x()) + wasNegative = 0; + else + wasNegative = 1; + break; + } + } while (j != jLast); + + if (wasNegative < 0) + return false; + } + if (wasNegative ? point2.x() > point.x() : point2.x() < point.x()) + ++intersected; + } + } else if (point2.x() == point.x() && point2.y() >= point.y()) + return true; + } + point1 = &point2; + } + + return intersected & 1; +} + +void PlatformPathElement::move(const FloatSize& offset) +{ + int n = numControlPoints(); + for (int i = 0; i < n; ++i) + m_data.m_points[i].move(offset); +} + +void PlatformPathElement::transform(const AffineTransform& t) +{ + int n = numControlPoints(); + for (int i = 0; i < n; ++i) { + FloatPoint p = t.mapPoint(m_data.m_points[i]); + m_data.m_points[i].set(p.x(), p.y()); + } +} + +void PlatformPathElement::inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const +{ + if (m_type == PathArcTo) { + const ArcTo& data = m_data.m_arcToData; + PathPoint startPoint; + startPoint = lastPoint; + PathPoint endPoint = data.m_end; + if (!data.m_clockwise) + std::swap(startPoint, endPoint); + + int q0 = quadrant(startPoint, data.m_center); + int q1 = quadrant(endPoint, data.m_center); + bool containsExtremes[4] = { false }; // bottom, left, top, right + static const PathPoint extremeVectors[4] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; + if (q0 == q1) { + if (startPoint.m_x == endPoint.m_x || isQuadrantOnBottom(q0) != startPoint.m_x > endPoint.m_x) { + for (int i = 0; i < 4; ++i) + containsExtremes[i] = true; + } + } else { + int extreme = q0; + int diff = quadrantDiff(q1, q0); + for (int i = 0; i < diff; ++i) { + containsExtremes[extreme] = true; + extreme = nextQuadrant(extreme); + } + } + + inflateRectToContainPoint(r, startPoint.m_x, startPoint.m_y); + inflateRectToContainPoint(r, endPoint.m_x, endPoint.m_y); + for (int i = 0; i < 4; ++i) { + if (containsExtremes[i]) + inflateRectToContainPoint(r, data.m_center.m_x + data.m_radius.m_x * extremeVectors[i].m_x, data.m_center.m_y + data.m_radius.m_y * extremeVectors[i].m_y); + } + } else { + int n = numPoints(); + for (int i = 0; i < n; ++i) + inflateRectToContainPoint(r, m_data.m_points[i].m_x, m_data.m_points[i].m_y); + } +} + +PathElementType PlatformPathElement::type() const +{ + switch (m_type) { + case PathMoveTo: + return PathElementMoveToPoint; + case PathLineTo: + return PathElementAddLineToPoint; + case PathArcTo: + // FIXME: there's no arcTo type for PathElement + return PathElementAddLineToPoint; + // return PathElementAddQuadCurveToPoint; + case PathQuadCurveTo: + return PathElementAddQuadCurveToPoint; + case PathBezierCurveTo: + return PathElementAddCurveToPoint; + default: + ASSERT(m_type == PathCloseSubpath); + return PathElementCloseSubpath; + } +} + +PlatformPath::PlatformPath() + : m_penLifted(true) +{ + m_currentPoint.clear(); +} + +void PlatformPath::ensureSubpath() +{ + if (m_penLifted) { + m_penLifted = false; + m_subpaths.append(PathPolygon()); + m_subpaths.last().append(m_currentPoint); + } else + ASSERT(!m_subpaths.isEmpty()); +} + +void PlatformPath::addToSubpath(const PlatformPathElement& e) +{ + if (e.platformType() == PlatformPathElement::PathMoveTo) { + m_penLifted = true; + m_currentPoint = e.pointAt(0); + } else if (e.platformType() == PlatformPathElement::PathCloseSubpath) { + m_penLifted = true; + if (!m_subpaths.isEmpty()) { + if (m_currentPoint != m_subpaths.last()[0]) { + // According to W3C, we have to draw a line from current point to the initial point + m_subpaths.last().append(m_subpaths.last()[0]); + m_currentPoint = m_subpaths.last()[0]; + } + } else + m_currentPoint.clear(); + } else { + ensureSubpath(); + switch (e.platformType()) { + case PlatformPathElement::PathLineTo: + m_subpaths.last().append(e.pointAt(0)); + break; + case PlatformPathElement::PathArcTo: + addArcPoints(m_subpaths.last(), e.arcTo()); + break; + case PlatformPathElement::PathQuadCurveTo: + { + PathPoint control[] = { + m_currentPoint, + e.pointAt(0), + e.pointAt(1), + }; + // FIXME: magic number? + quadCurve(50, m_subpaths.last(), control); + } + break; + case PlatformPathElement::PathBezierCurveTo: + { + PathPoint control[] = { + m_currentPoint, + e.pointAt(0), + e.pointAt(1), + e.pointAt(2), + }; + // FIXME: magic number? + bezier(100, m_subpaths.last(), control); + } + break; + default: + ASSERT_NOT_REACHED(); + break; + } + m_currentPoint = m_subpaths.last().last(); + } +} + +void PlatformPath::append(const PlatformPathElement& e) +{ + e.inflateRectToContainMe(m_boundingRect, lastPoint()); + addToSubpath(e); + m_elements.append(e); +} + +void PlatformPath::append(const PlatformPath& p) +{ + const PlatformPathElements& e = p.elements(); + for (PlatformPathElements::const_iterator it(e.begin()); it != e.end(); ++it) { + addToSubpath(*it); + it->inflateRectToContainMe(m_boundingRect, lastPoint()); + m_elements.append(*it); + } +} + +void PlatformPath::clear() +{ + m_elements.clear(); + m_boundingRect = FloatRect(); + m_subpaths.clear(); + m_currentPoint.clear(); + m_penLifted = true; +} + +void PlatformPath::strokePath(HDC dc, const AffineTransform* transformation) const +{ + drawPolygons(dc, m_subpaths, false, transformation); +} + +void PlatformPath::fillPath(HDC dc, const AffineTransform* transformation) const +{ + HGDIOBJ oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); + drawPolygons(dc, m_subpaths, true, transformation); + SelectObject(dc, oldPen); +} + +void PlatformPath::translate(const FloatSize& size) +{ + for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) + it->move(size); + + m_boundingRect.move(size); + for (Vector::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) + it->move(size); +} + +void PlatformPath::transform(const AffineTransform& t) +{ + for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) + it->transform(t); + + m_boundingRect = t.mapRect(m_boundingRect); + for (Vector::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) + it->transform(t); +} + +bool PlatformPath::contains(const FloatPoint& point, WindRule rule) const +{ + // optimization: check the bounding rect first + if (!containsPoint(m_boundingRect, point)) + return false; + + for (Vector::const_iterator i = m_subpaths.begin(); i != m_subpaths.end(); ++i) { + if (i->contains(point)) + return true; + } + + return false; +} + +void PlatformPath::moveTo(const FloatPoint& point) +{ + PlatformPathElement::MoveTo data = { { point.x(), point.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addLineTo(const FloatPoint& point) +{ + PlatformPathElement::LineTo data = { { point.x(), point.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + PlatformPathElement::QuadCurveTo data = { { cp.x(), cp.y() }, { p.x(), p.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + PlatformPathElement::BezierCurveTo data = { { cp1.x(), cp1.y() }, { cp2.x(), cp2.y() }, { p.x(), p.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addArcTo(const FloatPoint& fp1, const FloatPoint& fp2, float radius) +{ + const PathPoint& p0 = m_currentPoint; + PathPoint p1; + p1 = fp1; + PathPoint p2; + p2 = fp2; + if (!radius || p0 == p1 || p1 == p2) { + addLineTo(p1); + return; + } + + PathVector v01 = p0 - p1; + PathVector v21 = p2 - p1; + + // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A) + double cross = v01.m_x * v21.m_y - v01.m_y * v21.m_x; + + if (fabs(cross) < 1E-10) { + // on one line + addLineTo(p1); + return; + } + + double d01 = v01.length(); + double d21 = v21.length(); + double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5; + double span = radius * tan(angle); + double rate = span / d01; + PathPoint startPoint; + startPoint.m_x = p1.m_x + v01.m_x * rate; + startPoint.m_y = p1.m_y + v01.m_y * rate; + + addLineTo(startPoint); + + PathPoint endPoint; + rate = span / d21; + endPoint.m_x = p1.m_x + v21.m_x * rate; + endPoint.m_y = p1.m_y + v21.m_y * rate; + + PathPoint midPoint; + midPoint.m_x = (startPoint.m_x + endPoint.m_x) * 0.5; + midPoint.m_y = (startPoint.m_y + endPoint.m_y) * 0.5; + + PathVector vm1 = midPoint - p1; + double dm1 = vm1.length(); + double d = _hypot(radius, span); + + PathPoint centerPoint; + rate = d / dm1; + centerPoint.m_x = p1.m_x + vm1.m_x * rate; + centerPoint.m_y = p1.m_y + vm1.m_y * rate; + + PlatformPathElement::ArcTo data = { + endPoint, + centerPoint, + { radius, radius }, + cross < 0 + }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::closeSubpath() +{ + PlatformPathElement pe; + append(pe); +} + +// add a circular arc centred at p with radius r from start angle sar (radians) to end angle ear +void PlatformPath::addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise) +{ + float startX, startY, endX, endY; + + normalizeAngle(sar); + normalizeAngle(ear); + + getEllipsePointByAngle(sar, a, b, startX, startY); + getEllipsePointByAngle(ear, a, b, endX, endY); + + transformArcPoint(startX, startY, p); + transformArcPoint(endX, endY, p); + + FloatPoint start(startX, startY); + moveTo(start); + + PlatformPathElement::ArcTo data = { { endX, endY }, { p.x(), p.y() }, { a, b }, !anticlockwise }; + PlatformPathElement pe(data); + append(pe); +} + + +void PlatformPath::addRect(const FloatRect& r) +{ + moveTo(r.location()); + + float right = r.right() - 1; + float bottom = r.bottom() - 1; + addLineTo(FloatPoint(right, r.y())); + addLineTo(FloatPoint(right, bottom)); + addLineTo(FloatPoint(r.x(), bottom)); + addLineTo(r.location()); +} + +void PlatformPath::addEllipse(const FloatRect& r) +{ + FloatSize radius(r.width() * 0.5, r.height() * 0.5); + addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true); +} + +void PlatformPath::apply(void* info, PathApplierFunction function) const +{ + PathElement pelement; + FloatPoint points[3]; + pelement.points = points; + + for (PlatformPathElements::const_iterator it(m_elements.begin()); it != m_elements.end(); ++it) { + pelement.type = it->type(); + int n = it->numPoints(); + for (int i = 0; i < n; ++i) + points[i] = it->pointAt(i); + function(info, &pelement); + } +} + +} // namespace Webcore diff --git a/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h new file mode 100644 index 0000000..4c86fc3 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h @@ -0,0 +1,182 @@ +/* + * 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. + */ + +#ifndef PlatformPathWinCE_h +#define PlatformPathWinCE_h + +#include "FloatPoint.h" +#include "FloatRect.h" +#include "Path.h" +#include + +namespace WebCore { + + class GraphicsContext; + + struct PathPoint { + float m_x; + float m_y; + const float& x() const { return m_x; } + const float& y() const { return m_y; } + void set(float x, float y) + { + m_x = x; + m_y = y; + }; + operator FloatPoint() const { return FloatPoint(m_x, m_y); } + void move(const FloatSize& offset) + { + m_x += offset.width(); + m_y += offset.height(); + } + PathPoint& operator=(const FloatPoint& p) + { + m_x = p.x(); + m_y = p.y(); + return *this; + } + void clear() { m_x = m_y = 0; } + }; + + struct PathPolygon: public Vector { + void move(const FloatSize& offset); + void transform(const AffineTransform& t); + bool contains(const FloatPoint& point) const; + }; + + class PlatformPathElement { + public: + enum PlaformPathElementType { + PathMoveTo, + PathLineTo, + PathArcTo, + PathQuadCurveTo, + PathBezierCurveTo, + PathCloseSubpath, + }; + + struct MoveTo { + PathPoint m_end; + }; + + struct LineTo { + PathPoint m_end; + }; + + struct ArcTo { + PathPoint m_end; + PathPoint m_center; + PathPoint m_radius; + bool m_clockwise; + }; + + struct QuadCurveTo { + PathPoint m_point0; + PathPoint m_point1; + }; + + struct BezierCurveTo { + PathPoint m_point0; + PathPoint m_point1; + PathPoint m_point2; + }; + + PlatformPathElement(): m_type(PathCloseSubpath) { m_data.m_points[0].set(0, 0); } + PlatformPathElement(const MoveTo& data): m_type(PathMoveTo) { m_data.m_moveToData = data; } + PlatformPathElement(const LineTo& data): m_type(PathLineTo) { m_data.m_lineToData = data; } + PlatformPathElement(const ArcTo& data): m_type(PathArcTo) { m_data.m_arcToData = data; } + PlatformPathElement(const QuadCurveTo& data): m_type(PathQuadCurveTo) { m_data.m_quadCurveToData = data; } + PlatformPathElement(const BezierCurveTo& data): m_type(PathBezierCurveTo) { m_data.m_bezierCurveToData = data; } + + const MoveTo& moveTo() const { return m_data.m_moveToData; } + const LineTo& lineTo() const { return m_data.m_lineToData; } + const ArcTo& arcTo() const { return m_data.m_arcToData; } + const QuadCurveTo& quadCurveTo() const { return m_data.m_quadCurveToData; } + const BezierCurveTo& bezierCurveTo() const { return m_data.m_bezierCurveToData; } + const PathPoint& lastPoint() const + { + int n = numPoints(); + return n > 1 ? m_data.m_points[n - 1] : m_data.m_points[0]; + } + const PathPoint& pointAt(int index) const { return m_data.m_points[index]; } + int numPoints() const; + int numControlPoints() const; + void move(const FloatSize& offset); + void transform(const AffineTransform& t); + PathElementType type() const; + PlaformPathElementType platformType() const { return m_type; } + void inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const; + + private: + PlaformPathElementType m_type; + union { + MoveTo m_moveToData; + LineTo m_lineToData; + ArcTo m_arcToData; + QuadCurveTo m_quadCurveToData; + BezierCurveTo m_bezierCurveToData; + PathPoint m_points[4]; + } m_data; + }; + + typedef Vector PlatformPathElements; + + class PlatformPath { + public: + PlatformPath(); + const PlatformPathElements& elements() const { return m_elements; } + void append(const PlatformPathElement& e); + void append(const PlatformPath& p); + void clear(); + bool isEmpty() const { return m_elements.isEmpty(); } + + void strokePath(HDC, const AffineTransform* tr) const; + void fillPath(HDC, const AffineTransform* tr) const; + FloatPoint lastPoint() const { return m_elements.isEmpty() ? FloatPoint(0, 0) : m_elements.last().lastPoint(); } + + const FloatRect& boundingRect() const { return m_boundingRect; } + bool contains(const FloatPoint& point, WindRule rule) const; + void translate(const FloatSize& size); + void transform(const AffineTransform& t); + + void moveTo(const FloatPoint&); + void addLineTo(const FloatPoint&); + void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point); + void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint&); + void addArcTo(const FloatPoint&, const FloatPoint&, float radius); + void closeSubpath(); + void addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise); + void addRect(const FloatRect& r); + void addEllipse(const FloatRect& r); + void apply(void* info, PathApplierFunction function) const; + + private: + void ensureSubpath(); + void addToSubpath(const PlatformPathElement& e); + + PlatformPathElements m_elements; + FloatRect m_boundingRect; + Vector m_subpaths; + PathPoint m_currentPoint; + bool m_penLifted; + }; + +} + +#endif // PlatformPathWinCE_h diff --git a/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp b/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp new file mode 100644 index 0000000..05d1535 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/SharedBitmap.cpp @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved. + * Copyright (C) 2010 Patrick Gansterer + * + * 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 "SharedBitmap.h" + +#include "GDIExtras.h" +#include "GraphicsContext.h" +#include "GraphicsTypes.h" +#include "TransformationMatrix.h" +#include "WinCEGraphicsExtras.h" +#include +#include +#include +#include + +#include + +namespace WebCore { + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter sharedBitmapLeakCounter("SharedBitmap"); +#endif + + +PassRefPtr SharedBitmap::create(const IntSize& size, BitmapInfo::BitCount bitCount, bool initPixels) +{ + RefPtr resultantBitmap = adoptRef(new SharedBitmap(size, bitCount, initPixels)); + if (resultantBitmap && !resultantBitmap->bytes()) + return 0; + return resultantBitmap.release(); +} + +PassRefPtr SharedBitmap::create(const Vector& data, const IntSize& size, bool hasAlpha) +{ + RefPtr result = create(size, BitmapInfo::BitCount32, false); + if (!result) + return 0; + memcpy(result->bytes(), data.data(), data.size() * sizeof(unsigned)); + result->setHasAlpha(hasAlpha); + return result.release(); +} + +SharedBitmap::SharedBitmap(const IntSize& size, BitmapInfo::BitCount bitCount, bool initPixels) + : m_bmpInfo(BitmapInfo::createBottomUp(size, bitCount)) + , m_locked(false) + , m_usesTransparentColor(false) + , m_transparentColor(RGB(0, 0, 0)) + , m_pixels(0) + , m_hasAlpha(false) + , m_validHeight(abs(size.height())) + , m_hbitmap(0) +{ +#ifndef NDEBUG + sharedBitmapLeakCounter.increment(); +#endif + + unsigned bufferSize = m_bmpInfo.numPixels(); + if (bitCount == BitmapInfo::BitCount16) + bufferSize /= 2; + + m_pixelData = adoptArrayPtr(new unsigned[bufferSize]); + m_pixels = m_pixelData.get(); + + if (initPixels) + resetPixels(); +} + +SharedBitmap::~SharedBitmap() +{ +#ifndef NDEBUG + sharedBitmapLeakCounter.decrement(); +#endif +} + +void SharedBitmap::resetPixels(bool black) +{ + if (!m_pixels) + return; + + unsigned bufferSize = m_bmpInfo.numPixels(); + if (black) { + unsigned bufferSizeInBytes = bufferSize * (is16bit() ? 2 : 4); + memset(m_pixels, 0, bufferSizeInBytes); + return; + } + + if (is16bit()) { + // Fill it with white color + wmemset(static_cast(m_pixels), 0xFFFF, bufferSize); + return; + } + + // Make it white but transparent + unsigned* pixel = static_cast(m_pixels); + const unsigned* bufferEnd = pixel + bufferSize; + while (pixel < bufferEnd) + *pixel++ = 0x00FFFFFF; +} + +static inline unsigned short convert32To16(unsigned pixel) +{ + unsigned short r = static_cast((pixel & 0x00F80000) >> 8); + unsigned short g = static_cast((pixel & 0x0000FC00) >> 5); + unsigned short b = static_cast((pixel & 0x000000F8) >> 3); + return r | g | b; +} + +bool SharedBitmap::to16bit() +{ + if (m_locked) + return false; + if (is16bit()) + return true; + + BitmapInfo newBmpInfo = BitmapInfo::create(m_bmpInfo.size(), BitmapInfo::BitCount16); + + int width = newBmpInfo.width(); + int paddedWidth = newBmpInfo.paddedWidth(); + int bufferSize = paddedWidth * newBmpInfo.height(); + OwnArrayPtr newPixelData(new unsigned[bufferSize / 2]); + void* newPixels = newPixelData.get(); + + if (!newPixels) + return false; + + unsigned short* p16 = static_cast(newPixels); + const unsigned* p32 = static_cast(m_pixels); + + bool skips = paddedWidth != width; + + const unsigned short* p16end = p16 + bufferSize; + while (p16 < p16end) { + for (unsigned short* p16lineEnd = p16 + width; p16 < p16lineEnd; ) + *p16++ = convert32To16(*p32++); + + if (skips) + *p16++ = 0; + } + + if (m_hbitmap) + m_hbitmap = nullptr; + else + m_pixelData = newPixelData.release(); + + m_pixels = newPixels; + m_bmpInfo = newBmpInfo; + + setHasAlpha(false); + return true; +} + +bool SharedBitmap::freeMemory() +{ + if (m_locked) + return false; + + if (m_hbitmap) { + m_hbitmap = nullptr; + m_pixels = 0; + return true; + } + + if (m_pixels) { + m_pixelData = nullptr; + m_pixels = 0; + return true; + } + + return false; +} + +PassOwnPtr SharedBitmap::createHandle(void** pixels, BitmapInfo* bmpInfo, int height, bool use16bit) const +{ + if (!m_pixels) + return 0; + + if (height == -1) + height = this->height(); + *bmpInfo = BitmapInfo::createBottomUp(IntSize(width(), height), (use16bit || is16bit()) ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32); + + OwnPtr hbmp = adoptPtr(CreateDIBSection(0, bmpInfo, DIB_RGB_COLORS, pixels, 0, 0)); + + if (!hbmp) + return 0; + + OwnPtr bmpDC = adoptPtr(CreateCompatibleDC(0)); + HGDIOBJ hOldBmp = SelectObject(bmpDC.get(), hbmp.get()); + + StretchDIBits(bmpDC.get(), 0, 0, width(), height, 0, 0, width(), height, m_pixels, &m_bmpInfo, DIB_RGB_COLORS, SRCCOPY); + + SelectObject(bmpDC.get(), hOldBmp); + + return hbmp.release(); +} + +bool SharedBitmap::ensureHandle() +{ + if (m_hbitmap) + return true; + + if (!m_pixels) + return false; + + if (m_locked) + return false; + + BitmapInfo bmpInfo; + void* pixels; + m_hbitmap = createHandle(&pixels, &bmpInfo, -1, !hasAlpha()); + + if (!m_hbitmap) + return false; + + m_pixelData = nullptr; + m_pixels = pixels; + m_bmpInfo = bmpInfo; + + return true; +} + +void SharedBitmap::draw(GraphicsContext* ctxt, const IntRect& dstRect, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) +{ + if (!m_pixels) + return; + ctxt->drawBitmap(this, dstRect, srcRect, styleColorSpace, compositeOp); +} + +void SharedBitmap::draw(HDC hdc, const IntRect& dstRect, const IntRect& srcRect, CompositeOperator compositeOp) +{ + if (!m_pixels) + return; + + if (dstRect.isEmpty() || srcRect.isEmpty()) + return; + + HBITMAP hbitmap = 0; + OwnPtr hTempBitmap; + bool usingHandle = compositeOp == CompositeSourceOver && (hasAlpha() && hasAlphaBlendSupport() || usesTransparentColor()); + + if (usingHandle) { + if (ensureHandle()) + hbitmap = m_hbitmap.get(); + else { + void* pixels; + BitmapInfo bmpInfo; + hTempBitmap = createHandle(&pixels, &bmpInfo, -1, usesTransparentColor()); + hbitmap = hTempBitmap.get(); + } + } + if (!hbitmap) { + // FIXME: handle other composite operation types? + DWORD rop = compositeOp == CompositeCopy ? SRCCOPY + : compositeOp == CompositeXOR ? PATINVERT + : compositeOp == CompositeClear ? WHITENESS + : SRCCOPY; + + StretchDIBits(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(), + srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), m_pixels, &m_bmpInfo, DIB_RGB_COLORS, rop); + return; + } + + OwnPtr hmemdc = adoptPtr(CreateCompatibleDC(hdc)); + HGDIOBJ hOldBmp = SelectObject(hmemdc.get(), hbitmap); + + if (!usesTransparentColor() && hasAlphaBlendSupport()) { + static const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + bool success = alphaBlendIfSupported(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(), hmemdc.get(), + srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), blend); + ASSERT_UNUSED(success, success); + } else { + TransparentBlt(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(), hmemdc.get(), + srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), transparentColor()); + } + + SelectObject(hmemdc.get(), hOldBmp); +} + +PassOwnPtr SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha, BitmapInfo& bmpInfo, void*& pixels) +{ + if (!bytes()) + return 0; + + int oldWidth = width(); + int oldHeight = height(); + int copyWidth = std::min(rect.width(), oldWidth - rect.x()); + int copyHeight = std::min(rect.height(), oldHeight - rect.y()); + if (!copyWidth || !copyHeight) + return 0; + + bmpInfo = BitmapInfo::createBottomUp(IntSize(copyWidth, copyHeight), (useAlpha && is32bit()) ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16); + OwnPtr newBmp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0)); + + if (!newBmp) + return 0; + + OwnPtr dcNew = adoptPtr(CreateCompatibleDC(0)); + HGDIOBJ tmpNew = SelectObject(dcNew.get(), newBmp.get()); + + StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight, + bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY); + + SelectObject(dcNew.get(), tmpNew); + return newBmp.release(); +} + +PassRefPtr SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha) +{ + int oldWidth = width(); + int oldHeight = height(); + int copyWidth = std::min(rect.width(), oldWidth - rect.x()); + int copyHeight = std::min(rect.height(), oldHeight - rect.y()); + if (!copyWidth || !copyHeight) + return 0; + + RefPtr newBmp = create(IntSize(copyWidth, copyHeight), useAlpha && is32bit() ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16, false); + + if (!newBmp || !newBmp->bytes()) + return 0; + + DCHolder dcNew(newBmp.get()); + + StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight, + bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY); + + return newBmp; +} + +static void drawPatternSimple(HDC hdc, const RECT& destRect, HBITMAP hbmp, const POINT& phase) +{ + OwnPtr hBrush = adoptPtr(CreatePatternBrush(hbmp)); + if (!hBrush) + return; + + POINT oldOrg; + SetBrushOrgEx(hdc, destRect.left - phase.x, destRect.top - phase.y, &oldOrg); + FillRect(hdc, &destRect, hBrush.get()); + SetBrushOrgEx(hdc, oldOrg.x, oldOrg.y, 0); +} + +static void drawPatternSimple(HDC hdc, const RECT& destRect, const SharedBitmap* bmp, const SIZE& bmpSize, const POINT& phase) +{ + int dstY = destRect.top; + for (int sourceY = phase.y; dstY < destRect.bottom; ) { + int sourceH = std::min(bmpSize.cy - sourceY, destRect.bottom - dstY); + int dstX = destRect.left; + for (int sourceX = phase.x; dstX < destRect.right; ) { + int sourceW = std::min(bmpSize.cx - sourceX, destRect.right - dstX); + + StretchDIBits(hdc, dstX, dstY, sourceW, sourceH, sourceX, sourceY, sourceW, sourceH, + bmp->bytes(), &bmp->bitmapInfo(), DIB_RGB_COLORS, SRCCOPY); + + dstX += sourceW; + sourceX = 0; + } + + dstY += sourceH; + sourceY = 0; + } +} + +static LONG normalizePhase(LONG phase, int limit) +{ + if (!phase || limit < 2) + return 0; + + if (limit == 2) + return phase & 1; + + if (phase < 0) { + phase = -phase; + if (phase > limit) + phase = static_cast(static_cast(phase) % static_cast(limit)); + if (phase) + phase = limit - phase; + return phase; + } + + if (phase < limit) + return phase; + + return static_cast(static_cast(phase) % static_cast(limit)); +} + +void SharedBitmap::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize) +{ + if (!m_pixels) + return; + ctxt->drawBitmapPattern(this, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, origSourceSize); +} + +void SharedBitmap::drawPattern(HDC hdc, const AffineTransform& transform, const FloatRect& tileRectIn, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize) +{ + if (!m_pixels) + return; + + if (tileRectIn.width() <= 0 || tileRectIn.height() <= 0) + return; + + bool useAlpha = op == CompositeSourceOver && hasAlpha() && is32bit(); + + int bmpWidth = width(); + int bmpHeight = height(); + + FloatRect tileRect(tileRectIn); + if (bmpWidth != origSourceSize.width()) { + double rate = static_cast(bmpWidth) / origSourceSize.width(); + double temp = tileRect.width() * rate; + tileRect.setX(tileRect.x() * rate); + tileRect.setWidth(temp); + temp = tileRect.height() * rate; + tileRect.setY(tileRect.y() * rate); + tileRect.setHeight(temp); + } + + OwnPtr clippedBmp; + + if (tileRect.x() || tileRect.y() || tileRect.width() != bmpWidth || tileRect.height() != bmpHeight) { + BitmapInfo patternBmpInfo; + void* patternPixels; + clippedBmp = clipBitmap(IntRect(tileRect), useAlpha, patternBmpInfo, patternPixels); + if (!clippedBmp) + return; + + bmpWidth = tileRect.width(); + bmpHeight = tileRect.height(); + } + + AffineTransform tf = transform; + tf *= patternTransform; + + FloatRect trRect = tf.mapRect(destRect); + + RECT clipBox; + int clipType = GetClipBox(hdc, &clipBox); + if (clipType == SIMPLEREGION) + trRect.intersect(FloatRect(clipBox.left, clipBox.top, clipBox.right - clipBox.left, clipBox.bottom - clipBox.top)); + else if (clipType == COMPLEXREGION) { + OwnPtr clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0)); + if (GetClipRgn(hdc, clipRgn.get()) > 0) { + DWORD regionDataSize = GetRegionData(clipRgn.get(), sizeof(RGNDATA), 0); + if (regionDataSize) { + Vector regionData(regionDataSize); + GetRegionData(clipRgn.get(), regionDataSize, regionData.data()); + RECT* rect = reinterpret_cast(regionData[0].Buffer); + for (DWORD i = 0; i < regionData[0].rdh.nCount; ++i, ++rect) + trRect.intersect(FloatRect(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top)); + } + } + } + + if (trRect.width() <= 0 || trRect.height() <= 0) + return; + + trRect.inflate(1); + IntRect visibleDstRect = enclosingIntRect(tf.inverse().mapRect(trRect)); + visibleDstRect.intersect(IntRect(destRect)); + + if (visibleDstRect.width() <= 0 || visibleDstRect.height() <= 0) + return; + + trRect = tf.mapRect(visibleDstRect); + RECT dstRectWin = { + stableRound(trRect.x()), + stableRound(trRect.y()), + stableRound(trRect.right()), + stableRound(trRect.bottom()), + }; + if (dstRectWin.right <= dstRectWin.left || dstRectWin.bottom <= dstRectWin.top) + return; + + SIZE bmpSize = { bmpWidth, bmpHeight }; + + // Relative to destination, in bitmap pixels + POINT phaseWin = { stableRound(visibleDstRect.x() - phase.x()), stableRound(visibleDstRect.y() - phase.y()) }; + phaseWin.x = normalizePhase(phaseWin.x, bmpSize.cx); + phaseWin.y = normalizePhase(phaseWin.y, bmpSize.cy); + + RECT srcRectWin = { + 0, + 0, + stableRound(visibleDstRect.right()) - stableRound(visibleDstRect.x()), + stableRound(visibleDstRect.bottom()) - stableRound(visibleDstRect.y()) + }; + if (srcRectWin.right <= 0 || srcRectWin.bottom <= 0) + return; + + BitmapInfo bmpInfo = BitmapInfo::createBottomUp(IntSize(srcRectWin.right, srcRectWin.bottom), useAlpha ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16); + void* pixels; + OwnPtr hbmpTemp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0)); + + if (!hbmpTemp) + return; + + OwnPtr hmemdc = adoptPtr(CreateCompatibleDC(hdc)); + HGDIOBJ oldBmp = SelectObject(hmemdc.get(), hbmpTemp.get()); + if (clippedBmp) + drawPatternSimple(hmemdc.get(), srcRectWin, clippedBmp.get(), phaseWin); + else if ((op != CompositeSourceOver || canUseDIBits()) && srcRectWin.right <= bmpSize.cx * 2 && srcRectWin.bottom <= bmpSize.cy * 2) + drawPatternSimple(hmemdc.get(), srcRectWin, this, bmpSize, phaseWin); + else if (ensureHandle()) + drawPatternSimple(hmemdc.get(), srcRectWin, getHandle(), phaseWin); + else { + void* pixels; + BitmapInfo bmpInfo; + OwnPtr hbmp = createHandle(&pixels, &bmpInfo, -1, false); + if (hbmp) + drawPatternSimple(hmemdc.get(), srcRectWin, hbmp.get(), phaseWin); + else { + SelectObject(hmemdc.get(), oldBmp); + return; + } + } + + if (useAlpha && hasAlphaBlendSupport()) { + static const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + bool success = alphaBlendIfSupported(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left, dstRectWin.bottom - dstRectWin.top, + hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, blend); + ASSERT_UNUSED(success, success); + } else if (useAlpha && !hasAlphaBlendSupport() || op == CompositeSourceOver && usesTransparentColor()) { + TransparentBlt(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left, + dstRectWin.bottom - dstRectWin.top, hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, transparentColor()); + } else { + DWORD bmpOp = op == CompositeCopy ? SRCCOPY + : op == CompositeSourceOver ? SRCCOPY + : op == CompositeXOR ? PATINVERT + : op == CompositeClear ? WHITENESS + : SRCCOPY; // FIXEME: other types? + + StretchDIBits(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left, + dstRectWin.bottom - dstRectWin.top, 0, 0, srcRectWin.right, srcRectWin.bottom, + pixels, &bmpInfo, DIB_RGB_COLORS, bmpOp); + } + SelectObject(hmemdc.get(), oldBmp); +} + +SharedBitmap::DCProvider* SharedBitmap::s_dcProvider = new SharedBitmap::DCProvider; + +HDC SharedBitmap::DCProvider::getDC(SharedBitmap* bmp, unsigned* key) +{ + if (!bmp || !bmp->ensureHandle()) + return 0; + + HDC hdc = CreateCompatibleDC(0); + if (!hdc) + return 0; + + *key = reinterpret_cast(SelectObject(hdc, bmp->getHandle())); + RECT rect = { 0, 0, bmp->width(), bmp->height() }; + OwnPtr clipRgn = adoptPtr(CreateRectRgnIndirect(&rect)); + SelectClipRgn(hdc, clipRgn.get()); + + return hdc; +} + +void SharedBitmap::DCProvider::releaseDC(SharedBitmap*, HDC hdc, unsigned key1) +{ + if (!hdc) + return; + + SelectObject(hdc, reinterpret_cast(key1)); + DeleteDC(hdc); +} + +void SharedBitmap::clearPixels(const IntRect& rect) +{ + if (!m_pixels) + return; + + IntRect bmpRect(0, 0, width(), height()); + bmpRect.intersect(rect); + if (is16bit()) { + unsigned w = m_bmpInfo.paddedWidth(); + unsigned short* dst = static_cast(m_pixels); + dst += bmpRect.y() * w + bmpRect.x(); + int wordsToSet = bmpRect.width(); + const unsigned short* dstEnd = dst + bmpRect.height() * w; + while (dst < dstEnd) { + wmemset(reinterpret_cast(dst), 0, wordsToSet); + dst += w; + } + return; + } + + unsigned w = width(); + unsigned* dst = static_cast(m_pixels); + dst += bmpRect.y() * w + bmpRect.x(); + int wordsToSet = bmpRect.width() * 2; + const unsigned* dstEnd = dst + bmpRect.height() * w; + while (dst < dstEnd) { + wmemset(reinterpret_cast(dst), 0, wordsToSet); + dst += w; + } +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/SharedBitmap.h b/Source/WebCore/platform/graphics/wince/SharedBitmap.h new file mode 100644 index 0000000..82f5d54 --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/SharedBitmap.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved. + * Copyright (C) 2010 Patrick Gansterer + * + * 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 SharedBitmap_h +#define SharedBitmap_h + +#include "AffineTransform.h" +#include "BitmapInfo.h" +#include "ColorSpace.h" +#include "GraphicsTypes.h" +#include +#include +#include +#include +#include +#include + +namespace WebCore { + +class FloatPoint; +class FloatRect; +class GraphicsContext; +class IntRect; +class IntSize; +class TransformationMatrix; + +class SharedBitmap: public RefCounted { +public: + ~SharedBitmap(); + static PassRefPtr create(const IntSize&, BitmapInfo::BitCount = BitmapInfo::BitCount32, bool initPixels = true); + static PassRefPtr create(const Vector&, const IntSize&, bool hasAlpha = true); + + const BitmapInfo& bitmapInfo() const { return m_bmpInfo; } + void* bytes() { return m_pixels; } + const void* bytes() const { return m_pixels; } + unsigned width() const { return m_bmpInfo.width(); } + unsigned height() const { return m_bmpInfo.height(); } + unsigned validHeight() const { return m_validHeight; } + void setValidHeight(unsigned validHeight) { m_validHeight = validHeight; } + void resetPixels(bool black = false); + void clearPixels(const IntRect& r); + bool locked() const { return m_locked; } + void lock() { m_locked = true; } + void unlock() { m_locked = false; } + bool freeMemory(); + bool is16bit() const { return m_bmpInfo.is16bit(); } + bool is32bit() const { return m_bmpInfo.is32bit(); } + bool to16bit(); + bool hasAlpha() const { return m_hasAlpha; } + void setHasAlpha(bool alpha) { m_hasAlpha = alpha; } + bool ensureHandle(); + HBITMAP getHandle() { return m_hbitmap.get(); } + PassOwnPtr createHandle(void** pixels, BitmapInfo* bmpInfo, int h = -1, bool use16bit = true) const; + bool usesTransparentColor() const { return m_usesTransparentColor; } + COLORREF transparentColor() const { return m_transparentColor; } + void setTransparentColor(COLORREF c) + { + m_usesTransparentColor = true; + m_transparentColor = c; + } + bool canUseDIBits() const { return !hasAlpha() && !usesTransparentColor(); } + + PassOwnPtr clipBitmap(const IntRect& rect, bool useAlpha, BitmapInfo& bmpInfo, void*& pixels); + + PassRefPtr clipBitmap(const IntRect& rect, bool useAlpha); + + void draw(GraphicsContext* ctxt, const IntRect& dstRect, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp); + void drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize); + void draw(HDC, const IntRect& dstRect, const IntRect& srcRect, CompositeOperator compositeOp); + void drawPattern(HDC, const AffineTransform&, const FloatRect& tileRectIn, const AffineTransform& patternTransform, + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize); + + class DCProvider { + public: + virtual HDC getDC(SharedBitmap*, unsigned*); + virtual void releaseDC(SharedBitmap*, HDC, unsigned); + }; + + static DCProvider* s_dcProvider; + + HDC getDC(unsigned* key1) { return s_dcProvider->getDC(this, key1); } + void releaseDC(HDC hdc, unsigned key1) { s_dcProvider->releaseDC(this, hdc, key1); } + + class DCHolder { + public: + DCHolder(SharedBitmap* bmp = 0) { setInternal(bmp); } + ~DCHolder() { clearInternal(); } + void set(SharedBitmap* bmp = 0) + { + clearInternal(); + setInternal(bmp); + } + HDC get() const { return m_hdc; } + private: + DCHolder& operator=(const DCHolder&); + DCHolder(const DCHolder&); + void clearInternal() + { + if (m_hdc) + m_bitmap->releaseDC(m_hdc, m_key); + } + void setInternal(SharedBitmap* bmp) + { + m_bitmap = bmp; + m_hdc = bmp ? bmp->getDC(&m_key) : 0; + } + SharedBitmap* m_bitmap; + HDC m_hdc; + unsigned m_key; + }; + +private: + SharedBitmap(const IntSize&, BitmapInfo::BitCount, bool initPixels); + BitmapInfo m_bmpInfo; + OwnPtr m_hbitmap; + void* m_pixels; + OwnArrayPtr m_pixelData; + COLORREF m_transparentColor; + int m_validHeight; + bool m_locked; + bool m_usesTransparentColor; + bool m_hasAlpha; +}; + +} // namespace WebCore + +#endif // SharedBitmap_h diff --git a/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp b/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp new file mode 100644 index 0000000..27a021e --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp @@ -0,0 +1,180 @@ +/* + * 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 +#include +#include + +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() +{ +} + +SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const +{ + FontDescription fontDesc(fontDescription); + fontDesc.setComputedSize(lroundf(scaleFactor * fontDesc.computedSize())); + fontDesc.setSpecifiedSize(lroundf(scaleFactor * fontDesc.specifiedSize())); + fontDesc.setKeywordSize(lroundf(scaleFactor * fontDesc.keywordSize())); + FontPlatformData* result = fontCache()->getCachedFontPlatformData(fontDesc, m_platformData.family()); + return result ? new SimpleFontData(*result) : 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->smallCaps) + m_derivedFontData->smallCaps = scaledFontData(fontDescription, .7); + + return m_derivedFontData->smallCaps.get(); +} + +SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const +{ + if (!m_derivedFontData) + m_derivedFontData = DerivedFontData::create(isCustomFont()); + if (!m_derivedFontData->emphasisMark) + m_derivedFontData->emphasisMark = scaledFontData(fontDescription, .5); + + return m_derivedFontData->emphasisMark.get(); +} + +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); +} + +FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const +{ + return FloatRect(); +} + +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; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h b/Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h new file mode 100644 index 0000000..4cab21c --- /dev/null +++ b/Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef WinCEGraphicsExtras_h +#define WinCEGraphicsExtras_h + +// This file is used to contain small utilities used by WINCE graphics code. + +namespace WebCore { + // Always round to same direction. 0.5 is rounded to 1, + // and -0.5 (0.5 - 1) is rounded to 0 (1 - 1), so that it + // is consistent when transformation shifts. + static inline int stableRound(double d) + { + if (d > 0) + return static_cast(d + 0.5); + + int i = static_cast(d); + return i - d > 0.5 ? i - 1 : i; + } +} + +#endif WinCEGraphicsExtras_h -- cgit v1.1