summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/wince
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/wince')
-rw-r--r--Source/WebCore/platform/graphics/wince/ColorWinCE.cpp38
-rw-r--r--Source/WebCore/platform/graphics/wince/FontCacheWinCE.cpp351
-rw-r--r--Source/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp91
-rw-r--r--Source/WebCore/platform/graphics/wince/FontCustomPlatformData.h59
-rw-r--r--Source/WebCore/platform/graphics/wince/FontPlatformData.cpp534
-rw-r--r--Source/WebCore/platform/graphics/wince/FontPlatformData.h93
-rw-r--r--Source/WebCore/platform/graphics/wince/FontWinCE.cpp342
-rw-r--r--Source/WebCore/platform/graphics/wince/GlyphPageTreeNodeWinCE.cpp78
-rw-r--r--Source/WebCore/platform/graphics/wince/GradientWinCE.cpp52
-rw-r--r--Source/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp1890
-rw-r--r--Source/WebCore/platform/graphics/wince/ImageBufferData.h34
-rw-r--r--Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp255
-rw-r--r--Source/WebCore/platform/graphics/wince/ImageWinCE.cpp195
-rw-r--r--Source/WebCore/platform/graphics/wince/MediaPlayerPrivateWinCE.h125
-rw-r--r--Source/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp145
-rw-r--r--Source/WebCore/platform/graphics/wince/MediaPlayerProxy.h70
-rw-r--r--Source/WebCore/platform/graphics/wince/PathWinCE.cpp163
-rw-r--r--Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp772
-rw-r--r--Source/WebCore/platform/graphics/wince/PlatformPathWinCE.h182
-rw-r--r--Source/WebCore/platform/graphics/wince/SharedBitmap.cpp615
-rw-r--r--Source/WebCore/platform/graphics/wince/SharedBitmap.h145
-rw-r--r--Source/WebCore/platform/graphics/wince/SimpleFontDataWinCE.cpp180
-rw-r--r--Source/WebCore/platform/graphics/wince/WinCEGraphicsExtras.h39
23 files changed, 6448 insertions, 0 deletions
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 <windows.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+static IMultiLanguage *multiLanguage = 0;
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static IMLangFontLink2* langFontLink = 0;
+#else
+static IMLangFontLink* langFontLink = 0;
+#endif
+
+IMultiLanguage* 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<UNICODERANGE, 64> glyphsetBuffer;
+ glyphsetBuffer.resize(unicodeRanges);
+
+ if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, glyphsetBuffer.data()))
+ return false;
+
+ // FIXME: Change this to a binary search. (Yong Li: That's easy. But, is it guaranteed that the ranges are sorted?)
+ for (Vector<UNICODERANGE, 64>::const_iterator i = glyphsetBuffer.begin(); i != glyphsetBuffer.end(); ++i) {
+ if (i->wcTo >= character)
+ return i->wcFrom <= character;
+ }
+
+ return false;
+}
+#else
+static bool currentFontContainsCharacter(IMLangFontLink* langFontLink, HDC hdc, HFONT hfont, UChar character, const wchar_t* faceName)
+{
+ DWORD fontCodePages = 0, charCodePages = 0;
+ HRESULT result = langFontLink->GetFontCodePages(hdc, hfont, &fontCodePages);
+ if (result != S_OK)
+ return false;
+ result = langFontLink->GetCharCodePages(character, &charCodePages);
+ if (result != S_OK)
+ return false;
+
+ fontCodePages |= FontPlatformData::getKnownFontCodePages(faceName);
+ if (fontCodePages & charCodePages)
+ return true;
+
+ return false;
+}
+#endif
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
+{
+ HFONT mlangFont;
+ if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &mlangFont)))
+ return mlangFont;
+
+ return 0;
+}
+#else
+static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask)
+{
+ HFONT mlangFont;
+ LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont);
+
+ return result == S_OK ? mlangFont : 0;
+}
+#endif
+
+static const Vector<DWORD, 4>& getCJKCodePageMasks()
+{
+ // The default order in which we look for a font for a CJK character. If the user's default code page is
+ // one of these, we will use it first.
+ static const UINT CJKCodePages[] = {
+ 932, /* Japanese */
+ 936, /* Simplified Chinese */
+ 950, /* Traditional Chinese */
+ 949 /* Korean */
+ };
+
+ static Vector<DWORD, 4> codePageMasks;
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
+#else
+ IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface();
+#endif
+ if (!langFontLink)
+ return codePageMasks;
+
+ UINT defaultCodePage;
+ DWORD defaultCodePageMask = 0;
+ if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
+ langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
+
+ if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
+ codePageMasks.append(defaultCodePageMask);
+ for (unsigned i = 0; i < 4; ++i) {
+ if (defaultCodePage != CJKCodePages[i]) {
+ DWORD codePageMask;
+ langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
+ codePageMasks.append(codePageMask);
+ }
+ }
+ }
+ return codePageMasks;
+}
+
+
+struct TraitsInFamilyProcData {
+ TraitsInFamilyProcData(const AtomicString& familyName)
+ : m_familyName(familyName)
+ {
+ }
+
+ const AtomicString& m_familyName;
+ HashSet<unsigned> m_traitsMasks;
+};
+
+static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
+
+ unsigned traitsMask = 0;
+ traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
+ traitsMask |= FontVariantNormalMask;
+ LONG weight = FontPlatformData::adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+
+void FontCache::platformInit()
+{
+}
+
+void FontCache::comInitialize()
+{
+}
+
+void FontCache::comUninitialize()
+{
+ if (langFontLink) {
+ langFontLink->Release();
+ langFontLink = 0;
+ }
+ if (multiLanguage) {
+ multiLanguage->Release();
+ multiLanguage = 0;
+ }
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ String familyName;
+ WCHAR name[LF_FACESIZE];
+
+ UChar character = characters[0];
+ const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData();
+ unsigned unicodeRange = findCharUnicodeRange(character);
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
+#else
+ if (IMLangFontLink* langFontLink = getFontLinkInterface()) {
+#endif
+ HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT);
+ HFONT hfont = 0;
+ DWORD codePages = 0;
+ UINT codePage = 0;
+ // Try MLang font linking first.
+ langFontLink->GetCharCodePages(character, &codePages);
+ if (codePages && unicodeRange == cRangeSetCJK) {
+ // The CJK character may belong to multiple code pages. We want to
+ // do font linking against a single one of them, preferring the default
+ // code page for the user's locale.
+ const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
+ unsigned numCodePages = CJKCodePageMasks.size();
+ for (unsigned i = 0; i < numCodePages; ++i) {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ hfont = createMLangFont(langFontLink, g_screenDC, CJKCodePageMasks[i]);
+#else
+ hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]);
+#endif
+ if (!hfont)
+ continue;
+
+ SelectObject(g_screenDC, hfont);
+ GetTextFace(g_screenDC, LF_FACESIZE, name);
+
+ if (hfont && !(codePages & CJKCodePageMasks[i])) {
+ // We asked about a code page that is not one of the code pages
+ // returned by MLang, so the font might not contain the character.
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (!currentFontContainsCharacter(langFontLink, g_screenDC, character)) {
+#else
+ if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) {
+#endif
+ SelectObject(g_screenDC, oldFont);
+ langFontLink->ReleaseFont(hfont);
+ hfont = 0;
+ continue;
+ }
+ }
+ break;
+ }
+ } else {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ hfont = createMLangFont(langFontLink, g_screenDC, codePages, character);
+#else
+ hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages);
+#endif
+ SelectObject(g_screenDC, hfont);
+ GetTextFace(g_screenDC, LF_FACESIZE, name);
+ }
+ SelectObject(g_screenDC, oldFont);
+
+ if (hfont) {
+ familyName = name;
+ langFontLink->ReleaseFont(hfont);
+ } else
+ FontPlatformData::mapKnownFont(codePages, familyName);
+ }
+
+ if (familyName.isEmpty())
+ familyName = FontPlatformData::defaultFontFamily();
+
+ if (!familyName.isEmpty()) {
+ // FIXME: temporary workaround for Thai font problem
+ FontDescription fontDescription(font.fontDescription());
+ if (unicodeRange == cRangeThai && fontDescription.weight() > FontWeightNormal)
+ fontDescription.setWeight(FontWeightNormal);
+
+ FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName);
+ if (result && result->hash() != origFont.hash()) {
+ if (SimpleFontData* fontData = getCachedFontData(result))
+ return fontData;
+ }
+ }
+
+ return 0;
+}
+
+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<unsigned>& traitsMasks)
+{
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = std::min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ TraitsInFamilyProcData procData(familyName);
+ EnumFontFamiliesEx(g_screenDC, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+}
+
+} // 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 <wtf/RandomNumber.h>
+
+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<char> fontUuid(sizeof(GUID));
+
+ unsigned int* ptr = reinterpret_cast<unsigned int*>(fontUuid.data());
+ for (int i = 0; i < sizeof(GUID) / sizeof(int) ; ++i)
+ *(ptr + i) = static_cast<unsigned int>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0));
+
+ Vector<char> fontNameVector;
+ base64Encode(fontUuid, fontNameVector);
+ ASSERT(fontNameVector.size() < LF_FACESIZE);
+ String fontName(fontNameVector.data(), fontNameVector.size());
+ return fontName.replace('/', '_');
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer* buffer)
+{
+ if (g_customFontCache) {
+ String fontName = createUniqueFontName();
+ RefPtr<SharedBuffer> 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 <wtf/Noncopyable.h>
+
+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 <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+
+#include <windows.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+static wchar_t songTiStr[] = { 0x5b8b, 0x4f53, 0 };
+static wchar_t heiTiStr[] = { 0x9ed1, 0x4f53, 0 };
+
+class FontFamilyCodePageInfo {
+public:
+ FontFamilyCodePageInfo()
+ : m_codePage(0), m_codePages(0)
+ {
+ }
+ FontFamilyCodePageInfo(const wchar_t* family, UINT codePage)
+ : m_family(family), m_codePage(codePage), m_codePages(0)
+ {
+ }
+ DWORD codePages() const
+ {
+ if (!m_codePages) {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface())
+ langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
+#else
+ if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface())
+ langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
+#endif
+ }
+ return m_codePages;
+ }
+
+ String m_family;
+ UINT m_codePage;
+private:
+ mutable DWORD m_codePages;
+};
+
+class FontFamilyChecker {
+public:
+ FontFamilyChecker(const wchar_t* family)
+ : m_exists(false)
+ {
+ EnumFontFamilies(g_screenDC, family, enumFontFamProc, (LPARAM)this);
+ }
+ bool isSupported() const { return m_exists; }
+private:
+ bool m_exists;
+ static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
+};
+
+class ValidFontFamilyFinder {
+public:
+ ValidFontFamilyFinder()
+ {
+ EnumFontFamilies(g_screenDC, 0, enumFontFamProc, (LPARAM)this);
+ }
+ const String& family() const { return m_family; }
+private:
+ String m_family;
+ static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
+};
+
+class FixedSizeFontData: public RefCounted<FixedSizeFontData> {
+public:
+ LOGFONT m_font;
+ OwnPtr<HFONT> m_hfont;
+ TEXTMETRIC m_metrics;
+ DWORD m_codePages;
+ unsigned m_weight;
+ bool m_italic;
+
+ static PassRefPtr<FixedSizeFontData> create(const AtomicString& family, unsigned weight, bool italic);
+private:
+ FixedSizeFontData()
+ : m_codePages(0)
+ , m_weight(0)
+ , m_italic(false)
+ {
+ memset(&m_font, 0, sizeof(m_font));
+ memset(&m_metrics, 0, sizeof(m_metrics));
+ }
+};
+
+struct FixedSizeFontDataKey {
+ FixedSizeFontDataKey(const AtomicString& family = AtomicString(), unsigned weight = 0, bool italic = false)
+ : m_family(family)
+ , m_weight(weight)
+ , m_italic(italic)
+ {
+ }
+
+ FixedSizeFontDataKey(WTF::HashTableDeletedValueType) : m_weight(-2) { }
+ bool isHashTableDeletedValue() const { return m_weight == -2; }
+
+ bool operator==(const FixedSizeFontDataKey& other) const
+ {
+ return equalIgnoringCase(m_family, other.m_family)
+ && m_weight == other.m_weight
+ && m_italic == other.m_italic;
+ }
+
+ AtomicString m_family;
+ unsigned m_weight;
+ bool m_italic;
+};
+
+struct FixedSizeFontDataKeyHash {
+ static unsigned hash(const FixedSizeFontDataKey& font)
+ {
+ unsigned hashCodes[] = {
+ CaseFoldingHash::hash(font.m_family),
+ font.m_weight,
+ // static_cast<unsigned>(font.m_italic);
+ };
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+ }
+
+ static bool equal(const FixedSizeFontDataKey& a, const FixedSizeFontDataKey& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FixedSizeFontDataKeyTraits : WTF::GenericHashTraits<FixedSizeFontDataKey> {
+ static const bool emptyValueIsZero = true;
+ static const FixedSizeFontDataKey& emptyValue()
+ {
+ DEFINE_STATIC_LOCAL(FixedSizeFontDataKey, key, (nullAtom));
+ return key;
+ }
+ static void constructDeletedValue(FixedSizeFontDataKey& slot)
+ {
+ new (&slot) FixedSizeFontDataKey(WTF::HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FixedSizeFontDataKey& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+int CALLBACK FontFamilyChecker::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
+{
+ ((FontFamilyChecker*)lParam)->m_exists = true;
+ return 0;
+}
+
+int CALLBACK ValidFontFamilyFinder::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
+{
+ if (lpelf->lfCharSet != SYMBOL_CHARSET) {
+ ((ValidFontFamilyFinder*)lParam)->m_family = String(lpelf->lfFaceName);
+ return 0;
+ }
+ return 1;
+}
+
+typedef Vector<FontFamilyCodePageInfo> KnownFonts;
+static KnownFonts& knownFonts()
+{
+ static KnownFonts fonts;
+ static bool firstTime = true;
+ if (firstTime) {
+ firstTime = false;
+ if (FontPlatformData::isSongTiSupported())
+ fonts.append(FontFamilyCodePageInfo(songTiStr, 936));
+ }
+ return fonts;
+}
+
+static String getDefaultFontFamily()
+{
+ if (FontFamilyChecker(L"Tahoma").isSupported())
+ return String(L"Tahoma");
+
+ bool good = false;
+ String family;
+ HKEY key;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\GDI\\SysFnt", 0, 0, &key) == ERROR_SUCCESS) {
+ DWORD maxlen, type;
+ if (RegQueryValueEx(key, L"Nm", 0, &type, 0, &maxlen) == ERROR_SUCCESS && type == REG_SZ) {
+ ++maxlen;
+ if (wchar_t* buffer = new wchar_t[maxlen]) {
+ if (RegQueryValueEx(key, L"Nm", 0, &type, (LPBYTE)buffer, &maxlen) == ERROR_SUCCESS) {
+ family = String(buffer, maxlen);
+ good = true;
+ }
+ delete[] buffer;
+ }
+ }
+ RegCloseKey(key);
+ }
+ if (good)
+ return family;
+
+ return ValidFontFamilyFinder().family();
+}
+
+typedef HashMap<FixedSizeFontDataKey, RefPtr<FixedSizeFontData>, FixedSizeFontDataKeyHash, FixedSizeFontDataKeyTraits> FixedSizeFontCache;
+FixedSizeFontCache g_fixedSizeFontCache;
+
+PassRefPtr<FixedSizeFontData> FixedSizeFontData::create(const AtomicString& family, unsigned weight, bool italic)
+{
+ FixedSizeFontData* fontData = new FixedSizeFontData();
+
+ fontData->m_weight = weight;
+ fontData->m_italic = italic;
+
+ LOGFONT& winFont = fontData->m_font;
+ // The size here looks unusual. The negative number is intentional.
+ winFont.lfHeight = -72;
+ winFont.lfWidth = 0;
+ winFont.lfEscapement = 0;
+ winFont.lfOrientation = 0;
+ winFont.lfUnderline = false;
+ winFont.lfStrikeOut = false;
+ winFont.lfCharSet = DEFAULT_CHARSET;
+ winFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ winFont.lfQuality = CLEARTYPE_QUALITY; //DEFAULT_QUALITY;
+ winFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ winFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ winFont.lfItalic = italic;
+ winFont.lfWeight = FontPlatformData::adjustedGDIFontWeight(weight, family);
+
+ int len = std::min(family.length(), (unsigned int)LF_FACESIZE - 1);
+ wmemcpy(winFont.lfFaceName, family.characters(), len);
+ winFont.lfFaceName[len] = L'\0';
+
+ fontData->m_hfont.set(CreateFontIndirect(&winFont));
+
+ HGDIOBJ oldFont = SelectObject(g_screenDC, fontData->m_hfont.get());
+
+ GetTextMetrics(g_screenDC, &fontData->m_metrics);
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) {
+#else
+ if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) {
+#endif
+ langFontLink->GetFontCodePages(g_screenDC, fontData->m_hfont.get(), &fontData->m_codePages);
+ fontData->m_codePages |= FontPlatformData::getKnownFontCodePages(winFont.lfFaceName);
+ }
+
+ SelectObject(g_screenDC, oldFont);
+
+ return adoptRef(fontData);
+}
+
+static PassRefPtr<FixedSizeFontData> createFixedSizeFontData(const AtomicString& family, unsigned weight, bool italic)
+{
+ FixedSizeFontDataKey key(family, weight, italic);
+ pair<FixedSizeFontCache::iterator, bool> result = g_fixedSizeFontCache.add(key, RefPtr<FixedSizeFontData>());
+ if (result.second)
+ result.first->second = FixedSizeFontData::create(family, weight, italic);
+
+ return result.first->second;
+}
+
+static LONG toGDIFontWeight(FontWeight fontWeight)
+{
+ static LONG gdiFontWeights[] = {
+ FW_THIN, // FontWeight100
+ FW_EXTRALIGHT, // FontWeight200
+ FW_LIGHT, // FontWeight300
+ FW_NORMAL, // FontWeight400
+ FW_MEDIUM, // FontWeight500
+ FW_SEMIBOLD, // FontWeight600
+ FW_BOLD, // FontWeight700
+ FW_EXTRABOLD, // FontWeight800
+ FW_HEAVY // FontWeight900
+ };
+ return gdiFontWeights[fontWeight];
+}
+
+class FontPlatformPrivateData {
+public:
+ int m_reference;
+ RefPtr<FixedSizeFontData> m_rootFontData;
+ AtomicString m_family;
+ FontDescription m_fontDescription;
+ OwnPtr<HFONT> m_hfontScaled;
+ int m_size;
+ long m_fontScaledWidth;
+ long m_fontScaledHeight;
+ bool m_disabled;
+ FontPlatformPrivateData(int size, unsigned weight)
+ : m_reference(1)
+ , m_family(FontPlatformData::defaultFontFamily())
+ , m_size(size)
+ , m_fontScaledWidth(0)
+ , m_fontScaledHeight(0)
+ , m_disabled(false)
+ {
+ m_rootFontData = createFixedSizeFontData(m_family, weight, false);
+ }
+ FontPlatformPrivateData(const FontDescription& fontDescription, const AtomicString& family)
+ : m_reference(1)
+ , m_size(fontDescription.computedPixelSize())
+ , m_fontDescription(fontDescription)
+ , m_family(family)
+ , m_fontScaledWidth(0)
+ , m_fontScaledHeight(0)
+ , m_disabled(!fontDescription.specifiedSize())
+ {
+ m_rootFontData = FixedSizeFontData::create(family, toGDIFontWeight(fontDescription.weight()), fontDescription.italic());
+ }
+};
+
+FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& desiredFamily, bool useDefaultFontIfNotPresent)
+{
+ String family(desiredFamily);
+ if (!equalIgnoringCase(family, defaultFontFamily()) && !FontFamilyChecker(family.charactersWithNullTermination()).isSupported()) {
+ if (equalIgnoringCase(family, String(heiTiStr)) && isSongTiSupported())
+ family = String(songTiStr);
+ else if (useDefaultFontIfNotPresent)
+ family = defaultFontFamily();
+ }
+
+ m_private = new FontPlatformPrivateData(fontDescription, family);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+{
+ if (!size)
+ m_private = 0;
+ else
+ m_private = new FontPlatformPrivateData((int)(size + 0.5), bold ? FW_BOLD : FW_NORMAL);
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ if (isValid() && !--m_private->m_reference) {
+ if (m_private->m_rootFontData->refCount() == 2) {
+ FixedSizeFontDataKey key(m_private->m_family, m_private->m_rootFontData->m_weight, m_private->m_rootFontData->m_italic);
+ g_fixedSizeFontCache.remove(key);
+ }
+ delete m_private;
+ }
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& o)
+{
+ if (isValid() && !--m_private->m_reference)
+ delete m_private;
+
+ if (m_private = o.m_private)
+ ++m_private->m_reference;
+
+ return *this;
+}
+
+HFONT FontPlatformData::hfont() const
+{
+ if (!isValid())
+ return 0;
+
+ if (m_private->m_disabled)
+ return 0;
+
+ if (!m_private->m_rootFontData->m_hfont)
+ m_private->m_rootFontData->m_hfont.set(CreateFontIndirect(&m_private->m_rootFontData->m_font));
+
+ return m_private->m_rootFontData->m_hfont.get();
+}
+
+HFONT FontPlatformData::getScaledFontHandle(int height, int width) const
+{
+ if (!isValid() || m_private->m_disabled)
+ return 0;
+
+ if (!m_private->m_hfontScaled || m_private->m_fontScaledHeight != height || m_private->m_fontScaledWidth != width) {
+ m_private->m_fontScaledHeight = height;
+ m_private->m_fontScaledWidth = width;
+ LOGFONT font = m_private->m_rootFontData->m_font;
+ font.lfHeight = -height;
+ font.lfWidth = width;
+ m_private->m_hfontScaled.set(CreateFontIndirect(&font));
+ }
+
+ return m_private->m_hfontScaled.get();
+}
+
+bool FontPlatformData::discardFontHandle()
+{
+ if (!isValid())
+ return false;
+
+ if (m_private->m_rootFontData->m_hfont) {
+ m_private->m_rootFontData->m_hfont.set(0);
+ return true;
+ }
+
+ if (m_private->m_hfontScaled) {
+ m_private->m_hfontScaled.set(0);
+ return true;
+ }
+ return false;
+}
+
+const TEXTMETRIC& FontPlatformData::metrics() const
+{
+ return m_private->m_rootFontData->m_metrics;
+}
+
+bool FontPlatformData::isSystemFont() const
+{
+ return false;
+}
+
+int FontPlatformData::size() const
+{
+ return m_private->m_size;
+}
+
+const FontDescription& FontPlatformData::fontDescription() const
+{
+ return m_private->m_fontDescription;
+}
+
+const AtomicString& FontPlatformData::family() const
+{
+ return m_private->m_family;
+}
+
+const LOGFONT& FontPlatformData::logFont() const
+{
+ return m_private->m_rootFontData->m_font;
+}
+
+int FontPlatformData::averageCharWidth() const
+{
+ return (m_private->m_rootFontData->m_metrics.tmAveCharWidth * size() + 36) / 72;
+}
+
+bool FontPlatformData::isDisabled() const
+{
+ return !isValid() || m_private->m_disabled;
+}
+
+DWORD FontPlatformData::codePages() const
+{
+ return m_private->m_rootFontData->m_codePages;
+}
+
+bool FontPlatformData::isSongTiSupported()
+{
+ static bool exists = FontFamilyChecker(songTiStr).isSupported();
+ return exists;
+}
+
+bool FontPlatformData::mapKnownFont(DWORD codePages, String& family)
+{
+ KnownFonts& fonts = knownFonts();
+ for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
+ if (i->codePages() & codePages) {
+ family = i->m_family;
+ return true;
+ }
+ }
+ return false;
+}
+
+DWORD FontPlatformData::getKnownFontCodePages(const wchar_t* family)
+{
+ KnownFonts& fonts = knownFonts();
+ for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
+ if (equalIgnoringCase(i->m_family, String(family)))
+ return i->codePages();
+ }
+ return 0;
+}
+
+const String& FontPlatformData::defaultFontFamily()
+{
+ static String family(getDefaultFontFamily());
+ return family;
+}
+
+LONG FontPlatformData::adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
+{
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr)) {
+ if (gdiFontWeight == FW_NORMAL)
+ return FW_MEDIUM;
+ if (gdiFontWeight == FW_BOLD)
+ return FW_SEMIBOLD;
+ }
+ return gdiFontWeight;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/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 <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/text/StringImpl.h>
+
+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<unsigned>(m_private) & ~1; }
+ HFONT hfont() const;
+ const TEXTMETRIC& metrics() const;
+ bool isSystemFont() const;
+ int size() const;
+ unsigned hash() const { return (unsigned)m_private; }
+ const FontDescription& fontDescription() const;
+ const AtomicString& family() const;
+ bool operator==(const FontPlatformData& other) const { return m_private == other.m_private; }
+ HFONT getScaledFontHandle(int height, int width) const;
+ const LOGFONT& logFont() const;
+ int averageCharWidth() const;
+ bool isDisabled() const;
+ bool discardFontHandle();
+ DWORD codePages() const;
+
+ static bool isSongTiSupported();
+ static bool mapKnownFont(DWORD codePages, String& family);
+ static DWORD getKnownFontCodePages(const wchar_t* family);
+ static const String& defaultFontFamily();
+ static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family);
+
+ 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 <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/unicode/Unicode.h>
+
+#include <windows.h>
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+HDC g_screenDC = GetDC(0);
+
+class ScreenDcReleaser {
+public:
+ ~ScreenDcReleaser()
+ {
+ ReleaseDC(0, g_screenDC);
+ }
+};
+
+ScreenDcReleaser releaseScreenDc;
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point);
+}
+
+class TextRunComponent {
+public:
+ TextRunComponent() : m_textRun(0, 0) {}
+ TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset);
+ TextRunComponent(int spaces, const Font &font, int offset);
+ ~TextRunComponent() { m_textRun; }
+
+ bool isSpace() const { return m_spaces; }
+ int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); }
+
+ TextRun m_textRun;
+ float m_width;
+ int m_offset;
+ int m_spaces;
+};
+
+TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o)
+ : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0
+ , parentTextRun.rtl()
+ , parentTextRun.directionalOverride()
+ , parentTextRun.applyRunRounding()
+ , parentTextRun.applyWordRounding())
+ , m_offset(o)
+ , m_spaces(0)
+{
+ WidthIterator it(&font, m_textRun);
+ it.advance(m_textRun.length(), 0);
+ m_width = it.m_runWidthSoFar;
+}
+
+TextRunComponent::TextRunComponent(int s, const Font &font, int o)
+ : m_textRun(0, 0)
+ , m_offset(o)
+ , m_spaces(s)
+{
+ m_width = s * font.primaryFont()->widthForGlyph(' ');
+}
+
+typedef Vector<TextRunComponent, 128> TextRunComponents;
+
+static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run)
+{
+ int letterSpacing = font.letterSpacing();
+ int wordSpacing = font.wordSpacing();
+ int padding = run.padding();
+ int numSpaces = 0;
+ if (padding) {
+ for (int i = 0; i < run.length(); i++)
+ if (Font::treatAsSpace(run[i]))
+ ++numSpaces;
+ }
+
+ int offset = 0;
+ if (letterSpacing) {
+ // need to draw every letter on it's own
+ int start = 0;
+ if (Font::treatAsSpace(run[0])) {
+ int add = 0;
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += add + letterSpacing + components->last().m_width;
+ start = 1;
+ }
+ for (int i = 1; i < run.length(); ++i) {
+ uint ch = run[i];
+ if (isHighSurrogate(ch) && isLowSurrogate(run[i-1]))
+ ch = surrogateToUcs4(ch, run[i-1]);
+ if (isLowSurrogate(ch) || category(ch) == Mark_NonSpacing)
+ continue;
+ if (Font::treatAsSpace(run[i])) {
+ int add = 0;
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run, font, offset));
+ offset += components->last().m_width + letterSpacing;
+ }
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += wordSpacing + add + components->last().m_width + letterSpacing;
+ start = i + 1;
+ continue;
+ }
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run,
+ font, offset));
+ offset += components->last().m_width + letterSpacing;
+ }
+ start = i;
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ offset += letterSpacing;
+ } else {
+ int start = 0;
+ for (int i = 0; i < run.length(); ++i) {
+ if (Font::treatAsSpace(run[i])) {
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ int add = 0;
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += add + components->last().m_width;
+ if (i)
+ offset += wordSpacing;
+ start = i + 1;
+ }
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ }
+ return offset;
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
+ int from, int to) const
+{
+ if (to < 0)
+ to = run.length();
+ if (from < 0)
+ from = 0;
+
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+
+ int curPos = 0;
+ for (int i = 0; i < (int)components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int len = comp.textLength();
+ int curEnd = curPos + len;
+ if (curPos < to && from < curEnd && !comp.isSpace()) {
+ FloatPoint pt = point;
+ if (run.rtl())
+ pt.setX(point.x() + w - comp.m_offset - comp.m_width);
+ else
+ pt.setX(point.x() + comp.m_offset);
+ drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos);
+ }
+ curPos += len;
+ if (from < curPos)
+ from = curPos;
+ }
+}
+
+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<const SimpleFontData*>* 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<int>(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<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
+ : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
+
+ offset += comp.textLength();
+ }
+ } else {
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int xs = comp.m_offset;
+ int xe = xs + comp.m_width;
+ if (position <= xe) {
+ if (position - xs >= xe)
+ return offset + comp.textLength();
+ return offset + (comp.isSpace()
+ ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
+ : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
+ }
+ offset += comp.textLength();
+ }
+ }
+ return run.length();
+}
+
+
+static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor)
+{
+ int start = 0;
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ if (start + comp.textLength() <= cursor) {
+ start += comp.textLength();
+ continue;
+ }
+ int xs = comp.m_offset;
+ if (rtl)
+ xs = width - xs - comp.m_width;
+
+ int pos = cursor - start;
+ if (comp.isSpace()) {
+ if (rtl)
+ pos = comp.textLength() - pos;
+ return xs + pos * comp.m_width / comp.m_spaces;
+ }
+ WidthIterator it(font, comp.m_textRun);
+ it.advance(pos);
+ return xs + it.m_runWidthSoFar;
+ }
+ return width;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const 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::ColorStop, 2>& 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 <paroga@paroga.com>
+ *
+ * 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 <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops);
+typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops);
+FuncGradientFillRectLinear g_linearGradientFiller = 0;
+FuncGradientFillRectRadial g_radialGradientFiller = 0;
+
+static inline bool isZero(double d)
+{
+ return d > 0 ? d <= 1.E-10 : d >= -1.E-10;
+}
+
+// stableRound rounds -0.5 to 0, where lround rounds -0.5 to -1.
+static inline int stableRound(double d)
+{
+ if (d > 0)
+ return static_cast<int>(d + 0.5);
+
+ int i = static_cast<int>(d);
+ return i - d > 0.5 ? i - 1 : i;
+}
+
+// Unlike enclosingIntRect(), this function does strict rounding.
+static inline IntRect roundRect(const FloatRect& r)
+{
+ return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.right()) - stableRound(r.x()), stableRound(r.bottom()) - stableRound(r.y()));
+}
+
+// Rotation transformation
+class RotationTransform {
+public:
+ RotationTransform()
+ : m_cosA(1.)
+ , m_sinA(0.)
+ , m_preShiftX(0)
+ , m_preShiftY(0)
+ , m_postShiftX(0)
+ , m_postShiftY(0)
+ {
+ }
+ RotationTransform operator-() const
+ {
+ RotationTransform rtn;
+ rtn.m_cosA = m_cosA;
+ rtn.m_sinA = -m_sinA;
+ rtn.m_preShiftX = m_postShiftX;
+ rtn.m_preShiftY = m_postShiftY;
+ rtn.m_postShiftX = m_preShiftX;
+ rtn.m_postShiftY = m_preShiftY;
+ return rtn;
+ }
+ void map(double x1, double y1, double* x2, double* y2) const
+ {
+ x1 += m_preShiftX;
+ y1 += m_preShiftY;
+ *x2 = x1 * m_cosA + y1 * m_sinA + m_postShiftX;
+ *y2 = y1 * m_cosA - x1 * m_sinA + m_postShiftY;
+ }
+ void map(int x1, int y1, int* x2, int* y2) const
+ {
+ x1 += m_preShiftX;
+ y1 += m_preShiftY;
+ *x2 = stableRound(x1 * m_cosA + y1 * m_sinA) + m_postShiftX;
+ *y2 = stableRound(y1 * m_cosA - x1 * m_sinA) + m_postShiftY;
+ }
+
+ double m_cosA;
+ double m_sinA;
+ int m_preShiftX;
+ int m_preShiftY;
+ int m_postShiftX;
+ int m_postShiftY;
+};
+
+template<class T> static inline IntPoint mapPoint(const IntPoint& p, const T& t)
+{
+ int x, y;
+ t.map(p.x(), p.y(), &x, &y);
+ return IntPoint(x, y);
+}
+
+template<class T> static inline FloatPoint mapPoint(const FloatPoint& p, const T& t)
+{
+ double x, y;
+ t.map(p.x(), p.y(), &x, &y);
+ return FloatPoint(static_cast<float>(x), static_cast<float>(y));
+}
+
+template<class Transform, class Rect, class Value> static inline Rect mapRect(const Rect& rect, const Transform& transform)
+{
+ Value x[4], y[4];
+ Value l, t, r, b;
+ r = rect.right() - 1;
+ b = rect.bottom() - 1;
+ transform.map(rect.x(), rect.y(), x, y);
+ transform.map(rect.x(), b, x + 1, y + 1);
+ transform.map(r, b, x + 2, y + 2);
+ transform.map(r, rect.y(), x + 3, y + 3);
+ l = r = x[3];
+ t = b = y[3];
+ for (int i = 0; i < 3; ++i) {
+ if (x[i] < l)
+ l = x[i];
+ else if (x[i] > r)
+ r = x[i];
+
+ if (y[i] < t)
+ t = y[i];
+ else if (y[i] > b)
+ b = y[i];
+ }
+
+ return IntRect(l, t, r - l + 1, b - t + 1);
+}
+
+template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform)
+{
+ return mapRect<T, IntRect, int>(rect, transform);
+}
+
+template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform)
+{
+ return mapRect<T, FloatRect, double>(rect, transform);
+}
+
+class GraphicsContextPlatformPrivateData {
+public:
+ GraphicsContextPlatformPrivateData()
+ : m_transform()
+ , m_opacity(1.0)
+ {
+ }
+
+ 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<float>(w), static_cast<float>(h));
+ }
+
+ void save()
+ {
+ if (m_dc)
+ SaveDC(m_dc);
+
+ m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this));
+ }
+
+ void restore()
+ {
+ if (m_backupData.isEmpty())
+ return;
+
+ if (m_dc)
+ RestoreDC(m_dc, -1);
+
+ GraphicsContextPlatformPrivateData::operator=(m_backupData.last());
+ m_backupData.removeLast();
+ }
+
+ bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); }
+
+ PassRefPtr<SharedBitmap> getTransparentLayerBitmap(IntRect& origRect, AlphaPaintType alphaPaint, RECT& bmpRect, bool checkClipBox, bool force) const
+ {
+ if (m_opacity <= 0)
+ return 0;
+
+ if (force || m_opacity < 1.) {
+ if (checkClipBox) {
+ RECT clipBox;
+ int clipType = GetClipBox(m_dc, &clipBox);
+ if (clipType == SIMPLEREGION || clipType == COMPLEXREGION)
+ origRect.intersect(clipBox);
+ if (origRect.isEmpty())
+ return 0;
+ }
+
+ RefPtr<SharedBitmap> bmp = SharedBitmap::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<SharedBitmap> m_bitmap;
+ Vector<GraphicsContextPlatformPrivateData> m_backupData;
+};
+
+static PassOwnPtr<HPEN> createPen(const Color& col, double fWidth, StrokeStyle style)
+{
+ int width = stableRound(fWidth);
+ if (width < 1)
+ width = 1;
+
+ int penStyle = PS_NULL;
+ switch (style) {
+ case SolidStroke:
+ penStyle = PS_SOLID;
+ break;
+ case DottedStroke: // not supported on Windows CE
+ case DashedStroke:
+ penStyle = PS_DASH;
+ width = 1;
+ break;
+ default:
+ break;
+ }
+
+ return adoptPtr(CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue())));
+}
+
+static inline PassOwnPtr<HBRUSH> createBrush(const Color& col)
+{
+ return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue())));
+}
+
+template <typename PixelType, bool Is16bit> static void _rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
+{
+ int destW = destBmp->width();
+ int destH = destBmp->height();
+ int sourceW = sourceBmp->width();
+ int sourceH = sourceBmp->height();
+ PixelType* dest = (PixelType*)destBmp->bytes();
+ const PixelType* source = (const PixelType*)sourceBmp->bytes();
+ int padding;
+ int paddedSourceW;
+ if (Is16bit) {
+ padding = destW & 1;
+ paddedSourceW = sourceW + (sourceW & 1);
+ } else {
+ padding = 0;
+ paddedSourceW = sourceW;
+ }
+ if (isZero(transform.m_sinA)) {
+ int cosA = transform.m_cosA > 0 ? 1 : -1;
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ int x1 = x + transform.m_preShiftX;
+ int y1 = y + transform.m_preShiftY;
+ int srcX = x1 * cosA + transform.m_postShiftX;
+ int srcY = y1 * cosA - transform.m_postShiftY;
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX] | 0xFF000000;
+ else
+ *dest++ |= 0xFF;
+ }
+ dest += padding;
+ }
+ } else if (isZero(transform.m_cosA)) {
+ int sinA = transform.m_sinA > 0 ? 1 : -1;
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ int x1 = x + transform.m_preShiftX;
+ int y1 = y + transform.m_preShiftY;
+ int srcX = y1 * sinA + transform.m_postShiftX;
+ int srcY = -x1 * sinA + transform.m_postShiftY;
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX];
+ }
+ dest += padding;
+ }
+ } else {
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ // FIXME: for best quality, we should get weighted sum of four neighbours,
+ // but that will be too expensive
+ int srcX, srcY;
+ transform.map(x, y, &srcX, &srcY);
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX];
+ }
+ dest += padding;
+ }
+ }
+}
+
+static void rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
+{
+ ASSERT(destBmp->is16bit() == sourceBmp->is16bit());
+ if (destBmp->is16bit())
+ _rotateBitmap<unsigned short, true>(destBmp, sourceBmp, transform);
+ else
+ _rotateBitmap<unsigned, false>(destBmp, sourceBmp, transform);
+}
+
+class TransparentLayerDC : Noncopyable {
+public:
+ TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform = 0, int alpha = 255, bool paintImage = false);
+ ~TransparentLayerDC();
+
+ HDC hdc() const { return m_memDc; }
+ const RECT& rect() const { return m_bmpRect; }
+ IntSize toShift() const { return IntSize(m_bmpRect.left - m_origRect.x(), m_bmpRect.top - m_origRect.y()); }
+ void fillAlphaChannel();
+
+private:
+ GraphicsContextPlatformPrivate* m_data;
+ IntRect m_origRect;
+ IntRect m_rotatedOrigRect;
+ HDC m_memDc;
+ RefPtr<SharedBitmap> m_bitmap;
+ RefPtr<SharedBitmap> m_rotatedBitmap;
+ RECT m_bmpRect;
+ unsigned m_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<SharedBitmap> 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<HBRUSH> brush;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush.get());
+ } else
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ OwnPtr<HPEN> 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<HPEN> 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<HBRUSH> brush;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush.get());
+ } else
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ OwnPtr<HPEN> 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<HPEN> 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<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ bool newClip;
+ if (GetClipRgn(dc, clipRgn.get()) <= 0) {
+ newClip = true;
+ clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
+ SelectClipRgn(dc, clipRgn.get());
+ } else {
+ newClip = false;
+ IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+ }
+
+ HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+ Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ SelectObject(dc, oldBrush);
+
+ if (newClip)
+ SelectClipRgn(dc, 0);
+ else
+ SelectClipRgn(dc, clipRgn.get());
+
+ SelectObject(dc, oldPen);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (!m_data->m_opacity || paintingDisabled() || npoints <= 1 || !points)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ Vector<POINT, 20> winPoints(npoints);
+ FloatPoint trPoint = m_data->mapPoint(points[0]);
+ winPoints[0].x = stableRound(trPoint.x());
+ winPoints[0].y = stableRound(trPoint.y());
+ RECT rect = { winPoints[0].x, winPoints[0].y, winPoints[0].x, winPoints[0].y };
+ for (size_t i = 1; i < npoints; ++i) {
+ trPoint = m_data->mapPoint(points[i]);
+ winPoints[i].x = stableRound(trPoint.x());
+ winPoints[i].y = stableRound(trPoint.y());
+ if (rect.left > winPoints[i].x)
+ rect.left = winPoints[i].x;
+ else if (rect.right < winPoints[i].x)
+ rect.right = winPoints[i].x;
+ if (rect.top > winPoints[i].y)
+ rect.top = winPoints[i].y;
+ else if (rect.bottom < winPoints[i].y)
+ rect.bottom = winPoints[i].y;
+ }
+ rect.bottom += 1;
+ rect.right += 1;
+
+ IntRect intRect(rect);
+ TransparentLayerDC transparentDC(m_data, intRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+
+ for (size_t i = 0; i < npoints; ++i) {
+ winPoints[i].x += transparentDC.toShift().width();
+ winPoints[i].y += transparentDC.toShift().height();
+ }
+
+ OwnPtr<HBRUSH> brush;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush.get());
+ } else
+ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ OwnPtr<HPEN> 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> hbrush(CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
+ FillRect(transparentDC.hdc(), &transparentDC.rect(), hbrush.get());
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0)
+ IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ else {
+ clipRgn.set(CreateRectRgn(trRect.x(), trRect.y(), trRect.right(), trRect.bottom()));
+ SelectClipRgn(m_data->m_dc, clipRgn.get());
+ }
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+
+ ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: implement
+}
+
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& 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<HPEN> 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<HBRUSH> 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<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ bool needsNewClip = (GetClipRgn(dc, clipRgn.get()) <= 0);
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopLeft.width() * 2), stableRound(newTopLeft.height() * 2));
+
+ // Draw top right
+ clipRect = rectWin;
+ clipRect.left = centerPoint.x();
+ clipRect.bottom = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopRight.width() * 2), stableRound(newTopRight.height() * 2));
+
+ // Draw bottom left
+ clipRect = rectWin;
+ clipRect.right = centerPoint.x();
+ clipRect.top = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomLeft.width() * 2), stableRound(newBottomLeft.height() * 2));
+
+ // Draw bottom right
+ clipRect = rectWin;
+ clipRect.left = centerPoint.x();
+ clipRect.top = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2));
+
+ SelectObject(dc, oldBrush);
+}
+
+
+void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height)
+{
+ if (!dc)
+ return;
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ if (needsNewClip) {
+ clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
+ SelectClipRgn(dc, clipRgn.get());
+ } else
+ IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+
+ ::RoundRect(dc, rectWin.left , rectWin.top , rectWin.right , rectWin.bottom , width, height);
+
+ SelectClipRgn(dc, needsNewClip ? 0 : clipRgn.get());
+}
+
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ notImplemented();
+ return frect;
+}
+
+Color gradientAverageColor(const Gradient* gradient)
+{
+ const Vector<Gradient::ColorStop>& stops = gradient->getStops();
+ if (stops.isEmpty())
+ return Color();
+
+ const Gradient::ColorStop& stop = stops.first();
+ if (stops.size() == 1)
+ return Color(stop.red, stop.green, stop.blue, stop.alpha);
+
+ const Gradient::ColorStop& lastStop = stops.last();
+ return Color((stop.red + lastStop.red) * 0.5f
+ , (stop.green + lastStop.green) * 0.5f
+ , (stop.blue + lastStop.blue) * 0.5f
+ , (stop.alpha + lastStop.alpha) * 0.5f);
+}
+
+void GraphicsContext::fillPath(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<HBRUSH> 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<HPEN> 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<Gradient::ColorStop>& stops = gradient->getStops();
+ if (stops.isEmpty())
+ return;
+
+ size_t numStops = stops.size();
+ if (numStops == 1) {
+ const Gradient::ColorStop& stop = stops.first();
+ Color color(stop.red, stop.green, stop.blue, stop.alpha);
+ fillRect(r, color, 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<TRIVERTEX, 20> tv;
+ tv.resize(numRects * 2);
+ Vector<GRADIENT_RECT, 10> mesh;
+ mesh.resize(numRects);
+ int x = rect.x();
+ int y = rect.y();
+ int width = rect.width();
+ int height = rect.height();
+ FloatSize d = gradient->p1() - gradient->p0();
+ bool vertical = 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<SharedBitmap> bmp = m_data->getTransparentLayerBitmap(trRect, alphaPaintType, bmpRect, true, mustSupportAlpha)) {
+ {
+ GraphicsContext gc(0);
+ gc.setBitmap(bmp);
+ gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d()));
+ font.drawText(&gc, run, IntPoint(0, font.ascent()), from, to);
+ }
+ unsigned key1;
+ 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> 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<int, 256> glyphSpace(numGlyphs);
+ Vector<UChar, 256> text(numGlyphs);
+ int* curSpace = glyphSpace.data();
+ UChar* curChar = text.data();
+ const UChar* srcChar = glyphBuffer.glyphs(from);
+ const UChar* const srcCharEnd = srcChar + numGlyphs;
+ *curChar++ = *srcChar++;
+ int firstOffset = stableRound(offset);
+ int lastOffset = firstOffset;
+ const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
+ // FIXME: ExtTextOut() can flip over each word for RTL languages, even when TA_RTLREADING is off.
+ // (this can be GDI bug or font driver bug?)
+ // We are not clear how it processes characters and handles specified spaces. On the other side,
+ // our glyph buffer is already in the correct order for rendering. So, the solution is that we
+ // call ExtTextOut() for each single character when the text contains any RTL character.
+ // This solution is not perfect as it is slower than calling ExtTextOut() one time for all characters.
+ // Drawing characters one by one may be too slow.
+ bool drawOneByOne = false;
+ if (scaleX == 1.) {
+ for (; srcChar < srcCharEnd; ++srcChar) {
+ offset += *advance++;
+ int offsetInt = stableRound(offset);
+ if (isCharVisible(*srcChar)) {
+ if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
+ drawOneByOne = true;
+ *curChar++ = *srcChar;
+ *curSpace++ = offsetInt - lastOffset;
+ lastOffset = offsetInt;
+ }
+ }
+ } else {
+ for (; srcChar < srcCharEnd; ++srcChar) {
+ offset += *advance++ * scaleX;
+ int offsetInt = stableRound(offset);
+ if (isCharVisible(*srcChar)) {
+ if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
+ drawOneByOne = true;
+ *curChar++ = *srcChar;
+ *curSpace++ = offsetInt - lastOffset;
+ lastOffset = offsetInt;
+ }
+ }
+ }
+ numGlyphs = curChar - text.data();
+ if (hasShadow) {
+ SetTextColor(m_data->m_dc, shadowRGBColor);
+ if (drawOneByOne) {
+ int xShadow = firstOffset + stableRound(trShadowPoint.x() - trPoint.x());
+ int yShadow = stableRound(trShadowPoint.y());
+ for (int i = 0; i < numGlyphs; ++i) {
+ ExtTextOut(m_data->m_dc, xShadow, yShadow, 0, NULL, text.data() + i, 1, 0);
+ xShadow += glyphSpace[i];
+ }
+ } else
+ ExtTextOut(m_data->m_dc, firstOffset + stableRound(trShadowPoint.x() - trPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, text.data(), numGlyphs, glyphSpace.data());
+ }
+ SetTextColor(m_data->m_dc, fontColor);
+ if (drawOneByOne) {
+ int x = firstOffset;
+ for (int i = 0; i < numGlyphs; ++i) {
+ ExtTextOut(m_data->m_dc, x, y, 0, NULL, text.data() + i, 1, 0);
+ x += glyphSpace[i];
+ }
+ } else
+ ExtTextOut(m_data->m_dc, firstOffset, y, 0, NULL, text.data(), numGlyphs, glyphSpace.data());
+ } else {
+ UChar c = *glyphBuffer.glyphs(from);
+ if (hasShadow) {
+ SetTextColor(m_data->m_dc, shadowRGBColor);
+ ExtTextOut(m_data->m_dc, stableRound(trShadowPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, &c, 1, 0);
+ }
+ SetTextColor(m_data->m_dc, fontColor);
+ ExtTextOut(m_data->m_dc, stableRound(trPoint.x()), y, 0, NULL, &c, 1, 0);
+ }
+
+ SetTextAlign(m_data->m_dc, oldTextAlign);
+ SetTextColor(m_data->m_dc, oldTextColor);
+ SetBkMode(m_data->m_dc, oldBkMode);
+ SelectObject(m_data->m_dc, hOldFont);
+}
+
+void GraphicsContext::drawFrameControl(const IntRect& rect, unsigned type, unsigned state)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ const int boxWidthBest = 8;
+ const int boxHeightBest = 8;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rectWin = trRect;
+
+ if ((rectWin.right - rectWin.left) < boxWidthBest) {
+ RefPtr<SharedBitmap> bmp = SharedBitmap::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<HBRUSH>(((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<SharedBitmap> 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 <wtf/UnusedParam.h>
+
+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<Image> 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<Image> 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<Image> imageCopy = copyImage();
+ imageCopy->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+template <bool premultiplied>
+static PassRefPtr<ByteArray> getImageData(const IntRect& rect, const SharedBitmap* bitmap)
+{
+ RefPtr<ByteArray> imageData = ByteArray::create(rect.width() * rect.height() * 4);
+
+ const unsigned char* src = static_cast<const unsigned char*>(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<unsigned char>((red * alpha + 254) / 255);
+ *dst++ = static_cast<unsigned char>((green * alpha + 254) / 255);
+ *dst++ = static_cast<unsigned char>((blue * alpha + 254) / 255);
+ *dst++ = static_cast<unsigned char>(alpha);
+ } else {
+ *dst++ = static_cast<unsigned char>(red);
+ *dst++ = static_cast<unsigned char>(green);
+ *dst++ = static_cast<unsigned char>(blue);
+ *dst++ = static_cast<unsigned char>(alpha);
+ ++src;
+ }
+ }
+ src += srcSkip;
+ dst += dstSkip;
+ }
+
+ return imageData.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<false>(rect, m_data.m_bitmap.get());
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<true>(rect, m_data.m_bitmap.get());
+}
+
+template <bool premultiplied>
+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<unsigned char>(blue * 255 / alpha);
+ *dst++ = static_cast<unsigned char>(green * 255 / alpha);
+ *dst++ = static_cast<unsigned char>(red * 255 / alpha);
+ *dst++ = static_cast<unsigned char>(alpha);
+ } else {
+ *dst++ = static_cast<unsigned char>(blue);
+ *dst++ = static_cast<unsigned char>(green);
+ *dst++ = static_cast<unsigned char>(red);
+ *dst++ = static_cast<unsigned char>(alpha);
+ }
+ }
+ src += srcSkip;
+ dst += dstSkip;
+ }
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<false>(source, sourceSize, sourceRect, destPoint, m_data.m_bitmap.get());
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<true>(source, sourceSize, sourceRect, destPoint, m_data.m_bitmap.get());
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& 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 <paroga@paroga.com>
+ *
+ * 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 <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+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> 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<SharedBitmap> bmp = frameAtIndex(i);
+ if (!bmp || bmp->height() != static_cast<unsigned>(srcSize.height()) || bmp->width() != static_cast<unsigned>(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<SharedBitmap> bmp = frameAtIndex(m_currentFrame);
+
+ if (bmp->width() != m_source.size().width()) {
+ double scaleFactor = static_cast<double>(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<SharedBitmap> 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<SharedBitmap> 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 <wtf/Forward.h>
+#include "MediaPlayerPrivate.h"
+#include "Timer.h"
+#include <wtf/OwnPtr.h>
+
+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<TimeRanges> 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<MediaPlayerPrivate>*);
+ 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<String>& types);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable();
+
+ MediaPlayer* m_player;
+ float m_seekTo;
+ float m_endTime;
+ Timer<MediaPlayerPrivate> 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 <runtime/Identifier.h>
+
+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<RenderWidget*>(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<HTMLMediaElement*>(m_mediaPlayer->mediaPlayerClient());
+ String url = element->initialURL();
+
+ if (url.isEmpty())
+ return;
+
+ Frame* frame = element->document()->frame();
+ Vector<String> paramNames;
+ Vector<String> 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<RenderPartObject*>(element->renderer()), url, nullAtom, serviceType, paramNames, paramValues);
+ m_init = true;
+
+}
+
+HTMLMediaElement* WebMediaPlayerProxy::element()
+{
+ return static_cast<HTMLMediaElement*>(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 <wtf/Forward.h>
+#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 <wtf/OwnPtr.h>
+
+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 <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+// Implemented in GraphicsContextWinCE.cpp
+void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y);
+
+static void quadCurve(int segments, Vector<PathPoint>& 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<PathPoint>& 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<PathPolygon>& polygons, bool fill, const AffineTransform* transformation)
+{
+ for (Vector<PathPolygon>::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<PathPoint>::iterator i = begin(); i < end(); ++i)
+ i->move(offset);
+}
+
+void PathPolygon::transform(const AffineTransform& t)
+{
+ for (Vector<PathPoint>::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<PathPoint>::const_iterator last = end();
+ // wasNegative: -1 means unknown, 0 means false, 1 means true.
+ int wasNegative = -1;
+ for (Vector<PathPoint>::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<PathPoint>::const_iterator jLast = i;
+ Vector<PathPoint>::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<PathPolygon>::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<PathPolygon>::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<PathPolygon>::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 <wtf/Vector.h>
+
+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<PathPoint> {
+ 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<PlatformPathElement> 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<PathPolygon> 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 <paroga@paroga.com>
+ *
+ * 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 <wtf/HashSet.h>
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/PassOwnArrayPtr.h>
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+#ifndef NDEBUG
+static WTF::RefCountedLeakCounter sharedBitmapLeakCounter("SharedBitmap");
+#endif
+
+
+PassRefPtr<SharedBitmap> SharedBitmap::create(const IntSize& size, BitmapInfo::BitCount bitCount, bool initPixels)
+{
+ RefPtr<SharedBitmap> resultantBitmap = adoptRef(new SharedBitmap(size, bitCount, initPixels));
+ if (resultantBitmap && !resultantBitmap->bytes())
+ return 0;
+ return resultantBitmap.release();
+}
+
+PassRefPtr<SharedBitmap> SharedBitmap::create(const Vector<unsigned>& data, const IntSize& size, bool hasAlpha)
+{
+ RefPtr<SharedBitmap> 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<wchar_t*>(m_pixels), 0xFFFF, bufferSize);
+ return;
+ }
+
+ // Make it white but transparent
+ unsigned* pixel = static_cast<unsigned*>(m_pixels);
+ const unsigned* bufferEnd = pixel + bufferSize;
+ while (pixel < bufferEnd)
+ *pixel++ = 0x00FFFFFF;
+}
+
+static inline unsigned short convert32To16(unsigned pixel)
+{
+ unsigned short r = static_cast<unsigned short>((pixel & 0x00F80000) >> 8);
+ unsigned short g = static_cast<unsigned short>((pixel & 0x0000FC00) >> 5);
+ unsigned short b = static_cast<unsigned short>((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<unsigned> newPixelData(new unsigned[bufferSize / 2]);
+ void* newPixels = newPixelData.get();
+
+ if (!newPixels)
+ return false;
+
+ unsigned short* p16 = static_cast<unsigned short*>(newPixels);
+ const unsigned* p32 = static_cast<const unsigned*>(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<HBITMAP> 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<HBITMAP> hbmp = adoptPtr(CreateDIBSection(0, bmpInfo, DIB_RGB_COLORS, pixels, 0, 0));
+
+ if (!hbmp)
+ return 0;
+
+ OwnPtr<HDC> 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<HBITMAP> 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<HDC> 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<HBITMAP> 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<int>(rect.width(), oldWidth - rect.x());
+ int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
+ if (!copyWidth || !copyHeight)
+ return 0;
+
+ bmpInfo = BitmapInfo::createBottomUp(IntSize(copyWidth, copyHeight), (useAlpha && is32bit()) ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16);
+ OwnPtr<HBITMAP> newBmp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));
+
+ if (!newBmp)
+ return 0;
+
+ OwnPtr<HDC> 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> SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha)
+{
+ int oldWidth = width();
+ int oldHeight = height();
+ int copyWidth = std::min<int>(rect.width(), oldWidth - rect.x());
+ int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
+ if (!copyWidth || !copyHeight)
+ return 0;
+
+ RefPtr<SharedBitmap> 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> 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<int>(bmpSize.cy - sourceY, destRect.bottom - dstY);
+ int dstX = destRect.left;
+ for (int sourceX = phase.x; dstX < destRect.right; ) {
+ int sourceW = std::min<int>(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<LONG>(static_cast<unsigned>(phase) % static_cast<unsigned>(limit));
+ if (phase)
+ phase = limit - phase;
+ return phase;
+ }
+
+ if (phase < limit)
+ return phase;
+
+ return static_cast<LONG>(static_cast<unsigned>(phase) % static_cast<unsigned>(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<double>(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<HBITMAP> 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<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
+ if (GetClipRgn(hdc, clipRgn.get()) > 0) {
+ DWORD regionDataSize = GetRegionData(clipRgn.get(), sizeof(RGNDATA), 0);
+ if (regionDataSize) {
+ Vector<RGNDATA> regionData(regionDataSize);
+ GetRegionData(clipRgn.get(), regionDataSize, regionData.data());
+ RECT* rect = reinterpret_cast<RECT*>(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<HBITMAP> hbmpTemp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));
+
+ if (!hbmpTemp)
+ return;
+
+ OwnPtr<HDC> 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<HBITMAP> 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<unsigned>(SelectObject(hdc, bmp->getHandle()));
+ RECT rect = { 0, 0, bmp->width(), bmp->height() };
+ OwnPtr<HRGN> 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<HGDIOBJ>(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<unsigned short*>(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<wchar_t*>(dst), 0, wordsToSet);
+ dst += w;
+ }
+ return;
+ }
+
+ unsigned w = width();
+ unsigned* dst = static_cast<unsigned*>(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<wchar_t*>(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 <paroga@paroga.com>
+ *
+ * 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 <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wingdi.h>
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class GraphicsContext;
+class IntRect;
+class IntSize;
+class TransformationMatrix;
+
+class SharedBitmap: public RefCounted<SharedBitmap> {
+public:
+ ~SharedBitmap();
+ static PassRefPtr<SharedBitmap> create(const IntSize&, BitmapInfo::BitCount = BitmapInfo::BitCount32, bool initPixels = true);
+ static PassRefPtr<SharedBitmap> create(const Vector<unsigned>&, 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<HBITMAP> 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<HBITMAP> clipBitmap(const IntRect& rect, bool useAlpha, BitmapInfo& bmpInfo, void*& pixels);
+
+ PassRefPtr<SharedBitmap> 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<HBITMAP> m_hbitmap;
+ void* m_pixels;
+ OwnArrayPtr<unsigned> 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 <wtf/MathExtras.h>
+#include <mlang.h>
+#include <tchar.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+void SimpleFontData::platformInit()
+{
+ if (!m_platformData.isValid())
+ return;
+
+ const TEXTMETRIC& tm = m_platformData.metrics();
+ m_isSystemFont = m_platformData.isSystemFont();
+
+ m_ascent = (tm.tmAscent * m_platformData.size() + 36) / 72;
+ m_descent = (tm.tmDescent * m_platformData.size() + 36) / 72;
+ m_lineGap = (tm.tmExternalLeading * m_platformData.size() + 36) / 72;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_xHeight = m_ascent * 0.56f;
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+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<int>(d + 0.5);
+
+ int i = static_cast<int>(d);
+ return i - d > 0.5 ? i - 1 : i;
+ }
+}
+
+#endif WinCEGraphicsExtras_h