summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp4
-rw-r--r--WebCore/platform/graphics/BitmapImage.h7
-rw-r--r--WebCore/platform/graphics/Color.h1
-rw-r--r--WebCore/platform/graphics/FloatPoint.h8
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.h10
-rw-r--r--WebCore/platform/graphics/FloatRect.h5
-rw-r--r--WebCore/platform/graphics/Font.cpp22
-rw-r--r--WebCore/platform/graphics/Font.h13
-rw-r--r--WebCore/platform/graphics/FontCache.cpp22
-rw-r--r--WebCore/platform/graphics/FontData.h7
-rw-r--r--WebCore/platform/graphics/FontFallbackList.cpp9
-rw-r--r--WebCore/platform/graphics/FontFallbackList.h14
-rw-r--r--WebCore/platform/graphics/FontFastPath.cpp37
-rw-r--r--WebCore/platform/graphics/GeneratedImage.cpp2
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h13
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.cpp38
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.h11
-rw-r--r--WebCore/platform/graphics/GlyphWidthMap.h2
-rw-r--r--WebCore/platform/graphics/Gradient.cpp13
-rw-r--r--WebCore/platform/graphics/Gradient.h20
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp24
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h35
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.cpp348
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h300
-rw-r--r--WebCore/platform/graphics/GraphicsLayerClient.h9
-rw-r--r--WebCore/platform/graphics/Image.cpp2
-rw-r--r--WebCore/platform/graphics/Image.h16
-rw-r--r--WebCore/platform/graphics/ImageBuffer.cpp73
-rw-r--r--WebCore/platform/graphics/ImageBuffer.h22
-rw-r--r--WebCore/platform/graphics/ImageSource.h13
-rw-r--r--WebCore/platform/graphics/IntPoint.h30
-rw-r--r--WebCore/platform/graphics/IntRect.h8
-rw-r--r--WebCore/platform/graphics/IntSize.h7
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp60
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h46
-rw-r--r--WebCore/platform/graphics/MediaPlayerPrivate.h21
-rw-r--r--WebCore/platform/graphics/Path.h8
-rw-r--r--WebCore/platform/graphics/Pattern.h3
-rw-r--r--WebCore/platform/graphics/SegmentedFontData.cpp8
-rw-r--r--WebCore/platform/graphics/SegmentedFontData.h4
-rw-r--r--WebCore/platform/graphics/SimpleFontData.cpp12
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h4
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp9
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h2
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp54
-rw-r--r--WebCore/platform/graphics/cairo/ImageCairo.cpp6
-rw-r--r--WebCore/platform/graphics/cairo/ImageSourceCairo.cpp20
-rw-r--r--WebCore/platform/graphics/cairo/PathCairo.cpp5
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h2
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferCG.cpp26
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp34
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp26
-rw-r--r--WebCore/platform/graphics/cg/PDFDocumentImage.cpp4
-rw-r--r--WebCore/platform/graphics/cg/PathCG.cpp7
-rw-r--r--WebCore/platform/graphics/cg/PatternCG.cpp8
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromiumMac.mm132
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp2
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheLinux.cpp46
-rw-r--r--WebCore/platform/graphics/chromium/FontChromiumWin.cpp43
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp63
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.h10
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp496
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp9
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h5
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp51
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.h38
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp5
-rw-r--r--WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp248
-rw-r--r--WebCore/platform/graphics/chromium/HarfbuzzSkia.h (renamed from WebCore/platform/graphics/skia/ImageSourceSkia.h)46
-rw-r--r--WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp6
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.cpp36
-rw-r--r--WebCore/platform/graphics/chromium/TransparencyWin.h11
-rw-r--r--WebCore/platform/graphics/filters/FEBlend.h3
-rw-r--r--WebCore/platform/graphics/filters/FEColorMatrix.cpp126
-rw-r--r--WebCore/platform/graphics/filters/FEColorMatrix.h3
-rw-r--r--WebCore/platform/graphics/filters/FEComponentTransfer.h3
-rw-r--r--WebCore/platform/graphics/filters/FEComposite.h3
-rw-r--r--WebCore/platform/graphics/filters/Filter.h14
-rw-r--r--WebCore/platform/graphics/filters/FilterEffect.cpp37
-rw-r--r--WebCore/platform/graphics/filters/FilterEffect.h35
-rw-r--r--WebCore/platform/graphics/filters/SourceAlpha.h2
-rw-r--r--WebCore/platform/graphics/filters/SourceGraphic.cpp18
-rw-r--r--WebCore/platform/graphics/filters/SourceGraphic.h4
-rw-r--r--WebCore/platform/graphics/gtk/FontGtk.cpp6
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformData.h6
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp7
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp17
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp49
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h180
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp2
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp36
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.h58
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.h3
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm60
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformData.h6
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformDataMac.mm9
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h177
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm1906
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h35
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm353
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.h7
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.mm36
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.mm9
-rw-r--r--WebCore/platform/graphics/qt/FontCacheQt.cpp230
-rw-r--r--WebCore/platform/graphics/qt/FontFallbackListQt.cpp44
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformData.h34
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformDataQt.cpp18
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp18
-rw-r--r--WebCore/platform/graphics/qt/FontQt43.cpp16
-rw-r--r--WebCore/platform/graphics/qt/GradientQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp30
-rw-r--r--WebCore/platform/graphics/qt/IconQt.cpp5
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp29
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp24
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.h4
-rw-r--r--WebCore/platform/graphics/qt/ImageQt.cpp11
-rw-r--r--WebCore/platform/graphics/qt/ImageSourceQt.cpp17
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp19
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp19
-rw-r--r--WebCore/platform/graphics/qt/TransformationMatrixQt.cpp2
-rw-r--r--WebCore/platform/graphics/skia/GradientSkia.cpp16
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h2
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextSkia.cpp109
-rw-r--r--WebCore/platform/graphics/skia/ImageBufferSkia.cpp22
-rw-r--r--WebCore/platform/graphics/skia/ImageSkia.cpp6
-rw-r--r--WebCore/platform/graphics/skia/ImageSourceSkia.cpp33
-rw-r--r--WebCore/platform/graphics/skia/PathSkia.cpp21
-rw-r--r--WebCore/platform/graphics/skia/PatternSkia.cpp8
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp120
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h8
-rw-r--r--WebCore/platform/graphics/skia/SkiaFontWin.cpp24
-rw-r--r--WebCore/platform/graphics/skia/SkiaUtils.cpp52
-rw-r--r--WebCore/platform/graphics/skia/SkiaUtils.h8
-rw-r--r--WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp2
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp2
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperations.h3
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.cpp11
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.h9
-rw-r--r--WebCore/platform/graphics/win/ColorSafari.cpp70
-rw-r--r--WebCore/platform/graphics/win/FontPlatformData.h8
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp4
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp50
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataWin.cpp5
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp126
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp98
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp120
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp14
-rw-r--r--WebCore/platform/graphics/win/ImageCGWin.cpp4
-rw-r--r--WebCore/platform/graphics/win/ImageCairoWin.cpp4
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp47
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h2
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp101
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.h7
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp5
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp11
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataWin.cpp7
-rw-r--r--WebCore/platform/graphics/win/TransformationMatrixWin.cpp (renamed from WebCore/platform/graphics/chromium/ColorChromium.cpp)24
-rw-r--r--WebCore/platform/graphics/wince/FontCacheWince.cpp352
-rw-r--r--WebCore/platform/graphics/wince/FontCustomPlatformData.cpp79
-rw-r--r--WebCore/platform/graphics/wince/FontCustomPlatformData.h55
-rw-r--r--WebCore/platform/graphics/wince/FontPlatformData.cpp532
-rw-r--r--WebCore/platform/graphics/wince/FontPlatformData.h90
-rw-r--r--WebCore/platform/graphics/wince/FontWince.cpp333
-rw-r--r--WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp79
-rw-r--r--WebCore/platform/graphics/wince/GraphicsContextWince.cpp1930
-rw-r--r--WebCore/platform/graphics/wince/SimpleFontDataWince.cpp161
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformData.h6
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformDataWx.cpp9
-rw-r--r--WebCore/platform/graphics/wx/ImageBufferWx.cpp2
-rw-r--r--WebCore/platform/graphics/wx/ImageSourceWx.cpp60
-rw-r--r--WebCore/platform/graphics/wx/PathWx.cpp5
171 files changed, 8653 insertions, 2696 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 2f9412d..0b94efb 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -86,7 +86,7 @@ void BitmapImage::destroyDecodedData(bool destroyAll)
destroyMetadataAndNotify(framesCleared);
- m_source.clear(destroyAll, clearBeforeFrame, m_data.get(), m_allDataReceived);
+ m_source.clear(destroyAll, clearBeforeFrame, data(), m_allDataReceived);
return;
}
@@ -163,7 +163,7 @@ bool BitmapImage::dataChanged(bool allDataReceived)
// Feed all the data we've seen so far to the image decoder.
m_allDataReceived = allDataReceived;
- m_source.setData(m_data.get(), allDataReceived);
+ m_source.setData(data(), allDataReceived);
// Clear the frame count.
m_haveFrameCount = false;
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
index a2de5d7..807c11b 100644
--- a/WebCore/platform/graphics/BitmapImage.h
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
* Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008-2009 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -164,7 +165,7 @@ protected:
virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator);
#endif
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
-#if PLATFORM(WX)
+#if PLATFORM(WX) || PLATFORM(WINCE)
virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
#endif
@@ -224,7 +225,11 @@ protected:
{
if (!m_checkedForSolidColor && frameCount() > 0) {
checkForSolidColor();
+ // WINCE PORT: checkForSolidColor() doesn't set m_checkedForSolidColor until
+ // it gets enough information to make final decision.
+#if !PLATFORM(WINCE)
ASSERT(m_checkedForSolidColor);
+#endif
}
return m_isSolidColor && m_currentFrame == 0;
}
diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h
index 3b815d2..5baa56e 100644
--- a/WebCore/platform/graphics/Color.h
+++ b/WebCore/platform/graphics/Color.h
@@ -149,7 +149,6 @@ inline bool operator!=(const Color& a, const Color& b)
return !(a == b);
}
-Color focusRingColor();
Color colorFromPremultipliedARGB(unsigned);
unsigned premultipliedARGBFromColor(const Color&);
diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h
index a3fbeea..a9850c9 100644
--- a/WebCore/platform/graphics/FloatPoint.h
+++ b/WebCore/platform/graphics/FloatPoint.h
@@ -51,11 +51,15 @@ class QPointF;
QT_END_NAMESPACE
#endif
+#ifdef MANUAL_MERGE_REQUIRED
#if PLATFORM(SYMBIAN)
class TPoint;
#endif
#if (PLATFORM(SKIA) || PLATFORM(SGL))
+#else // MANUAL_MERGE_REQUIRED
+#if PLATFORM(SKIA)
+#endif // MANUAL_MERGE_REQUIRED
struct SkPoint;
#endif
@@ -94,12 +98,16 @@ public:
operator QPointF() const;
#endif
+#ifdef MANUAL_MERGE_REQUIRED
#if PLATFORM(SYMBIAN)
operator TPoint() const;
FloatPoint(const TPoint&);
#endif
#if (PLATFORM(SKIA) || PLATFORM(SGL))
+#else // MANUAL_MERGE_REQUIRED
+#if PLATFORM(SKIA)
+#endif // MANUAL_MERGE_REQUIRED
operator SkPoint() const;
FloatPoint(const SkPoint&);
#endif
diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h
index 2e71ddd..73c3a37 100644
--- a/WebCore/platform/graphics/FloatPoint3D.h
+++ b/WebCore/platform/graphics/FloatPoint3D.h
@@ -49,6 +49,16 @@ private:
float m_z;
};
+inline bool operator==(const FloatPoint3D& a, const FloatPoint3D& b)
+{
+ return a.x() == b.x() && a.y() == b.y() && a.z() == b.z();
+}
+
+inline bool operator!=(const FloatPoint3D& a, const FloatPoint3D& b)
+{
+ return a.x() != b.x() || a.y() != b.y() || a.z() != b.z();
+}
+
} // namespace WebCore
#endif // FloatPoint3D_h
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
index 786fb3e..e906812 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -132,11 +132,6 @@ public:
FloatRect(const QRectF&);
operator QRectF() const;
#endif
-#if PLATFORM(SYMBIAN)
- FloatRect(const TRect&);
- operator TRect() const;
- TRect rect() const;
-#endif
#if PLATFORM(WX) && USE(WXGC)
FloatRect(const wxRect2DDouble&);
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp
index 85fe882..88774cb 100644
--- a/WebCore/platform/graphics/Font.cpp
+++ b/WebCore/platform/graphics/Font.cpp
@@ -59,9 +59,7 @@ Font::CodePath Font::s_codePath = Auto;
// ============================================================================================
Font::Font()
- : m_pageZero(0)
- , m_cachedPrimaryFont(0)
- , m_letterSpacing(0)
+ : m_letterSpacing(0)
, m_wordSpacing(0)
, m_isPlatformFont(false)
{
@@ -69,8 +67,6 @@ Font::Font()
Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
: m_fontDescription(fd)
- , m_pageZero(0)
- , m_cachedPrimaryFont(0)
, m_letterSpacing(letterSpacing)
, m_wordSpacing(wordSpacing)
, m_isPlatformFont(false)
@@ -79,8 +75,6 @@ Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
Font::Font(const FontPlatformData& fontData, bool isPrinterFont)
: m_fontList(FontFallbackList::create())
- , m_pageZero(0)
- , m_cachedPrimaryFont(0)
, m_letterSpacing(0)
, m_wordSpacing(0)
, m_isPlatformFont(true)
@@ -92,9 +86,6 @@ Font::Font(const FontPlatformData& fontData, bool isPrinterFont)
Font::Font(const Font& other)
: m_fontDescription(other.m_fontDescription)
, m_fontList(other.m_fontList)
- , m_pages(other.m_pages)
- , m_pageZero(other.m_pageZero)
- , m_cachedPrimaryFont(other.m_cachedPrimaryFont)
, m_letterSpacing(other.m_letterSpacing)
, m_wordSpacing(other.m_wordSpacing)
, m_isPlatformFont(other.m_isPlatformFont)
@@ -105,9 +96,6 @@ Font& Font::operator=(const Font& other)
{
m_fontDescription = other.m_fontDescription;
m_fontList = other.m_fontList;
- m_pages = other.m_pages;
- m_pageZero = other.m_pageZero;
- m_cachedPrimaryFont = other.m_cachedPrimaryFont;
m_letterSpacing = other.m_letterSpacing;
m_wordSpacing = other.m_wordSpacing;
m_isPlatformFont = other.m_isPlatformFont;
@@ -136,11 +124,10 @@ bool Font::operator==(const Font& other) const
&& (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
}
-void Font::cachePrimaryFont() const
+const SimpleFontData* Font::primaryFont() const
{
ASSERT(m_fontList);
- ASSERT(!m_cachedPrimaryFont);
- m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' ');
+ return m_fontList->primarySimpleFontData(this);
}
const FontData* Font::fontDataAt(unsigned index) const
@@ -165,9 +152,6 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const
if (!m_fontList)
m_fontList = FontFallbackList::create();
m_fontList->invalidate(fontSelector);
- m_cachedPrimaryFont = 0;
- m_pageZero = 0;
- m_pages.clear();
}
bool Font::isFixedPitch() const
diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h
index 8d85d8b..c067071 100644
--- a/WebCore/platform/graphics/Font.h
+++ b/WebCore/platform/graphics/Font.h
@@ -115,14 +115,7 @@ public:
int spaceWidth() const { return (int)ceilf(primaryFont()->adjustedSpaceWidth() + m_letterSpacing); }
int tabWidth() const { return 8 * spaceWidth(); }
- const SimpleFontData* primaryFont() const
- {
- ASSERT(isMainThread());
- if (!m_cachedPrimaryFont)
- cachePrimaryFont();
- return m_cachedPrimaryFont;
- }
-
+ const SimpleFontData* primaryFont() const;
const FontData* fontDataAt(unsigned) const;
GlyphData glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const;
// Used for complex text, and does not utilize the glyph map cache.
@@ -160,7 +153,6 @@ private:
float floatWidthForComplexText(const TextRun&, HashSet<const SimpleFontData*>* fallbackFonts = 0) const;
int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const;
FloatRect selectionRectForComplexText(const TextRun&, const IntPoint&, int h, int from, int to) const;
- void cachePrimaryFont() const;
friend struct WidthIterator;
@@ -191,9 +183,6 @@ public:
private:
FontDescription m_fontDescription;
mutable RefPtr<FontFallbackList> m_fontList;
- mutable HashMap<int, GlyphPageTreeNode*> m_pages;
- mutable GlyphPageTreeNode* m_pageZero;
- mutable const SimpleFontData* m_cachedPrimaryFont;
short m_letterSpacing;
short m_wordSpacing;
bool m_isPlatformFont;
diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp
index d9b4b28..06ea56b 100644
--- a/WebCore/platform/graphics/FontCache.cpp
+++ b/WebCore/platform/graphics/FontCache.cpp
@@ -328,18 +328,20 @@ void FontCache::purgeInactiveFontData(int count)
for (size_t i = 0; i < fontDataToDeleteCount; ++i)
delete fontDataToDelete[i];
- Vector<FontPlatformDataCacheKey> keysToRemove;
- keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size());
- FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
- for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
- if (platformData->second && !gFontDataCache->contains(*platformData->second))
- keysToRemove.append(platformData->first);
+ if (gFontPlatformDataCache) {
+ Vector<FontPlatformDataCacheKey> keysToRemove;
+ keysToRemove.reserveInitialCapacity(gFontPlatformDataCache->size());
+ FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
+ for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
+ if (platformData->second && !gFontDataCache->contains(*platformData->second))
+ keysToRemove.append(platformData->first);
+ }
+
+ size_t keysToRemoveCount = keysToRemove.size();
+ for (size_t i = 0; i < keysToRemoveCount; ++i)
+ delete gFontPlatformDataCache->take(keysToRemove[i]);
}
- size_t keysToRemoveCount = keysToRemove.size();
- for (size_t i = 0; i < keysToRemoveCount; ++i)
- delete gFontPlatformDataCache->take(keysToRemove[i]);
-
isPurging = false;
}
diff --git a/WebCore/platform/graphics/FontData.h b/WebCore/platform/graphics/FontData.h
index cb79919..76927f5 100644
--- a/WebCore/platform/graphics/FontData.h
+++ b/WebCore/platform/graphics/FontData.h
@@ -32,8 +32,9 @@
namespace WebCore {
class SimpleFontData;
+class String;
-class FontData : Noncopyable {
+class FontData : public Noncopyable {
public:
FontData()
: m_maxGlyphPageTreeLevel(0)
@@ -51,6 +52,10 @@ public:
void setMaxGlyphPageTreeLevel(unsigned level) const { m_maxGlyphPageTreeLevel = level; }
unsigned maxGlyphPageTreeLevel() const { return m_maxGlyphPageTreeLevel; }
+#ifndef NDEBUG
+ virtual String description() const = 0;
+#endif
+
private:
mutable unsigned m_maxGlyphPageTreeLevel;
};
diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp
index decacc5..649c117 100644
--- a/WebCore/platform/graphics/FontFallbackList.cpp
+++ b/WebCore/platform/graphics/FontFallbackList.cpp
@@ -36,7 +36,9 @@
namespace WebCore {
FontFallbackList::FontFallbackList()
- : m_fontSelector(0)
+ : m_pageZero(0)
+ , m_cachedPrimarySimpleFontData(0)
+ , m_fontSelector(0)
, m_familyIndex(0)
, m_pitch(UnknownPitch)
, m_loadingCustomFonts(false)
@@ -48,6 +50,9 @@ void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector)
{
releaseFontData();
m_fontList.clear();
+ m_pageZero = 0;
+ m_pages.clear();
+ m_cachedPrimarySimpleFontData = 0;
m_familyIndex = 0;
m_pitch = UnknownPitch;
m_loadingCustomFonts = false;
@@ -68,7 +73,7 @@ void FontFallbackList::releaseFontData()
void FontFallbackList::determinePitch(const Font* font) const
{
- const FontData* fontData = primaryFont(font);
+ const FontData* fontData = primaryFontData(font);
if (!fontData->isSegmented())
m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
else {
diff --git a/WebCore/platform/graphics/FontFallbackList.h b/WebCore/platform/graphics/FontFallbackList.h
index 07938ae..14ebbe4 100644
--- a/WebCore/platform/graphics/FontFallbackList.h
+++ b/WebCore/platform/graphics/FontFallbackList.h
@@ -31,6 +31,7 @@
namespace WebCore {
class Font;
+class GlyphPageTreeNode;
class GraphicsContext;
class IntRect;
class FontDescription;
@@ -57,7 +58,15 @@ public:
private:
FontFallbackList();
- const FontData* primaryFont(const Font* f) const { return fontDataAt(f, 0); }
+ const SimpleFontData* primarySimpleFontData(const Font* f)
+ {
+ ASSERT(isMainThread());
+ if (!m_cachedPrimarySimpleFontData)
+ m_cachedPrimarySimpleFontData = primaryFontData(f)->fontDataForCharacter(' ');
+ return m_cachedPrimarySimpleFontData;
+ }
+
+ const FontData* primaryFontData(const Font* f) const { return fontDataAt(f, 0); }
const FontData* fontDataAt(const Font*, unsigned index) const;
const FontData* fontDataForCharacters(const Font*, const UChar*, int length) const;
@@ -66,6 +75,9 @@ private:
void releaseFontData();
mutable Vector<pair<const FontData*, bool>, 1> m_fontList;
+ mutable HashMap<int, GlyphPageTreeNode*> m_pages;
+ mutable GlyphPageTreeNode* m_pageZero;
+ mutable const SimpleFontData* m_cachedPrimarySimpleFontData;
RefPtr<FontSelector> m_fontSelector;
mutable int m_familyIndex;
mutable Pitch m_pitch;
diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp
index deac1b6..b0e39db 100644
--- a/WebCore/platform/graphics/FontFastPath.cpp
+++ b/WebCore/platform/graphics/FontFastPath.cpp
@@ -1,6 +1,7 @@
/**
* Copyright (C) 2003, 2006 Apple Computer, Inc.
* Copyright (C) 2008 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Torch Mobile, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,6 +25,7 @@
#include "CharacterNames.h"
#include "FontCache.h"
+#include "FontFallbackList.h"
#include "FloatRect.h"
#include "GlyphBuffer.h"
#include "GlyphPageTreeNode.h"
@@ -57,13 +59,13 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap
unsigned pageNumber = (c / GlyphPage::size);
- GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero;
+ GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
if (!node) {
node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
if (pageNumber)
- m_pages.set(pageNumber, node);
+ m_fontList->m_pages.set(pageNumber, node);
else
- m_pageZero = node;
+ m_fontList->m_pageZero = node;
}
GlyphPage* page;
@@ -82,9 +84,9 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap
// Proceed with the fallback list.
node = node->getChild(fontDataAt(node->level()), pageNumber);
if (pageNumber)
- m_pages.set(pageNumber, node);
+ m_fontList->m_pages.set(pageNumber, node);
else
- m_pageZero = node;
+ m_fontList->m_pageZero = node;
}
} else {
while (true) {
@@ -118,9 +120,9 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap
// Proceed with the fallback list.
node = node->getChild(fontDataAt(node->level()), pageNumber);
if (pageNumber)
- m_pages.set(pageNumber, node);
+ m_fontList->m_pages.set(pageNumber, node);
else
- m_pageZero = node;
+ m_fontList->m_pageZero = node;
}
}
@@ -154,16 +156,33 @@ GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCap
GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
// Cache it so we don't have to do system fallback again next time.
- if (!useSmallCapsFont)
+ if (!useSmallCapsFont) {
+#if PLATFORM(WINCE)
+ // missingGlyphData returns a null character, which is not suitable for GDI to display.
+ // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
+ // display the character, probably because the font package is not installed correctly.
+ // So we just always set the glyph to be same as the character, and let GDI solve it.
+ page->setGlyphDataForCharacter(c, c, characterFontData);
+ return page->glyphDataForCharacter(c);
+#else
page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+#endif
+ }
return data;
}
// Even system fallback can fail; use the missing glyph in that case.
// FIXME: It would be nicer to use the missing glyph from the last resort font instead.
GlyphData data = primaryFont()->missingGlyphData();
- if (!useSmallCapsFont)
+ if (!useSmallCapsFont) {
+#if PLATFORM(WINCE)
+ // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
+ page->setGlyphDataForCharacter(c, c, data.fontData);
+ return page->glyphDataForCharacter(c);
+#else
page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+#endif
+ }
return data;
}
diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp
index c40a40a..bac9da0 100644
--- a/WebCore/platform/graphics/GeneratedImage.cpp
+++ b/WebCore/platform/graphics/GeneratedImage.cpp
@@ -51,7 +51,7 @@ void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcR
const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect)
{
// Create a BitmapImage and call drawPattern on it.
- OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size, false);
+ OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size);
ASSERT(imageBuffer.get());
// Fill with the gradient.
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
index dcda419..04491a7 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Torch Mobile Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -49,6 +50,8 @@ class SimpleFontData;
#if PLATFORM(CAIRO)
// FIXME: Why does Cairo use such a huge struct instead of just an offset into an array?
typedef cairo_glyph_t GlyphBufferGlyph;
+#elif PLATFORM(WINCE)
+typedef wchar_t GlyphBufferGlyph;
#else
typedef Glyph GlyphBufferGlyph;
#endif
@@ -57,6 +60,10 @@ typedef Glyph GlyphBufferGlyph;
// can be passed directly to CGContextShowGlyphsWithAdvances in FontMac.mm
#if PLATFORM(CG)
typedef CGSize GlyphBufferAdvance;
+#elif PLATFORM(WINCE)
+// There is no cross-platform code that uses the height of GlyphBufferAdvance,
+// so we can save memory space on embedded devices by storing only the width
+typedef float GlyphBufferAdvance;
#else
typedef FloatSize GlyphBufferAdvance;
#endif
@@ -117,6 +124,8 @@ public:
{
#if PLATFORM(CG)
return m_advances[index].width;
+#elif PLATFORM(WINCE)
+ return m_advances[index];
#else
return m_advances[index].width();
#endif
@@ -147,6 +156,8 @@ public:
#if PLATFORM(CG)
CGSize advance = { width, 0 };
m_advances.append(advance);
+#elif PLATFORM(WINCE)
+ m_advances.append(width);
#else
m_advances.append(FloatSize(width, 0));
#endif
@@ -161,6 +172,7 @@ public:
#endif
}
+#if !PLATFORM(WINCE)
void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance)
{
m_fontData.append(font);
@@ -174,6 +186,7 @@ public:
m_advances.append(advance);
}
+#endif
private:
Vector<const SimpleFontData*, 2048> m_fontData;
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
index a34a192..6419e0c 100644
--- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
@@ -29,6 +29,7 @@
#include "config.h"
#include "GlyphPageTreeNode.h"
+#include "CString.h"
#include "CharacterNames.h"
#include "SegmentedFontData.h"
#include "SimpleFontData.h"
@@ -377,4 +378,41 @@ void GlyphPageTreeNode::pruneFontData(const SimpleFontData* fontData, unsigned l
it->second->pruneFontData(fontData, level);
}
+#ifndef NDEBUG
+ void GlyphPageTreeNode::showSubtree()
+ {
+ Vector<char> indent(level());
+ indent.fill('\t', level());
+ indent.append(0);
+
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::iterator it = m_children.begin(); it != end; ++it) {
+ printf("%s\t%p %s\n", indent.data(), it->first, it->first->description().utf8().data());
+ it->second->showSubtree();
+ }
+ if (m_systemFallbackChild) {
+ printf("%s\t* fallback\n", indent.data());
+ m_systemFallbackChild->showSubtree();
+ }
+ }
+#endif
+
}
+
+#ifndef NDEBUG
+void showGlyphPageTrees()
+{
+ printf("Page 0:\n");
+ showGlyphPageTree(0);
+ HashMap<int, WebCore::GlyphPageTreeNode*>::iterator end = WebCore::GlyphPageTreeNode::roots->end();
+ for (HashMap<int, WebCore::GlyphPageTreeNode*>::iterator it = WebCore::GlyphPageTreeNode::roots->begin(); it != end; ++it) {
+ printf("\nPage %d:\n", it->first);
+ showGlyphPageTree(it->first);
+ }
+}
+
+void showGlyphPageTree(unsigned pageNumber)
+{
+ WebCore::GlyphPageTreeNode::getRoot(pageNumber)->showSubtree();
+}
+#endif
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.h b/WebCore/platform/graphics/GlyphPageTreeNode.h
index 80e87aa..7918ac5 100644
--- a/WebCore/platform/graphics/GlyphPageTreeNode.h
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.h
@@ -35,6 +35,11 @@
#include <wtf/RefCounted.h>
#include <wtf/unicode/Unicode.h>
+#ifndef NDEBUG
+void showGlyphPageTrees();
+void showGlyphPageTree(unsigned pageNumber);
+#endif
+
namespace WebCore {
class FontData;
@@ -210,6 +215,10 @@ private:
static GlyphPageTreeNode* getRoot(unsigned pageNumber);
void initializePage(const FontData*, unsigned pageNumber);
+#ifndef NDEBUG
+ void showSubtree();
+#endif
+
GlyphPageTreeNode* m_parent;
RefPtr<GlyphPage> m_page;
unsigned m_level;
@@ -220,6 +229,8 @@ private:
#ifndef NDEBUG
unsigned m_pageNumber;
+
+ friend void ::showGlyphPageTree(unsigned pageNumber);
#endif
};
diff --git a/WebCore/platform/graphics/GlyphWidthMap.h b/WebCore/platform/graphics/GlyphWidthMap.h
index e194ecf..66dea1f 100644
--- a/WebCore/platform/graphics/GlyphWidthMap.h
+++ b/WebCore/platform/graphics/GlyphWidthMap.h
@@ -39,7 +39,7 @@ typedef unsigned short Glyph;
const float cGlyphWidthUnknown = -1;
-class GlyphWidthMap : Noncopyable {
+class GlyphWidthMap : public Noncopyable {
public:
GlyphWidthMap() : m_filledPrimaryPage(false) { }
~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); } }
diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp
index 51c7162..77a0d21 100644
--- a/WebCore/platform/graphics/Gradient.cpp
+++ b/WebCore/platform/graphics/Gradient.cpp
@@ -155,4 +155,17 @@ void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
m_spreadMethod = spreadMethod;
}
+void Gradient::setGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation)
+{
+ m_gradientSpaceTransformation = gradientSpaceTransformation;
+ setPlatformGradientSpaceTransform(gradientSpaceTransformation);
+}
+
+#if !PLATFORM(SKIA)
+void Gradient::setPlatformGradientSpaceTransform(const TransformationMatrix&)
+{
+}
+#endif
+
+
} //namespace
diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h
index 764deee..074c99d 100644
--- a/WebCore/platform/graphics/Gradient.h
+++ b/WebCore/platform/graphics/Gradient.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -76,12 +77,28 @@ namespace WebCore {
void getColor(float value, float* r, float* g, float* b, float* a) const;
+#ifdef MANUAL_MERGE_REQUIRED
#if PLATFORM(SGL)
SkShader* getShader(SkShader::TileMode);
#else
+#else // MANUAL_MERGE_REQUIRED
+#if PLATFORM(WINCE) && !PLATFORM(QT)
+ const FloatPoint& p0() const { return m_p0; }
+ const FloatPoint& p1() const { return m_p1; }
+ float r0() const { return m_r0; }
+ float r1() const { return m_r1; }
+ bool isRadial() const { return m_radial; }
+ struct ColorStop;
+ const Vector<ColorStop>& getStops() const;
+#else
+#endif // MANUAL_MERGE_REQUIRED
PlatformGradient platformGradient();
+#ifdef MANUAL_MERGE_REQUIRED
#endif
+#else // MANUAL_MERGE_REQUIRED
+#endif
+#endif // MANUAL_MERGE_REQUIRED
struct ColorStop {
float stop;
float red;
@@ -97,11 +114,12 @@ namespace WebCore {
void setSpreadMethod(GradientSpreadMethod);
GradientSpreadMethod spreadMethod() { return m_spreadMethod; }
- void setGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation) { m_gradientSpaceTransformation = gradientSpaceTransformation; }
+ void setGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation);
// Qt and CG transform the gradient at draw time
TransformationMatrix gradientSpaceTransform() { return m_gradientSpaceTransformation; }
virtual void fill(GraphicsContext*, const FloatRect&);
+ void setPlatformGradientSpaceTransform(const TransformationMatrix& gradientSpaceTransformation);
private:
Gradient(const FloatPoint& p0, const FloatPoint& p1);
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
index 4dae3d2..a4e8408 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -214,6 +214,7 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
}
m_common->state.strokeColorSpace = PatternColorSpace;
m_common->state.strokePattern = pattern;
+ setPlatformStrokePattern(m_common->state.strokePattern.get());
}
void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
@@ -225,6 +226,7 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
}
m_common->state.fillColorSpace = PatternColorSpace;
m_common->state.fillPattern = pattern;
+ setPlatformFillPattern(m_common->state.fillPattern.get());
}
void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
@@ -236,6 +238,7 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
}
m_common->state.strokeColorSpace = GradientColorSpace;
m_common->state.strokeGradient = gradient;
+ setPlatformStrokeGradient(m_common->state.strokeGradient.get());
}
void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
@@ -247,6 +250,7 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
}
m_common->state.fillColorSpace = GradientColorSpace;
m_common->state.fillGradient = gradient;
+ setPlatformFillGradient(m_common->state.fillGradient.get());
}
Gradient* GraphicsContext::fillGradient() const
@@ -320,6 +324,7 @@ void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect
drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale);
}
+#if !PLATFORM(WINCE) || PLATFORM(QT)
void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to)
{
if (paintingDisabled())
@@ -327,6 +332,7 @@ void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPo
font.drawText(this, run, point, from, to);
}
+#endif
void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point)
{
@@ -508,6 +514,24 @@ void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
generator.fill(this, rect);
}
+#if !PLATFORM(SKIA)
+void GraphicsContext::setPlatformFillGradient(Gradient*)
+{
+}
+
+void GraphicsContext::setPlatformFillPattern(Pattern*)
+{
+}
+
+void GraphicsContext::setPlatformStrokeGradient(Gradient*)
+{
+}
+
+void GraphicsContext::setPlatformStrokePattern(Pattern*)
+{
+}
+#endif
+
#if !PLATFORM(CG) && !PLATFORM(SKIA)
// Implement this if you want to go ahead and push the drawing mode into your native context
// immediately.
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index 3fdafad..b52344d 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2009 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -71,6 +72,8 @@ class wxWindowDC;
#endif
#elif PLATFORM(SKIA)
typedef class PlatformContextSkia PlatformGraphicsContext;
+#elif PLATFORM(WINCE)
+typedef struct HDC__ PlatformGraphicsContext;
#else
typedef void PlatformGraphicsContext;
#endif
@@ -94,6 +97,12 @@ typedef unsigned char UInt8;
namespace WebCore {
+#if PLATFORM(WINCE) && !PLATFORM(QT)
+ class SharedBitmap;
+ class SimpleFontData;
+ class GlyphBuffer;
+#endif
+
const int cMisspellingLineThickness = 3;
const int cMisspellingLinePatternWidth = 4;
const int cMisspellingLinePatternGapWidth = 1;
@@ -143,12 +152,14 @@ namespace WebCore {
InterpolationHigh
};
- class GraphicsContext : Noncopyable {
+ class GraphicsContext : public Noncopyable {
public:
GraphicsContext(PlatformGraphicsContext*);
~GraphicsContext();
+#if !PLATFORM(WINCE) || PLATFORM(QT)
PlatformGraphicsContext* platformContext() const;
+#endif
float strokeThickness() const;
void setStrokeThickness(float);
@@ -329,7 +340,23 @@ namespace WebCore {
void concatCTM(const TransformationMatrix&);
TransformationMatrix getCTM() const;
-#if PLATFORM(WIN)
+#if PLATFORM(WINCE) && !PLATFORM(QT)
+ void setBitmap(PassRefPtr<SharedBitmap>);
+ const TransformationMatrix& affineTransform() const;
+ TransformationMatrix& affineTransform();
+ void resetAffineTransform();
+ void fillRect(const FloatRect&, const Gradient*);
+ void drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point);
+ void drawFrameControl(const IntRect& rect, unsigned type, unsigned state);
+ void drawFocusRect(const IntRect& rect);
+ void paintTextField(const IntRect& rect, unsigned state);
+ void drawBitmap(SharedBitmap*, const IntRect& dstRect, const IntRect& srcRect, CompositeOperator compositeOp);
+ void drawBitmapPattern(SharedBitmap*, const FloatRect& tileRectIn, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize);
+ void drawIcon(HICON icon, const IntRect& dstRect, UINT flags);
+ HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = false, bool mayCreateBitmap = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
+ void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = false, bool mayCreateBitmap = true); // The passed in HDC should be the one handed back by getWindowsContext.
+ void drawRoundCorner(bool newClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height);
+#elif PLATFORM(WIN)
GraphicsContext(HDC, bool hasAlpha = false); // FIXME: To be removed.
bool inTransparencyLayer() const;
HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
@@ -399,8 +426,12 @@ namespace WebCore {
void setPlatformStrokeColor(const Color&);
void setPlatformStrokeStyle(const StrokeStyle&);
void setPlatformStrokeThickness(float);
+ void setPlatformStrokeGradient(Gradient*);
+ void setPlatformStrokePattern(Pattern*);
void setPlatformFillColor(const Color&);
+ void setPlatformFillGradient(Gradient*);
+ void setPlatformFillPattern(Pattern*);
void setPlatformShouldAntialias(bool b);
diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp
index 0c442a2..7d43832 100644
--- a/WebCore/platform/graphics/GraphicsLayer.cpp
+++ b/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -35,147 +35,24 @@
namespace WebCore {
-void GraphicsLayer::FloatValue::set(float key, float value, const TimingFunction* timingFunction)
-{
- m_key = key;
- m_value = value;
- if (timingFunction != m_timingFunction) {
- if (timingFunction)
- m_timingFunction.set(new TimingFunction(*timingFunction));
- else
- m_timingFunction.clear();
- }
-}
-
-void GraphicsLayer::TransformValue::set(float key, const TransformOperations* value, const TimingFunction* timingFunction)
-{
- m_key = key;
- if (value != m_value) {
- if (value)
- m_value.set(new TransformOperations(*value));
- else
- m_value.clear();
- }
- if (timingFunction != m_timingFunction) {
- if (timingFunction)
- m_timingFunction.set(new TimingFunction(*timingFunction));
- else
- m_timingFunction.clear();
- }
-}
-
-void GraphicsLayer::FloatValueList::insert(float key, float value, const TimingFunction* timingFunction)
-{
- for (size_t i = 0; i < m_values.size(); ++i) {
- FloatValue& curFloatValue = m_values[i];
- if (curFloatValue.key() == key) {
- curFloatValue.set(key, value, timingFunction);
- return;
- }
- if (curFloatValue.key() > key) {
- // insert before
- m_values.insert(i, FloatValue(key, value, timingFunction));
- return;
- }
- }
-
- // append
- m_values.append(FloatValue(key, value, timingFunction));
-}
-
-void GraphicsLayer::TransformValueList::insert(float key, const TransformOperations* value, const TimingFunction* timingFunction)
+void KeyframeValueList::insert(const AnimationValue* value)
{
for (size_t i = 0; i < m_values.size(); ++i) {
- TransformValue& curTransValue = m_values[i];
- if (curTransValue.key() == key) {
- curTransValue.set(key, value, timingFunction);
+ const AnimationValue* curValue = m_values[i];
+ if (curValue->keyTime() == value->keyTime()) {
+ ASSERT_NOT_REACHED();
+ // insert after
+ m_values.insert(i + 1, value);
return;
}
- if (curTransValue.key() > key) {
+ if (curValue->keyTime() > value->keyTime()) {
// insert before
- m_values.insert(i, TransformValue(key, value, timingFunction));
+ m_values.insert(i, value);
return;
}
}
- // append
- m_values.append(TransformValue(key, value, timingFunction));
-}
-
-// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
-// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
-// true if the rotation between any two keyframes is >= 180 degrees.
-void GraphicsLayer::TransformValueList::makeFunctionList(FunctionList& list, bool& isValid, bool& hasBigRotation) const
-{
- list.clear();
- isValid = false;
- hasBigRotation = false;
-
- if (m_values.size() < 2)
- return;
-
- // empty transforms match anything, so find the first non-empty entry as the reference
- size_t firstIndex = 0;
- for ( ; firstIndex < m_values.size(); ++firstIndex) {
- if (m_values[firstIndex].value()->operations().size() > 0)
- break;
- }
-
- if (firstIndex >= m_values.size())
- return;
-
- const TransformOperations* firstVal = m_values[firstIndex].value();
-
- // see if the keyframes are valid
- for (size_t i = firstIndex + 1; i < m_values.size(); ++i) {
- const TransformOperations* val = m_values[i].value();
-
- // a null transform matches anything
- if (val->operations().isEmpty())
- continue;
-
- if (firstVal->operations().size() != val->operations().size())
- return;
-
- for (size_t j = 0; j < firstVal->operations().size(); ++j) {
- if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j)))
- return;
- }
- }
-
- // keyframes are valid, fill in the list
- isValid = true;
-
- double lastRotAngle = 0.0;
- double maxRotAngle = -1.0;
-
- list.resize(firstVal->operations().size());
- for (size_t j = 0; j < firstVal->operations().size(); ++j) {
- TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType();
- list[j] = type;
-
- // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
- if (type == TransformOperation::ROTATE_X ||
- type == TransformOperation::ROTATE_Y ||
- type == TransformOperation::ROTATE_Z ||
- type == TransformOperation::ROTATE_3D) {
- lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle();
-
- if (maxRotAngle < 0)
- maxRotAngle = fabs(lastRotAngle);
-
- for (size_t i = firstIndex + 1; i < m_values.size(); ++i) {
- const TransformOperations* val = m_values[i].value();
- double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle());
- double diffAngle = fabs(rotAngle - lastRotAngle);
- if (diffAngle > maxRotAngle)
- maxRotAngle = diffAngle;
- lastRotAngle = rotAngle;
- }
- }
- }
-
- hasBigRotation = maxRotAngle >= 180.0;
+ m_values.append(value);
}
GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
@@ -193,6 +70,8 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
, m_masksToBounds(false)
, m_drawsContent(false)
, m_paintingPhase(GraphicsLayerPaintAllMask)
+ , m_geometryOrientation(CompositingCoordinatesTopDown)
+ , m_contentsOrientation(CompositingCoordinatesTopDown)
, m_parent(0)
#ifndef NDEBUG
, m_repaintCount(0)
@@ -202,8 +81,6 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
GraphicsLayer::~GraphicsLayer()
{
- removeAllAnimations();
-
removeAllChildren();
removeFromParent();
}
@@ -315,9 +192,9 @@ void GraphicsLayer::removeFromParent()
}
}
-void GraphicsLayer::setBackgroundColor(const Color& inColor, const Animation*, double /*beginTime*/)
+void GraphicsLayer::setBackgroundColor(const Color& color)
{
- m_backgroundColor = inColor;
+ m_backgroundColor = color;
m_backgroundColorSet = true;
}
@@ -327,96 +204,13 @@ void GraphicsLayer::clearBackgroundColor()
m_backgroundColorSet = false;
}
-bool GraphicsLayer::setOpacity(float opacity, const Animation*, double)
-{
- m_opacity = opacity;
- return false; // not animating
-}
-
void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const IntRect& clip)
{
- m_client->paintContents(this, context, m_paintingPhase, clip);
-}
-
-String GraphicsLayer::propertyIdToString(AnimatedPropertyID property)
-{
- switch (property) {
- case AnimatedPropertyWebkitTransform:
- return "transform";
- case AnimatedPropertyOpacity:
- return "opacity";
- case AnimatedPropertyBackgroundColor:
- return "backgroundColor";
- case AnimatedPropertyInvalid:
- ASSERT_NOT_REACHED();
- }
- ASSERT_NOT_REACHED();
- return "";
-}
-
-int GraphicsLayer::findAnimationEntry(AnimatedPropertyID property, short index) const
-{
- for (size_t i = 0; i < m_animations.size(); ++i) {
- if (m_animations[i].matches(property, index))
- return static_cast<int>(i);
- }
- return -1;
-}
-
-void GraphicsLayer::addAnimationEntry(AnimatedPropertyID property, short index, bool isTransition, const Animation* transition)
-{
- int i = findAnimationEntry(property, index);
-
- if (i >= 0)
- m_animations[i].reset(transition, isTransition);
- else
- m_animations.append(AnimationEntry(transition, property, index, isTransition));
-}
-
-void GraphicsLayer::removeAllAnimations()
-{
- size_t size = m_animations.size();
- for (size_t i = 0; i < size; ++i)
- removeAnimation(0, true);
-}
-
-void GraphicsLayer::removeAllAnimationsForProperty(AnimatedPropertyID property)
-{
- for (short j = 0; ; ++j) {
- int i = findAnimationEntry(property, j);
- if (i < 0)
- break;
- removeAnimation(i, false);
- }
-}
-
-void GraphicsLayer::removeFinishedAnimations(const String& name, int /*index*/, bool reset)
-{
- size_t size = m_animations.size();
- for (size_t i = 0; i < size; ) {
- AnimationEntry& anim = m_animations[i];
- if (!anim.isTransition() && anim.animation()->name() == name) {
- removeAnimation(i, reset);
- --size;
- } else
- ++i;
- }
-}
-
-void GraphicsLayer::removeFinishedTransitions(AnimatedPropertyID property)
-{
- size_t size = m_animations.size();
- for (size_t i = 0; i < size; ) {
- AnimationEntry& anim = m_animations[i];
- if (anim.isTransition() && property == anim.property()) {
- removeAnimation(i, false);
- --size;
- } else
- ++i;
- }
+ if (m_client)
+ m_client->paintContents(this, context, m_paintingPhase, clip);
}
-void GraphicsLayer::suspendAnimations()
+void GraphicsLayer::suspendAnimations(double)
{
}
@@ -448,6 +242,116 @@ void GraphicsLayer::setZPosition(float position)
}
#endif
+float GraphicsLayer::accumulatedOpacity() const
+{
+ if (!preserves3D())
+ return 1;
+
+ return m_opacity * (parent() ? parent()->accumulatedOpacity() : 1);
+}
+
+void GraphicsLayer::distributeOpacity(float accumulatedOpacity)
+{
+ // If this is a transform layer we need to distribute our opacity to all our children
+
+ // Incoming accumulatedOpacity is the contribution from our parent(s). We mutiply this by our own
+ // opacity to get the total contribution
+ accumulatedOpacity *= m_opacity;
+
+ setOpacityInternal(accumulatedOpacity);
+
+ if (preserves3D()) {
+ size_t numChildren = children().size();
+ for (size_t i = 0; i < numChildren; ++i)
+ children()[i]->distributeOpacity(accumulatedOpacity);
+ }
+}
+
+// An "invalid" list is one whose functions don't match, and therefore has to be animated as a Matrix
+// The hasBigRotation flag will always return false if isValid is false. Otherwise hasBigRotation is
+// true if the rotation between any two keyframes is >= 180 degrees.
+
+static inline const TransformOperations* operationsAt(const KeyframeValueList& valueList, size_t index)
+{
+ return static_cast<const TransformAnimationValue*>(valueList.at(index))->value();
+}
+
+void GraphicsLayer::fetchTransformOperationList(const KeyframeValueList& valueList, TransformOperationList& list, bool& isValid, bool& hasBigRotation)
+{
+ ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
+
+ list.clear();
+ isValid = false;
+ hasBigRotation = false;
+
+ if (valueList.size() < 2)
+ return;
+
+ // Empty transforms match anything, so find the first non-empty entry as the reference.
+ size_t firstIndex = 0;
+ for ( ; firstIndex < valueList.size(); ++firstIndex) {
+ if (operationsAt(valueList, firstIndex)->operations().size() > 0)
+ break;
+ }
+
+ if (firstIndex >= valueList.size())
+ return;
+
+ const TransformOperations* firstVal = operationsAt(valueList, firstIndex);
+
+ // See if the keyframes are valid.
+ for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
+ const TransformOperations* val = operationsAt(valueList, i);
+
+ // a null transform matches anything
+ if (val->operations().isEmpty())
+ continue;
+
+ if (firstVal->operations().size() != val->operations().size())
+ return;
+
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ if (!firstVal->operations().at(j)->isSameType(*val->operations().at(j)))
+ return;
+ }
+ }
+
+ // Keyframes are valid, fill in the list.
+ isValid = true;
+
+ double lastRotAngle = 0.0;
+ double maxRotAngle = -1.0;
+
+ list.resize(firstVal->operations().size());
+ for (size_t j = 0; j < firstVal->operations().size(); ++j) {
+ TransformOperation::OperationType type = firstVal->operations().at(j)->getOperationType();
+ list[j] = type;
+
+ // if this is a rotation entry, we need to see if any angle differences are >= 180 deg
+ if (type == TransformOperation::ROTATE_X ||
+ type == TransformOperation::ROTATE_Y ||
+ type == TransformOperation::ROTATE_Z ||
+ type == TransformOperation::ROTATE_3D) {
+ lastRotAngle = static_cast<RotateTransformOperation*>(firstVal->operations().at(j).get())->angle();
+
+ if (maxRotAngle < 0)
+ maxRotAngle = fabs(lastRotAngle);
+
+ for (size_t i = firstIndex + 1; i < valueList.size(); ++i) {
+ const TransformOperations* val = operationsAt(valueList, i);
+ double rotAngle = val->operations().isEmpty() ? 0 : (static_cast<RotateTransformOperation*>(val->operations().at(j).get())->angle());
+ double diffAngle = fabs(rotAngle - lastRotAngle);
+ if (diffAngle > maxRotAngle)
+ maxRotAngle = diffAngle;
+ lastRotAngle = rotAngle;
+ }
+ }
+ }
+
+ hasBigRotation = maxRotAngle >= 180.0;
+}
+
+
static void writeIndent(TextStream& ts, int indent)
{
for (int i = 0; i != indent; ++i)
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
index ae51951..4d7668a 100644
--- a/WebCore/platform/graphics/GraphicsLayer.h
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -34,6 +34,7 @@
#include "FloatPoint3D.h"
#include "FloatSize.h"
#include "GraphicsLayerClient.h"
+#include "IntRect.h"
#include "TransformationMatrix.h"
#include "TransformOperations.h"
#include <wtf/OwnPtr.h>
@@ -42,7 +43,7 @@
#ifdef __OBJC__
@class WebLayer;
@class CALayer;
-typedef WebLayer PlatformLayer;
+typedef CALayer PlatformLayer;
typedef CALayer* NativeLayer;
#else
typedef void* PlatformLayer;
@@ -61,117 +62,95 @@ class Image;
class TextStream;
class TimingFunction;
-// GraphicsLayer is an abstraction for a rendering surface with backing store,
-// which may have associated transformation and animations.
+// Base class for animation values (also used for transitions). Here to
+// represent values for properties being animated via the GraphicsLayer,
+// without pulling in style-related data from outside of the platform directory.
+class AnimationValue : public Noncopyable {
+public:
+ AnimationValue(float keyTime, const TimingFunction* timingFunction = 0)
+ : m_keyTime(keyTime)
+ , m_timingFunction(0)
+ {
+ if (timingFunction)
+ m_timingFunction.set(new TimingFunction(*timingFunction));
+ }
+
+ virtual ~AnimationValue() { }
-class GraphicsLayer {
+ float keyTime() const { return m_keyTime; }
+ const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
+
+private:
+ float m_keyTime;
+ OwnPtr<TimingFunction> m_timingFunction;
+};
+
+// Used to store one float value of an animation.
+class FloatAnimationValue : public AnimationValue {
+public:
+ FloatAnimationValue(float keyTime, float value, const TimingFunction* timingFunction = 0)
+ : AnimationValue(keyTime, timingFunction)
+ , m_value(value)
+ {
+ }
+
+ float value() const { return m_value; }
+
+private:
+ float m_value;
+};
+
+// Used to store one transform value in a keyframe list.
+class TransformAnimationValue : public AnimationValue {
public:
- // Used to store one float value of a keyframe animation.
- class FloatValue {
- public:
- FloatValue(float key, float value, const TimingFunction* timingFunction = 0)
- : m_key(key), m_value(value), m_timingFunction(0)
- {
- if (timingFunction)
- m_timingFunction.set(new TimingFunction(*timingFunction));
- }
-
- FloatValue(const FloatValue& other)
- : m_key(other.key()), m_value(other.value()), m_timingFunction(0)
- {
- if (other.timingFunction())
- m_timingFunction.set(new TimingFunction(*other.timingFunction()));
- }
-
- const FloatValue& operator=(const FloatValue& other)
- {
- if (&other != this)
- set(other.key(), other.value(), other.timingFunction());
- return *this;
- }
-
- void set(float key, float value, const TimingFunction*);
-
- float key() const { return m_key; }
- float value() const { return m_value; }
- const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
-
- private:
- float m_key;
- float m_value;
- OwnPtr<TimingFunction> m_timingFunction;
- };
+ TransformAnimationValue(float keyTime, const TransformOperations* value = 0, const TimingFunction* timingFunction = 0)
+ : AnimationValue(keyTime, timingFunction)
+ {
+ if (value)
+ m_value.set(new TransformOperations(*value));
+ }
+
+ const TransformOperations* value() const { return m_value.get(); }
+
+private:
+ OwnPtr<TransformOperations> m_value;
+};
+
+// Used to store a series of values in a keyframe list. Values will all be of the same type,
+// which can be inferred from the property.
+class KeyframeValueList : public Noncopyable {
+public:
+
+ KeyframeValueList(AnimatedPropertyID property)
+ : m_property(property)
+ {
+ }
+ ~KeyframeValueList()
+ {
+ deleteAllValues(m_values);
+ }
- class FloatValueList {
- public:
- void insert(float key, float value, const TimingFunction* timingFunction);
-
- size_t size() const { return m_values.size(); }
- const FloatValue& at(size_t i) const { return m_values.at(i); }
- const Vector<FloatValue>& values() const { return m_values; }
-
- private:
- Vector<FloatValue> m_values;
- };
-
- // Used to store one transform in a keyframe list.
- class TransformValue {
- public:
- TransformValue(float key = NAN, const TransformOperations* value = 0, const TimingFunction* timingFunction = 0)
- : m_key(key)
- {
- if (value)
- m_value.set(new TransformOperations(*value));
- if (timingFunction)
- m_timingFunction.set(new TimingFunction(*timingFunction));
- }
-
- TransformValue(const TransformValue& other)
- : m_key(other.key())
- {
- if (other.value())
- m_value.set(new TransformOperations(*other.value()));
- if (other.timingFunction())
- m_timingFunction.set(new TimingFunction(*other.timingFunction()));
- }
-
- const TransformValue& operator=(const TransformValue& other)
- {
- if (&other != this)
- set(other.key(), other.value(), other.timingFunction());
- return *this;
- }
-
- void set(float key, const TransformOperations* value, const TimingFunction* timingFunction);
-
- float key() const { return m_key; }
- const TransformOperations* value() const { return m_value.get(); }
- const TimingFunction* timingFunction() const { return m_timingFunction.get(); }
-
- private:
- float m_key;
- OwnPtr<TransformOperations> m_value;
- OwnPtr<TimingFunction> m_timingFunction;
- };
+ AnimatedPropertyID property() const { return m_property; }
+
+ size_t size() const { return m_values.size(); }
+ const AnimationValue* at(size_t i) const { return m_values.at(i); }
+
+ // Insert, sorted by keyTime. Takes ownership of the pointer.
+ void insert(const AnimationValue*);
- // Used to store a series of transforms in a keyframe list.
- class TransformValueList {
- public:
- typedef Vector<TransformOperation::OperationType> FunctionList;
-
- size_t size() const { return m_values.size(); }
- const TransformValue& at(size_t i) const { return m_values.at(i); }
- const Vector<TransformValue>& values() const { return m_values; }
-
- void insert(float key, const TransformOperations* value, const TimingFunction* timingFunction);
-
- // return a list of the required functions. List is empty if keyframes are not valid
- // If return value is true, functions contain rotations of >= 180 degrees
- void makeFunctionList(FunctionList& list, bool& isValid, bool& hasBigRotation) const;
- private:
- Vector<TransformValue> m_values;
- };
+protected:
+ Vector<const AnimationValue*> m_values;
+ AnimatedPropertyID m_property;
+};
+
+
+
+// GraphicsLayer is an abstraction for a rendering surface with backing store,
+// which may have associated transformation and animations.
+
+class GraphicsLayer {
+public:
static GraphicsLayer* createGraphicsLayer(GraphicsLayerClient*);
@@ -235,7 +214,7 @@ public:
// The color used to paint the layer backgrounds
const Color& backgroundColor() const { return m_backgroundColor; }
- virtual void setBackgroundColor(const Color&, const Animation* = 0, double beginTime = 0);
+ virtual void setBackgroundColor(const Color&);
virtual void clearBackgroundColor();
bool backgroundColorSet() const { return m_backgroundColorSet; }
@@ -247,8 +226,7 @@ public:
virtual void setBackfaceVisibility(bool b) { m_backfaceVisibility = b; }
float opacity() const { return m_opacity; }
- // return true if we started an animation
- virtual bool setOpacity(float o, const Animation* = 0, double beginTime = 0);
+ virtual void setOpacity(float opacity) { m_opacity = opacity; }
// Some GraphicsLayers paint only the foreground or the background content
GraphicsLayerPaintingPhase drawingPhase() const { return m_paintingPhase; }
@@ -258,24 +236,25 @@ public:
// mark the given rect (in layer coords) as needing dispay. Never goes deep.
virtual void setNeedsDisplayInRect(const FloatRect&) = 0;
- virtual bool animateTransform(const TransformValueList&, const IntSize&, const Animation*, double beginTime, bool isTransition) = 0;
- virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&, const Animation*, double beginTime) = 0;
+ // Set that the position/size of the contents (image or video).
+ IntRect contentsRect() const { return m_contentsRect; }
+ virtual void setContentsRect(const IntRect& r) { m_contentsRect = r; }
- void removeFinishedAnimations(const String& name, int index, bool reset);
- void removeFinishedTransitions(AnimatedPropertyID);
- void removeAllAnimations();
-
- virtual void suspendAnimations();
+ // Return true if the animation is handled by the compositing system. If this returns
+ // false, the animation will be run by AnimationController.
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*keyframesName*/, double /*beginTime*/) { return false; }
+ virtual void removeAnimationsForProperty(AnimatedPropertyID) { }
+ virtual void removeAnimationsForKeyframes(const String& /* keyframesName */) { }
+ virtual void pauseAnimation(const String& /* keyframesName */) { }
+
+ virtual void suspendAnimations(double time);
virtual void resumeAnimations();
// Layer contents
virtual void setContentsToImage(Image*) { }
virtual void setContentsToVideo(PlatformLayer*) { }
virtual void setContentsBackgroundColor(const Color&) { }
- virtual void clearContents() { }
- virtual void updateContentsRect() { }
-
// Callback from the underlying graphics system to draw layer contents.
void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip);
@@ -293,6 +272,14 @@ public:
enum CompositingCoordinatesOrientation { CompositingCoordinatesTopDown, CompositingCoordinatesBottomUp };
static CompositingCoordinatesOrientation compositingCoordinatesOrientation();
+ // Set the geometry orientation (top-down, or bottom-up) for this layer, which also controls sublayer geometry.
+ virtual void setGeometryOrientation(CompositingCoordinatesOrientation orientation) { m_geometryOrientation = orientation; }
+ CompositingCoordinatesOrientation geometryOrientation() const { return m_geometryOrientation; }
+
+ // Flippedness of the contents of this layer. Does not affect sublayer geometry.
+ virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; }
+ CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; }
+
#ifndef NDEBUG
static bool showDebugBorders();
static bool showRepaintCounter();
@@ -306,19 +293,25 @@ public:
virtual void setZPosition(float);
#endif
- static String propertyIdToString(AnimatedPropertyID);
-
+ virtual void distributeOpacity(float);
+ virtual float accumulatedOpacity() const;
+
+ // Some compositing systems may do internal batching to synchronize compositing updates
+ // with updates drawn into the window. This is a signal to flush any internal batched state.
+ virtual void syncCompositingState() { }
+
protected:
- GraphicsLayer(GraphicsLayerClient*);
- void dumpProperties(TextStream&, int indent) const;
+ typedef Vector<TransformOperation::OperationType> TransformOperationList;
+ // Given a list of TransformAnimationValues, return an array of transform operations.
+ // On return, if hasBigRotation is true, functions contain rotations of >= 180 degrees
+ static void fetchTransformOperationList(const KeyframeValueList&, TransformOperationList&, bool& isValid, bool& hasBigRotation);
- // returns -1 if not found
- int findAnimationEntry(AnimatedPropertyID, short index) const;
- void addAnimationEntry(AnimatedPropertyID, short index, bool isTransition, const Animation*);
+ virtual void setOpacityInternal(float) { }
+
+ GraphicsLayer(GraphicsLayerClient*);
- virtual void removeAnimation(int /*index*/, bool /*reset*/) {}
- void removeAllAnimationsForProperty(AnimatedPropertyID);
+ void dumpProperties(TextStream&, int indent) const;
GraphicsLayerClient* m_client;
String m_name;
@@ -348,53 +341,14 @@ protected:
bool m_drawsContent : 1;
GraphicsLayerPaintingPhase m_paintingPhase;
+ CompositingCoordinatesOrientation m_geometryOrientation; // affects geometry of layer positions
+ CompositingCoordinatesOrientation m_contentsOrientation; // affects orientation of layer contents
Vector<GraphicsLayer*> m_children;
GraphicsLayer* m_parent;
-
- // AnimationEntry represents an animation of a property on this layer.
- // For transform only, there may be more than one, in which case 'index'
- // is an index into the list of transforms.
- class AnimationEntry {
- public:
- AnimationEntry(const Animation* animation, AnimatedPropertyID property, short index, bool isTransition)
- : m_animation(const_cast<Animation*>(animation))
- , m_property(property)
- , m_index(index)
- , m_isCurrent(true)
- , m_isTransition(isTransition)
- {
- }
-
- const Animation* animation() const { return m_animation.get(); }
- AnimatedPropertyID property() const { return m_property; }
- int index() const { return m_index; }
- bool isCurrent() const { return m_isCurrent; }
- void setIsCurrent(bool b = true) { m_isCurrent = b; }
- bool isTransition() const { return m_isTransition; }
-
- bool matches(AnimatedPropertyID property, short index) const
- {
- return m_property == property && m_index == index;
- }
-
- void reset(const Animation* animation, bool isTransition)
- {
- m_animation = const_cast<Animation*>(animation);
- m_isTransition = isTransition;
- m_isCurrent = true;
- }
-
- private:
- RefPtr<Animation> m_animation;
- AnimatedPropertyID m_property : 14;
- short m_index : 16;
- bool m_isCurrent : 1;
- bool m_isTransition : 1;
- };
-
- Vector<AnimationEntry> m_animations; // running animations/transitions
-
+
+ IntRect m_contentsRect;
+
#ifndef NDEBUG
int m_repaintCount;
#endif
diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h
index 46382f2..8c0b7ed 100644
--- a/WebCore/platform/graphics/GraphicsLayerClient.h
+++ b/WebCore/platform/graphics/GraphicsLayerClient.h
@@ -53,13 +53,14 @@ class GraphicsLayerClient {
public:
virtual ~GraphicsLayerClient() {}
- // Callbacks for when hardware-accelerated transitions and animation started
+ // Callback for when hardware-accelerated animation started.
virtual void notifyAnimationStarted(const GraphicsLayer*, double time) = 0;
+
+ // Notification that a layer property changed that requires a subsequent call to syncCompositingState()
+ // to appear on the screen.
+ virtual void notifySyncRequired(const GraphicsLayer*) = 0;
virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0;
-
- // Return a rect for the "contents" of the graphics layer, i.e. video or image content, in GraphicsLayer coordinates.
- virtual IntRect contentsBox(const GraphicsLayer*) = 0;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp
index 08d96b4..80b5457 100644
--- a/WebCore/platform/graphics/Image.cpp
+++ b/WebCore/platform/graphics/Image.cpp
@@ -119,7 +119,6 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl
FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(),
scaledTileSize.height() / intrinsicTileSize.height());
- TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height());
FloatRect oneTileRect;
oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width()));
@@ -137,6 +136,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl
return;
}
+ TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height());
FloatRect tileRect(FloatPoint(), intrinsicTileSize);
drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect);
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
index cff8b22..294ddf6 100644
--- a/WebCore/platform/graphics/Image.h
+++ b/WebCore/platform/graphics/Image.h
@@ -31,9 +31,9 @@
#include "GraphicsTypes.h"
#include "ImageSource.h"
#include "IntRect.h"
-#include <wtf/RefPtr.h>
-#include <wtf/PassRefPtr.h>
#include "SharedBuffer.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
#if PLATFORM(MAC)
#ifdef __OBJC__
@@ -67,13 +67,13 @@ typedef struct _GdkPixbuf GdkPixbuf;
namespace WebCore {
-class TransformationMatrix;
class FloatPoint;
class FloatRect;
class FloatSize;
class GraphicsContext;
class SharedBuffer;
class String;
+class TransformationMatrix;
// This class gets notified when an image creates or destroys decoded frames and when it advances animation frames.
class ImageObserver;
@@ -81,6 +81,7 @@ class ImageObserver;
class Image : public RefCounted<Image> {
friend class GeneratedImage;
friend class GraphicsContext;
+
public:
virtual ~Image();
@@ -172,13 +173,8 @@ protected:
virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
-#if PLATFORM(CG)
- // These are private to CG. Ideally they would be only in the .cpp file, but the callback requires access
- // to the private function nativeImageForCurrentFrame()
- static void drawPatternCallback(void* info, CGContext*);
-#endif
-
-protected:
+
+private:
RefPtr<SharedBuffer> m_data; // The encoded raw data for the image.
ImageObserver* m_imageObserver;
};
diff --git a/WebCore/platform/graphics/ImageBuffer.cpp b/WebCore/platform/graphics/ImageBuffer.cpp
new file mode 100644
index 0000000..55305d1
--- /dev/null
+++ b/WebCore/platform/graphics/ImageBuffer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ *
+ * 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 "ImageBuffer.h"
+
+#if !PLATFORM(CG)
+
+#include <math.h>
+
+namespace WebCore {
+
+void ImageBuffer::transformColorSpace(ImageColorSpace srcColorSpace, ImageColorSpace dstColorSpace)
+{
+ if (srcColorSpace == dstColorSpace)
+ return;
+
+ // only sRGB <-> linearRGB are supported at the moment
+ if ((srcColorSpace != LinearRGB && srcColorSpace != DeviceRGB) ||
+ (dstColorSpace != LinearRGB && dstColorSpace != DeviceRGB))
+ return;
+
+ Vector<int> lookUpTable;
+ if (dstColorSpace == LinearRGB) {
+ if (m_linearRgbLUT.isEmpty()) {
+ for (unsigned i = 0; i < 256; i++) {
+ float color = i / 255.0f;
+ color = (color <= 0.04045f ? color / 12.92f : pow((color + 0.055f) / 1.055f, 2.4f));
+ color = std::max(0.0f, color);
+ color = std::min(1.0f, color);
+ m_linearRgbLUT.append(static_cast<int>(color * 255));
+ }
+ }
+ platformTransformColorSpace(m_linearRgbLUT);
+ } else if (dstColorSpace == DeviceRGB) {
+ if (m_deviceRgbLUT.isEmpty()) {
+ for (unsigned i = 0; i < 256; i++) {
+ float color = i / 255.0f;
+ color = pow(1.055f * color, 1.0f / 2.4f) - 0.055f;
+ color = std::max(0.0f, color);
+ color = std::min(1.0f, color);
+ m_deviceRgbLUT.append(static_cast<int>(color * 255));
+ }
+ }
+ platformTransformColorSpace(m_deviceRgbLUT);
+ }
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h
index 573e274..2a96d3b 100644
--- a/WebCore/platform/graphics/ImageBuffer.h
+++ b/WebCore/platform/graphics/ImageBuffer.h
@@ -43,13 +43,20 @@ namespace WebCore {
class IntRect;
class String;
- class ImageBuffer : Noncopyable {
+ enum ImageColorSpace {
+ Unknown,
+ DeviceRGB, // like sRGB
+ GrayScale,
+ LinearRGB
+ };
+
+ class ImageBuffer : public Noncopyable {
public:
// Will return a null pointer on allocation failure.
- static PassOwnPtr<ImageBuffer> create(const IntSize& size, bool grayScale)
+ static PassOwnPtr<ImageBuffer> create(const IntSize& size, ImageColorSpace colorSpace = DeviceRGB)
{
bool success = false;
- OwnPtr<ImageBuffer> buf(new ImageBuffer(size, grayScale, success));
+ OwnPtr<ImageBuffer> buf(new ImageBuffer(size, colorSpace, success));
if (success)
return buf.release();
return 0;
@@ -70,6 +77,8 @@ namespace WebCore {
String toDataURL(const String& mimeType) const;
#if !PLATFORM(CG)
TransformationMatrix baseTransform() const { return TransformationMatrix(); }
+ void transformColorSpace(ImageColorSpace srcColorSpace, ImageColorSpace dstColorSpace);
+ void platformTransformColorSpace(const Vector<int>&);
#else
TransformationMatrix baseTransform() const { return TransformationMatrix(1, 0, 0, -1, 0, m_size.height()); }
#endif
@@ -80,9 +89,14 @@ namespace WebCore {
OwnPtr<GraphicsContext> m_context;
mutable RefPtr<Image> m_image;
+#if !PLATFORM(CG)
+ Vector<int> m_linearRgbLUT;
+ Vector<int> m_deviceRgbLUT;
+#endif
+
// This constructor will place its success into the given out-variable
// so that create() knows when it should return failure.
- ImageBuffer(const IntSize&, bool grayScale, bool& success);
+ ImageBuffer(const IntSize&, ImageColorSpace colorSpace, bool& success);
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h
index d4a1658..c9ac03a 100644
--- a/WebCore/platform/graphics/ImageSource.h
+++ b/WebCore/platform/graphics/ImageSource.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -50,6 +51,8 @@ class SkBitmapRef;
class PrivateAndroidImageSourceRec;
#elif PLATFORM(SKIA)
class NativeImageSkia;
+#elif PLATFORM(WINCE)
+#include "SharedBitmap.h"
#endif
namespace WebCore {
@@ -96,12 +99,16 @@ typedef cairo_surface_t* NativeImagePtr;
class ImageDecoder;
typedef ImageDecoder* NativeImageSourcePtr;
typedef NativeImageSkia* NativeImagePtr;
+#elif PLATFORM(WINCE)
+class ImageDecoder;
+typedef ImageDecoder* NativeImageSourcePtr;
+typedef RefPtr<SharedBitmap> NativeImagePtr;
#endif
const int cAnimationLoopOnce = -1;
const int cAnimationNone = -2;
-class ImageSource : Noncopyable {
+class ImageSource : public Noncopyable {
public:
ImageSource();
~ImageSource();
@@ -153,6 +160,7 @@ public:
bool frameHasAlphaAtIndex(size_t); // Whether or not the frame actually used any alpha.
bool frameIsCompleteAtIndex(size_t); // Whether or not the frame is completely decoded.
+#ifdef MANUAL_MERGE_REQUIRED
#if PLATFORM(SGL)
void clearURL();
void setURL(const String& url);
@@ -161,6 +169,9 @@ private:
// FIXME: This is protected only to allow ImageSourceSkia to set ICO decoder
// with a preferred size. See ImageSourceSkia.h for discussion.
protected:
+#else // MANUAL_MERGE_REQUIRED
+private:
+#endif // MANUAL_MERGE_REQUIRED
NativeImageSourcePtr m_decoder;
};
diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h
index 1bfeeaa..e6d4816 100644
--- a/WebCore/platform/graphics/IntPoint.h
+++ b/WebCore/platform/graphics/IntPoint.h
@@ -29,10 +29,15 @@
#include "IntSize.h"
#include <wtf/Platform.h>
+#if PLATFORM(QT)
+#include <QDataStream>
+#endif
+
#if PLATFORM(CG)
typedef struct CGPoint CGPoint;
#endif
+
#if PLATFORM(MAC)
#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
typedef struct CGPoint NSPoint;
@@ -51,9 +56,6 @@ QT_END_NAMESPACE
#elif PLATFORM(GTK)
typedef struct _GdkPoint GdkPoint;
#endif
-#if PLATFORM(SYMBIAN)
-class TPoint;
-#endif
#if PLATFORM(WX)
class wxPoint;
@@ -78,6 +80,7 @@ public:
void setX(int x) { m_x = x; }
void setY(int y) { m_y = y; }
+ void move(const IntSize& s) { move(s.width(), s.height()); }
void move(int dx, int dy) { m_x += dx; m_y += dy; }
IntPoint expandedTo(const IntPoint& other) const
@@ -119,10 +122,6 @@ public:
IntPoint(const GdkPoint&);
operator GdkPoint() const;
#endif
-#if PLATFORM(SYMBIAN)
- IntPoint(const TPoint&);
- operator TPoint() const;
-#endif
#if PLATFORM(WX)
IntPoint(const wxPoint&);
@@ -176,6 +175,23 @@ inline bool operator!=(const IntPoint& a, const IntPoint& b)
return a.x() != b.x() || a.y() != b.y();
}
+#if PLATFORM(QT)
+inline QDataStream& operator<<(QDataStream& stream, const IntPoint& point)
+{
+ stream << point.x() << point.y();
+ return stream;
+}
+
+inline QDataStream& operator>>(QDataStream& stream, IntPoint& point)
+{
+ int x, y;
+ stream >> x >> y;
+ point.setX(x);
+ point.setY(y);
+ return stream;
+}
+#endif
+
} // namespace WebCore
#endif // IntPoint_h
diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h
index 1be98b8..0b607f5 100644
--- a/WebCore/platform/graphics/IntRect.h
+++ b/WebCore/platform/graphics/IntRect.h
@@ -50,9 +50,6 @@ QT_END_NAMESPACE
#elif PLATFORM(GTK)
typedef struct _GdkRectangle GdkRectangle;
#endif
-#if PLATFORM(SYMBIAN)
-class TRect;
-#endif
#if PLATFORM(WX)
class wxRect;
@@ -148,11 +145,6 @@ public:
IntRect(const GdkRectangle&);
operator GdkRectangle() const;
#endif
-#if PLATFORM(SYMBIAN)
- IntRect(const TRect&);
- operator TRect() const;
- TRect Rect() const;
-#endif
#if PLATFORM(CG)
operator CGRect() const;
diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h
index cac0bd1..dc7a85d 100644
--- a/WebCore/platform/graphics/IntSize.h
+++ b/WebCore/platform/graphics/IntSize.h
@@ -48,9 +48,6 @@ QT_BEGIN_NAMESPACE
class QSize;
QT_END_NAMESPACE
#endif
-#if PLATFORM(SYMBIAN)
-class TSize;
-#endif
namespace WebCore {
@@ -115,10 +112,6 @@ public:
IntSize(const QSize&);
operator QSize() const;
#endif
-#if PLATFORM(SYMBIAN)
- IntSize(const TSize&);
- operator TSize() const;
-#endif
private:
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index fb7225a..6205a7b 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -38,6 +38,8 @@
#if PLATFORM(MAC)
#include "MediaPlayerPrivateQTKit.h"
+#elif PLATFORM(WINCE)
+#include "MediaPlayerPrivateWince.h"
#elif PLATFORM(WIN)
#include "MediaPlayerPrivateQuickTimeWin.h"
#elif PLATFORM(GTK)
@@ -64,6 +66,8 @@ public:
virtual void play() { }
virtual void pause() { }
+ virtual bool supportsFullscreen() const { return false; }
+
virtual IntSize naturalSize() const { return IntSize(0, 0); }
virtual bool hasVideo() const { return false; }
@@ -79,6 +83,7 @@ public:
virtual void setEndTime(float) { }
virtual void setRate(float) { }
+ virtual void setPreservesPitch(bool) { }
virtual bool paused() const { return false; }
virtual void setVolume(float) { }
@@ -104,6 +109,8 @@ public:
virtual void deliverNotification(MediaPlayerProxyNotificationType) { }
virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) { }
#endif
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
};
static MediaPlayerPrivateInterface* createNullMediaPlayer(MediaPlayer* player)
@@ -185,6 +192,7 @@ MediaPlayer::MediaPlayer(MediaPlayerClient* client)
, m_visible(false)
, m_rate(1.0f)
, m_volume(1.0f)
+ , m_preservesPitch(true)
, m_autobuffer(false)
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
, m_playerProxy(0)
@@ -225,7 +233,7 @@ void MediaPlayer::load(const String& url, const ContentType& contentType)
engine = chooseBestEngineForTypeAndCodecs(type, codecs);
// if we didn't find an engine that claims the MIME type, just use the first engine
- if (!engine)
+ if (!engine && !installedMediaEngines().isEmpty())
engine = installedMediaEngines()[0];
// don't delete and recreate the player unless it comes from a different engine
@@ -297,6 +305,16 @@ bool MediaPlayer::seeking() const
return m_private->seeking();
}
+bool MediaPlayer::supportsFullscreen() const
+{
+ return m_private->supportsFullscreen();
+}
+
+bool MediaPlayer::supportsSave() const
+{
+ return m_private->supportsSave();
+}
+
IntSize MediaPlayer::naturalSize()
{
return m_private->naturalSize();
@@ -347,6 +365,17 @@ void MediaPlayer::setRate(float rate)
m_private->setRate(rate);
}
+bool MediaPlayer::preservesPitch() const
+{
+ return m_preservesPitch;
+}
+
+void MediaPlayer::setPreservesPitch(bool preservesPitch)
+{
+ m_preservesPitch = preservesPitch;
+ m_private->setPreservesPitch(preservesPitch);
+}
+
int MediaPlayer::dataRate() const
{
return m_private->dataRate();
@@ -417,6 +446,11 @@ void MediaPlayer::paint(GraphicsContext* p, const IntRect& r)
m_private->paint(p, r);
}
+void MediaPlayer::paintCurrentFrameInContext(GraphicsContext* p, const IntRect& r)
+{
+ m_private->paintCurrentFrameInContext(p, r);
+}
+
MediaPlayer::SupportsType MediaPlayer::supportsType(ContentType contentType)
{
String type = contentType.type();
@@ -458,6 +492,29 @@ void MediaPlayer::setMediaPlayerProxy(WebMediaPlayerProxy* proxy)
}
#endif
+#if USE(ACCELERATED_COMPOSITING)
+void MediaPlayer::acceleratedRenderingStateChanged()
+{
+ m_private->acceleratedRenderingStateChanged();
+}
+
+bool MediaPlayer::supportsAcceleratedRendering() const
+{
+ return m_private->supportsAcceleratedRendering();
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+bool MediaPlayer::hasSingleSecurityOrigin() const
+{
+ return m_private->hasSingleSecurityOrigin();
+}
+
+MediaPlayer::MovieLoadType MediaPlayer::movieLoadType() const
+{
+ return m_private->movieLoadType();
+}
+
+// Client callbacks.
void MediaPlayer::networkStateChanged()
{
if (m_mediaPlayerClient)
@@ -507,4 +564,5 @@ void MediaPlayer::rateChanged()
}
}
+
#endif
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 9b2f685..7f5f2a0 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -49,6 +49,10 @@ class MediaPlayer;
class MediaPlayerPrivateInterface;
class String;
+#if USE(ACCELERATED_COMPOSITING)
+class GraphicsLayer;
+#endif
+
class MediaPlayerClient {
public:
virtual ~MediaPlayerClient() { }
@@ -65,25 +69,34 @@ public:
// time has jumped, eg. not as a result of normal playback
virtual void mediaPlayerTimeChanged(MediaPlayer*) { }
- // a new frame of video is available
- virtual void mediaPlayerRepaint(MediaPlayer*) { }
-
// the media file duration has changed, or is now known
virtual void mediaPlayerDurationChanged(MediaPlayer*) { }
// the playback rate has changed
virtual void mediaPlayerRateChanged(MediaPlayer*) { }
- // the movie size has changed
- virtual void mediaPlayerSizeChanged(MediaPlayer*) { }
-
// The MediaPlayer has found potentially problematic media content.
// This is used internally to trigger swapping from a <video>
// element to an <embed> in standalone documents
virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*) { }
+
+// Presentation-related methods
+ // a new frame of video is available
+ virtual void mediaPlayerRepaint(MediaPlayer*) { }
+
+ // the movie size has changed
+ virtual void mediaPlayerSizeChanged(MediaPlayer*) { }
+
+#if USE(ACCELERATED_COMPOSITING)
+ // whether the rendering system can accelerate the display of this MediaPlayer.
+ virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; }
+
+ // return the GraphicsLayer that will host the presentation for this MediaPlayer.
+ virtual GraphicsLayer* mediaPlayerGraphicsLayer(MediaPlayer*) { return 0; }
+#endif
};
-class MediaPlayer : Noncopyable {
+class MediaPlayer : public Noncopyable {
public:
MediaPlayer(MediaPlayerClient*);
virtual ~MediaPlayer();
@@ -94,6 +107,8 @@ public:
static void getSupportedTypes(HashSet<String>&);
static bool isAvailable();
+ bool supportsFullscreen() const;
+ bool supportsSave() const;
IntSize naturalSize();
bool hasVideo();
@@ -126,6 +141,9 @@ public:
float rate() const;
void setRate(float);
+
+ bool preservesPitch() const;
+ void setPreservesPitch(bool);
float maxTimeBuffered();
float maxTimeSeekable();
@@ -143,6 +161,7 @@ public:
void setAutobuffer(bool);
void paint(GraphicsContext*, const IntRect&);
+ void paintCurrentFrameInContext(GraphicsContext*, const IntRect&);
enum NetworkState { Empty, Idle, Loading, Loaded, FormatError, NetworkError, DecodeError };
NetworkState networkState();
@@ -150,6 +169,9 @@ public:
enum ReadyState { HaveNothing, HaveMetadata, HaveCurrentData, HaveFutureData, HaveEnoughData };
ReadyState readyState();
+ enum MovieLoadType { Unknown, Download, StoredStream, LiveStream };
+ MovieLoadType movieLoadType() const;
+
void networkStateChanged();
void readyStateChanged();
void volumeChanged();
@@ -168,6 +190,15 @@ public:
void setMediaPlayerProxy(WebMediaPlayerProxy* proxy);
#endif
+#if USE(ACCELERATED_COMPOSITING)
+ // whether accelerated rendering is supported by the media engine for the current media.
+ bool supportsAcceleratedRendering() const;
+ // called when the rendering system flips the into or out of accelerated rendering mode.
+ void acceleratedRenderingStateChanged();
+#endif
+
+ bool hasSingleSecurityOrigin() const;
+
private:
static void initializeMediaEngines();
@@ -179,6 +210,7 @@ private:
bool m_visible;
float m_rate;
float m_volume;
+ bool m_preservesPitch;
bool m_autobuffer;
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
WebMediaPlayerProxy* m_playerProxy; // not owned or used, passed to m_private
diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h
index e17259c..6d1359b 100644
--- a/WebCore/platform/graphics/MediaPlayerPrivate.h
+++ b/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -46,6 +46,9 @@ public:
virtual void play() = 0;
virtual void pause() = 0;
+ virtual bool supportsFullscreen() const { return false; }
+ virtual bool supportsSave() const { return false; }
+
virtual IntSize naturalSize() const = 0;
virtual bool hasVideo() const = 0;
@@ -63,6 +66,8 @@ public:
virtual void setEndTime(float) = 0;
virtual void setRate(float) = 0;
+ virtual void setPreservesPitch(bool) { }
+
virtual bool paused() const = 0;
virtual void setVolume(float) = 0;
@@ -81,7 +86,9 @@ public:
virtual void setSize(const IntSize&) = 0;
- virtual void paint(GraphicsContext*, const IntRect&) = 0 ;
+ virtual void paint(GraphicsContext*, const IntRect&) = 0;
+
+ virtual void paintCurrentFrameInContext(GraphicsContext* c, const IntRect& r) { paint(c, r); }
virtual void setAutobuffer(bool) { };
@@ -90,6 +97,18 @@ public:
virtual void deliverNotification(MediaPlayerProxyNotificationType) = 0;
virtual void setMediaPlayerProxy(WebMediaPlayerProxy*) = 0;
#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+ // whether accelerated rendering is supported by the media engine for the current media.
+ virtual bool supportsAcceleratedRendering() const { return false; }
+ // called when the rendering system flips the into or out of accelerated rendering mode.
+ virtual void acceleratedRenderingStateChanged() { }
+#endif
+
+ virtual bool hasSingleSecurityOrigin() const { return false; }
+
+ virtual MediaPlayer::MovieLoadType movieLoadType() const { return MediaPlayer::Unknown; }
+
};
}
diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h
index 2b0a7d1..da324bc 100644
--- a/WebCore/platform/graphics/Path.h
+++ b/WebCore/platform/graphics/Path.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved.
* 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,6 +52,10 @@ typedef WebCore::CairoPath PlatformPath;
#elif PLATFORM(SKIA)
class SkPath;
typedef SkPath PlatformPath;
+#elif PLATFORM(WINCE)
+namespace WebCore {
+ class PlatformPath;
+}
#else
typedef void PlatformPath;
#endif
@@ -106,6 +111,9 @@ namespace WebCore {
void clear();
bool isEmpty() const;
+ // Gets the current point of the current path, which is conceptually the final point reached by the path so far.
+ // Note the Path can be empty (isEmpty() == true) and still have a current point.
+ bool hasCurrentPoint() const;
void moveTo(const FloatPoint&);
void addLineTo(const FloatPoint&);
diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h
index 6981748..02ad3ec 100644
--- a/WebCore/platform/graphics/Pattern.h
+++ b/WebCore/platform/graphics/Pattern.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -52,6 +53,8 @@ typedef wxGraphicsBrush* PlatformPatternPtr;
class wxBrush;
typedef wxBrush* PlatformPatternPtr;
#endif // USE(WXGC)
+#elif PLATFORM(WINCE)
+typedef void* PlatformPatternPtr;
#endif
namespace WebCore {
diff --git a/WebCore/platform/graphics/SegmentedFontData.cpp b/WebCore/platform/graphics/SegmentedFontData.cpp
index 1731d16..7e10040 100644
--- a/WebCore/platform/graphics/SegmentedFontData.cpp
+++ b/WebCore/platform/graphics/SegmentedFontData.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "SegmentedFontData.h"
+#include "PlatformString.h"
#include "SimpleFontData.h"
#include <wtf/Assertions.h>
@@ -87,4 +88,11 @@ bool SegmentedFontData::isSegmented() const
return true;
}
+#ifndef NDEBUG
+String SegmentedFontData::description() const
+{
+ return "[segmented font]";
+}
+#endif
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/SegmentedFontData.h b/WebCore/platform/graphics/SegmentedFontData.h
index 0a78321..645dc0d 100644
--- a/WebCore/platform/graphics/SegmentedFontData.h
+++ b/WebCore/platform/graphics/SegmentedFontData.h
@@ -59,6 +59,10 @@ public:
unsigned numRanges() const { return m_ranges.size(); }
const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; }
+#ifndef NDEBUG
+ virtual String description() const;
+#endif
+
private:
virtual const SimpleFontData* fontDataForCharacter(UChar32) const;
virtual bool containsCharacters(const UChar*, int length) const;
diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp
index bab7d99..c879228 100644
--- a/WebCore/platform/graphics/SimpleFontData.cpp
+++ b/WebCore/platform/graphics/SimpleFontData.cpp
@@ -190,4 +190,16 @@ bool SimpleFontData::isSegmented() const
return false;
}
+#ifndef NDEBUG
+String SimpleFontData::description() const
+{
+ if (isSVGFont())
+ return "[SVG font]";
+ if (isCustomFont())
+ return "[custom font]";
+
+ return platformData().description();
+}
+#endif
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
index aab6429..cb472b0 100644
--- a/WebCore/platform/graphics/SimpleFontData.h
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -105,6 +105,10 @@ public:
const GlyphData& missingGlyphData() const { return m_missingGlyphData; }
+#ifndef NDEBUG
+ virtual String description() const;
+#endif
+
#if PLATFORM(MAC)
NSFont* getNSFont() const { return m_platformData.font(); }
#endif
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index 23f30f3..5765546 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -62,15 +62,6 @@
namespace WebCore {
-static const unsigned aquaFocusRingColor = 0xFF7DADD9;
-
-Color focusRingColor()
-{
- static Color focusRingColor = aquaFocusRingColor;
-
- return focusRingColor;
-}
-
static inline void setColor(cairo_t* cr, const Color& col)
{
float red, green, blue, alpha;
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
index 531ebf4..54e1217 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -65,6 +65,7 @@ public:
// On Windows, we need to update the HDC for form controls to draw in the right place.
void save();
void restore();
+ void flush();
void clip(const FloatRect&);
void clip(const Path&);
void scale(const FloatSize&);
@@ -78,6 +79,7 @@ public:
// On everything else, we do nothing.
void save() {}
void restore() {}
+ void flush() {}
void clip(const FloatRect&) {}
void clip(const Path&) {}
void scale(const FloatSize&) {}
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index d2652d6..c905ee8 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -39,9 +39,29 @@
#include <cairo.h>
#include <wtf/Vector.h>
+#include <math.h>
using namespace std;
+// Cairo doesn't provide a way to copy a cairo_surface_t.
+// See http://lists.cairographics.org/archives/cairo/2007-June/010877.html
+// Once cairo provides the way, use the function instead of this.
+static inline cairo_surface_t* copySurface(cairo_surface_t* surface)
+{
+ cairo_format_t format = cairo_image_surface_get_format(surface);
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ cairo_surface_t* newsurface = cairo_image_surface_create(format, width, height);
+
+ cairo_t* cr = cairo_create(newsurface);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ return newsurface;
+}
+
namespace WebCore {
ImageBufferData::ImageBufferData(const IntSize& size)
@@ -49,7 +69,7 @@ ImageBufferData::ImageBufferData(const IntSize& size)
{
}
-ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
@@ -82,12 +102,42 @@ Image* ImageBuffer::image() const
// It's assumed that if image() is called, the actual rendering to the
// GraphicsContext must be done.
ASSERT(context());
+
+ // This creates a COPY of the image and will cache that copy. This means
+ // that if subsequent operations take place on the context, neither the
+ // currently-returned image, nor the results of future image() calls,
+ // will contain that operation.
+ //
+ // This seems silly, but is the way the CG port works: image() is
+ // intended to be used only when rendering is "complete."
+ cairo_surface_t* newsurface = copySurface(m_data.m_surface);
+
// BitmapImage will release the passed in surface on destruction
- m_image = BitmapImage::create(cairo_surface_reference(m_data.m_surface));
+ m_image = BitmapImage::create(newsurface);
}
return m_image.get();
}
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface);
+ int stride = cairo_image_surface_get_stride(m_data.m_surface);
+ for (int y = 0; y < m_size.height(); ++y) {
+ unsigned* row = reinterpret_cast<unsigned*>(dataSrc + stride * y);
+ for (int x = 0; x < m_size.width(); x++) {
+ unsigned* pixel = row + x;
+ Color pixelColor = colorFromPremultipliedARGB(*pixel);
+ pixelColor = Color(lookUpTable[pixelColor.red()],
+ lookUpTable[pixelColor.green()],
+ lookUpTable[pixelColor.blue()],
+ lookUpTable[pixelColor.alpha()]);
+ *pixel = premultipliedARGBFromColor(pixelColor);
+ }
+ }
+}
+
PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
{
ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp
index 7c34e6f..c8c992e 100644
--- a/WebCore/platform/graphics/cairo/ImageCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -157,11 +157,15 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con
if (!image) // If it's too early we won't have an image yet.
return;
+ // Avoid NaN
+ if (!isfinite(phase.x()) || !isfinite(phase.y()))
+ return;
+
cairo_t* cr = context->platformContext();
context->save();
IntRect imageSize = enclosingIntRect(tileRect);
- OwnPtr<ImageBuffer> imageSurface = ImageBuffer::create(imageSize.size(), false);
+ OwnPtr<ImageBuffer> imageSurface = ImageBuffer::create(imageSize.size());
if (!imageSurface)
return;
diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
index b51caf6..df62618 100644
--- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
@@ -34,13 +34,10 @@
#include "ICOImageDecoder.h"
#include "JPEGImageDecoder.h"
#include "PNGImageDecoder.h"
+#include "XBMImageDecoder.h"
#include "SharedBuffer.h"
#include <cairo.h>
-#if !PLATFORM(WIN)
-#include "XBMImageDecoder.h"
-#endif
-
namespace WebCore {
ImageDecoder* createDecoder(const Vector<char>& data)
@@ -80,11 +77,9 @@ ImageDecoder* createDecoder(const Vector<char>& data)
!memcmp(contents, "\000\000\002\000", 4))
return new ICOImageDecoder();
-#if !PLATFORM(WIN)
// XBMs require 8 bytes of info.
if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
return new XBMImageDecoder();
-#endif
// Give up. We don't know what the heck this is.
return 0;
@@ -158,9 +153,12 @@ IntSize ImageSource::size() const
return m_decoder->size();
}
-IntSize ImageSource::frameSizeAtIndex(size_t) const
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
{
- return size();
+ if (!m_decoder)
+ return IntSize();
+
+ return m_decoder->frameSizeAtIndex(index);
}
int ImageSource::repetitionCount()
@@ -193,11 +191,7 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
if (!size().height())
return 0;
- return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(),
- CAIRO_FORMAT_ARGB32,
- size().width(),
- size().height(),
- size().width()*4);
+ return buffer->asNewNativeImage();
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp
index 13ca1e2..75681bd 100644
--- a/WebCore/platform/graphics/cairo/PathCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -89,6 +89,11 @@ bool Path::isEmpty() const
#endif
}
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
void Path::translate(const FloatSize& p)
{
cairo_t* cr = platformPath()->m_cr;
diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
index beee660..f63a8dd 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
+++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
@@ -50,6 +50,7 @@ public:
// These methods do nothing on Mac.
void save() {}
void restore() {}
+ void flush() {}
void clip(const FloatRect&) {}
void clip(const Path&) {}
void scale(const FloatSize&) {}
@@ -64,6 +65,7 @@ public:
// On Windows, we need to update the HDC for form controls to draw in the right place.
void save();
void restore();
+ void flush();
void clip(const FloatRect&);
void clip(const Path&);
void scale(const FloatSize&);
diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
index 96e5604..6db7e88 100644
--- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -38,6 +38,7 @@
#include <wtf/Assertions.h>
#include <wtf/OwnArrayPtr.h>
#include <wtf/RetainPtr.h>
+#include <math.h>
using namespace std;
@@ -48,7 +49,7 @@ ImageBufferData::ImageBufferData(const IntSize&)
{
}
-ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
@@ -57,7 +58,7 @@ ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
if (size.width() < 0 || size.height() < 0)
return;
bytesPerRow = size.width();
- if (!grayScale) {
+ if (imageColorSpace != GrayScale) {
// Protect against overflow
if (bytesPerRow > 0x3FFFFFFF)
return;
@@ -67,9 +68,26 @@ ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
m_data.m_data = tryFastCalloc(size.height(), bytesPerRow);
ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0);
- CGColorSpaceRef colorSpace = grayScale ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
+ CGColorSpaceRef colorSpace;
+ switch(imageColorSpace) {
+ case DeviceRGB:
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+ break;
+ case GrayScale:
+ colorSpace = CGColorSpaceCreateDeviceGray();
+ break;
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER)
+ case LinearRGB:
+ colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
+ break;
+#endif
+ default:
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+ break;
+ }
+
CGContextRef cgContext = CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow,
- colorSpace, grayScale ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast);
+ colorSpace, (imageColorSpace == GrayScale) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
if (!cgContext)
return;
diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp
index dbf1d85..a5620e8 100644
--- a/WebCore/platform/graphics/cg/ImageCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -166,32 +166,44 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F
// interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed
// into the destination rect. See <rdar://problem/6112909>.
shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && srcRect.size() != destRect.size();
+ float xScale = srcRect.width() / destRect.width();
+ float yScale = srcRect.height() / destRect.height();
if (shouldUseSubimage) {
- image = CGImageCreateWithImageInRect(image, srcRect);
+ FloatRect subimageRect = srcRect;
+ float leftPadding = srcRect.x() - floorf(srcRect.x());
+ float topPadding = srcRect.y() - floorf(srcRect.y());
+
+ subimageRect.move(-leftPadding, -topPadding);
+ adjustedDestRect.move(-leftPadding / xScale, -topPadding / yScale);
+
+ subimageRect.setWidth(ceilf(subimageRect.width() + leftPadding));
+ adjustedDestRect.setWidth(subimageRect.width() / xScale);
+
+ subimageRect.setHeight(ceilf(subimageRect.height() + topPadding));
+ adjustedDestRect.setHeight(subimageRect.height() / yScale);
+
+ image = CGImageCreateWithImageInRect(image, subimageRect);
if (currHeight < srcRect.bottom()) {
ASSERT(CGImageGetHeight(image) == currHeight - CGRectIntegral(srcRect).origin.y);
- adjustedDestRect.setHeight(destRect.height() / srcRect.height() * CGImageGetHeight(image));
+ adjustedDestRect.setHeight(CGImageGetHeight(image) / yScale);
}
} else {
- float xScale = srcRect.width() / destRect.width();
- float yScale = srcRect.height() / destRect.height();
-
adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale));
adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale));
-
- CGContextClipToRect(context, destRect);
}
+
+ CGContextClipToRect(context, destRect);
}
// If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly.
if (!shouldUseSubimage && currHeight < selfSize.height())
adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height());
- // Flip the coords.
ctxt->setCompositeOperation(compositeOp);
- CGContextTranslateCTM(context, adjustedDestRect.x(), adjustedDestRect.bottom());
+
+ // Flip the coords.
CGContextScaleCTM(context, 1, -1);
- adjustedDestRect.setLocation(FloatPoint());
+ adjustedDestRect.setY(-adjustedDestRect.bottom());
// Draw the image.
CGContextDrawImage(context, adjustedDestRect, image);
@@ -205,7 +217,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F
imageObserver()->didDraw(this);
}
-void Image::drawPatternCallback(void* info, CGContextRef context)
+static void drawPatternCallback(void* info, CGContextRef context)
{
CGImageRef image = (CGImageRef)info;
CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect(0, 0, CGImageGetWidth(image), CGImageGetHeight(image))), image);
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
index 7cb8799..b716060 100644
--- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -38,7 +38,14 @@
namespace WebCore {
static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
-static const CFStringRef kCGImageSourceDoNotCacheImageBlocks = CFSTR("kCGImageSourceDoNotCacheImageBlocks");
+
+#if !PLATFORM(MAC)
+static void sharedBufferDerefCallback(void*, void* info)
+{
+ SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+ sharedBuffer->deref();
+}
+#endif
ImageSource::ImageSource()
: m_decoder(0)
@@ -79,11 +86,12 @@ void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool
static CFDictionaryRef imageSourceOptions()
{
static CFDictionaryRef options;
-
+
if (!options) {
- const void* keys[3] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceDoNotCacheImageBlocks };
- const void* values[3] = { kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue };
- options = CFDictionaryCreate(NULL, keys, values, 3,
+ const unsigned numOptions = 2;
+ const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
+ const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue };
+ options = CFDictionaryCreate(NULL, keys, values, numOptions,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
return options;
@@ -104,8 +112,12 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
CFDataRef cfData = data->createCFData();
#else
// If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the
- // scenes. We use CFDataCreateWithBytesNoCopy in that case.
- CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), kCFAllocatorNull);
+ // scenes. We use CFDataCreateWithBytesNoCopy in that case. Ensure that the SharedBuffer lives as long as the CFDataRef.
+ data->ref();
+ CFAllocatorContext context = {0, data, 0, 0, 0, 0, 0, &sharedBufferDerefCallback, 0};
+ CFAllocatorRef derefAllocator = CFAllocatorCreate(kCFAllocatorDefault, &context);
+ CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), derefAllocator);
+ CFRelease(derefAllocator);
#endif
CGImageSourceUpdateData(m_decoder, cfData, allDataReceived);
CFRelease(cfData);
diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
index 2578f08..858b18e 100644
--- a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
+++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
@@ -68,11 +68,11 @@ bool PDFDocumentImage::dataChanged(bool allDataReceived)
#if PLATFORM(MAC)
// On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability
// to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.
- CFDataRef data = m_data->createCFData();
+ CFDataRef data = this->data()->createCFData();
#else
// If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the
// scenes. We use CFDataCreateWithBytesNoCopy in that case.
- CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(m_data->data()), m_data->size(), kCFAllocatorNull);
+ CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(this->data()->data()), this->data()->size(), kCFAllocatorNull);
#endif
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
CFRelease(data);
diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp
index ebd0359..5812cea 100644
--- a/WebCore/platform/graphics/cg/PathCG.cpp
+++ b/WebCore/platform/graphics/cg/PathCG.cpp
@@ -245,7 +245,12 @@ void Path::clear()
bool Path::isEmpty() const
{
return CGPathIsEmpty(m_path);
- }
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *element)
{
diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp
index 697bc57..63628f4 100644
--- a/WebCore/platform/graphics/cg/PatternCG.cpp
+++ b/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -62,10 +62,10 @@ CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& userSpac
// If FLT_MAX should also be used for xStep or yStep, nothing is rendered. Using fractions of FLT_MAX also
// result in nothing being rendered.
// INT_MAX is almost correct, but there seems to be some number wrapping occuring making the fill
- // pattern is not filled correctly.
- // So, just pick a really large number that works.
- float xStep = m_repeatX ? tileRect.width() : (100000000.0f);
- float yStep = m_repeatY ? tileRect.height() : (100000000.0f);
+ // pattern is not filled correctly.
+ // To make error of floating point less than 0.5, we use the half of the number of mantissa of float (1 << 22).
+ CGFloat xStep = m_repeatX ? tileRect.width() : (1 << 22);
+ CGFloat yStep = m_repeatY ? tileRect.height() : (1 << 22);
// The pattern will release the tile when it's done rendering in patternReleaseCallback
tileImage()->ref();
diff --git a/WebCore/platform/graphics/chromium/ColorChromiumMac.mm b/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
deleted file mode 100644
index 01dff7e..0000000
--- a/WebCore/platform/graphics/chromium/ColorChromiumMac.mm
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Color.h"
-
-#import <AppKit/NSColor.h>
-#import <wtf/Assertions.h>
-#import <wtf/StdLibExtras.h>
-#import <wtf/RetainPtr.h>
-
-namespace WebCore {
-
-Color focusRingColor()
-{
- // To avoid the Mac Chromium build having to rebasline 500+ layout tests and
- // continue to do this w/ new tests that get landed in WebKit, we want to
- // run the layout tests w/ the same color that stock WebKit uses.
- //
- // FIXME: For now we've hard coded the color that WebKit uses for layout
- // tests. We need to revisit this and do either of the following:
- // A. Fully honor the color from the UI, which means collecting the color
- // (and change notifications) in the browser process, and messaging the
- // color to the render process.
- // B. Adding a "layout tests" flag, to control the orage vs. blue colors
- // depending if we're running layout tests.
- // To see the WebKit implementation of using the UI color and/or a flag for
- // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm.
- // (Reality is we just need an api to override the focus color and both
- // of the above are covered for what this file needs to provide, the
- // two options would be details that happen in other places.)
-
- // From WebKit:
- // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9;
- static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF);
- return oldAquaFocusRingColor;
-}
-
-// createCGColor() and the functions it calls are verbatum copies of
-// graphics/mac/ColorMac.mm. These are copied here so that we don't need to
-// include ColorMac.mm in the Chromium build.
-// FIXME: Check feasibility of using pure CG calls and unifying this copy with
-// ColorMac.mm's under graphics/cg.
-
-NSColor* nsColor(const Color& color)
-{
- unsigned c = color.rgb();
- switch (c) {
- case 0: {
- // Need this to avoid returning nil because cachedRGBAValues will default to 0.
- DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:0.0f]));
- return clearColor.get();
- }
- case Color::black: {
- DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:1.0f]));
- return blackColor.get();
- }
- case Color::white: {
- DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f]));
- return whiteColor.get();
- }
- default: {
- const int cacheSize = 32;
- static unsigned cachedRGBAValues[cacheSize];
- static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize];
-
- for (int i = 0; i != cacheSize; ++i)
- if (cachedRGBAValues[i] == c)
- return cachedColors[i].get();
-
- NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f
- green:color.green() / 255.0f
- blue:color.blue() / 255.0f
- alpha:color.alpha() /255.0f];
-
- static int cursor;
- cachedRGBAValues[cursor] = c;
- cachedColors[cursor] = result;
- if (++cursor == cacheSize)
- cursor = 0;
- return result;
- }
- }
-}
-
-static CGColorRef CGColorFromNSColor(NSColor* color)
-{
- // This needs to always use device colorspace so it can de-calibrate the color for
- // CGColor to possibly recalibrate it.
- NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- CGFloat red = [deviceColor redComponent];
- CGFloat green = [deviceColor greenComponent];
- CGFloat blue = [deviceColor blueComponent];
- CGFloat alpha = [deviceColor alphaComponent];
- const CGFloat components[4] = { red, green, blue, alpha };
- static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB();
- CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components);
- return cgColor;
-}
-
-CGColorRef createCGColor(const Color& c)
-{
- // We could directly create a CGColor here, but that would
- // skip any RGB caching the nsColor method does. A direct
- // creation could be investigated for a possible performance win.
- return CGColorFromNSColor(nsColor(c));
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
index bf1cd2e..9252ae0 100644
--- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
@@ -288,7 +288,7 @@ static bool fontContainsCharacter(const FontPlatformData* fontData,
if (count == 0 && ChromiumBridge::ensureFontLoaded(hfont))
count = GetFontUnicodeRanges(hdc, 0);
if (count == 0) {
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the font unicode range after second attempt");
SelectObject(hdc, oldFont);
ReleaseDC(0, hdc);
return true;
diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
index 797825e..3fe1561 100644
--- a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
@@ -31,9 +31,8 @@
#include "config.h"
#include "FontCache.h"
-#include <fontconfig/fontconfig.h>
-
#include "AtomicString.h"
+#include "ChromiumBridge.h"
#include "CString.h"
#include "Font.h"
#include "FontDescription.h"
@@ -46,6 +45,7 @@
#include "SkTypeface.h"
#include "SkUtils.h"
+#include <unicode/utf16.h>
#include <wtf/Assertions.h>
namespace WebCore {
@@ -58,38 +58,12 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font,
const UChar* characters,
int length)
{
- FcCharSet* cset = FcCharSetCreate();
- for (int i = 0; i < length; ++i)
- FcCharSetAddChar(cset, characters[i]);
-
- FcPattern* pattern = FcPatternCreate();
-
- FcValue fcvalue;
- fcvalue.type = FcTypeCharSet;
- fcvalue.u.c = cset;
- FcPatternAdd(pattern, FC_CHARSET, fcvalue, 0);
-
- FcConfigSubstitute(0, pattern, FcMatchPattern);
- FcDefaultSubstitute(pattern);
-
- FcResult result;
- FcPattern* match = FcFontMatch(0, pattern, &result);
- FcPatternDestroy(pattern);
-
- SimpleFontData* ret = 0;
-
- if (match) {
- FcChar8* family;
- if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) {
- AtomicString fontFamily(reinterpret_cast<char*>(family));
- ret = getCachedFontData(getCachedFontPlatformData(font.fontDescription(), fontFamily, false));
- }
- FcPatternDestroy(match);
- }
-
- FcCharSetDestroy(cset);
+ String family = ChromiumBridge::getFontFamilyForCharacters(characters, length);
+ if (family.isEmpty())
+ return 0;
- return ret;
+ AtomicString atomicFamily(family);
+ return getCachedFontData(getCachedFontPlatformData(font.fontDescription(), atomicFamily, false));
}
FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
@@ -165,13 +139,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
if (fontDescription.italic())
style |= SkTypeface::kItalic;
- // FIXME: This #ifdef can go away once we're firmly using the new Skia.
- // During the transition, this makes the code compatible with both versions.
-#ifdef SK_USE_OLD_255_TO_256
SkTypeface* tf = SkTypeface::CreateFromName(name, static_cast<SkTypeface::Style>(style));
-#else
- SkTypeface* tf = SkTypeface::Create(name, static_cast<SkTypeface::Style>(style));
-#endif
if (!tf)
return 0;
diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
index 4710245..3d67992 100644
--- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
@@ -146,17 +146,23 @@ void TransparencyAwareFontPainter::initializeForGDI()
// know everything is opaque so don't need to do anything special.
layerMode = TransparencyWin::NoLayer;
}
- m_transparency.init(m_graphicsContext, layerMode, TransparencyWin::KeepTransform, layerRect);
+
+ // Bug 26088 - init() might fail if layerRect is invalid. Given this, we
+ // need to be careful to check for null pointers everywhere after this call
+ m_transparency.init(m_graphicsContext, layerMode,
+ TransparencyWin::KeepTransform, layerRect);
// Set up the DC, using the one from the transparency helper.
- m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
- SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
- SetBkMode(m_hdc, TRANSPARENT);
+ if (m_transparency.platformContext()) {
+ m_hdc = m_transparency.platformContext()->canvas()->beginPlatformPaint();
+ SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(m_hdc, TRANSPARENT);
+ }
}
TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
{
- if (!m_useGDI)
+ if (!m_useGDI || !m_graphicsContext || !m_platformContext)
return; // Nothing to do.
m_transparency.composite();
if (m_createdTransparencyLayer)
@@ -208,12 +214,13 @@ TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter(
{
init();
- m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
+ if (m_hdc)
+ m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
}
TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter()
{
- if (m_useGDI)
+ if (m_useGDI && m_hdc)
::SelectObject(m_hdc, m_oldFont);
}
@@ -245,6 +252,9 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
numGlyphs, glyphs, advances, 0, &origin);
}
+ if (!m_graphicsContext || !m_hdc)
+ return true;
+
// Windows' origin is the top-left of the bounding box, so we have
// to subtract off the font ascent to get it.
int x = lroundf(m_point.x() + startAdvance);
@@ -265,7 +275,7 @@ bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
COLORREF savedTextColor = GetTextColor(m_hdc);
SetTextColor(m_hdc, textColor);
ExtTextOut(m_hdc, x + shadowSize.width(), y + shadowSize.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
- SetTextColor(m_hdc, savedTextColor);
+ SetTextColor(m_hdc, savedTextColor);
}
return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
@@ -379,6 +389,17 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
for (int i = 0; i < curLen; ++i, ++glyphIndex) {
glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
+
+ // Bug 26088 - very large positive or negative runs can fail to
+ // render so we clamp the size here. In the specs, negative
+ // letter-spacing is implementation-defined, so this should be
+ // fine, and it matches Safari's implementation. The call actually
+ // seems to crash if kMaxNegativeRun is set to somewhere around
+ // -32830, so we give ourselves a little breathing room.
+ const int maxNegativeRun = -32768;
+ const int maxPositiveRun = 32768;
+ if ((curWidth + advances[i] < maxNegativeRun) || (curWidth + advances[i] > maxPositiveRun))
+ advances[i] = 0;
curWidth += advances[i];
}
@@ -394,7 +415,9 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
break;
}
- ASSERT(success);
+ if (!success)
+ LOG_ERROR("Unable to draw the glyphs after second attempt");
+
curAdvance += curWidth;
}
}
@@ -436,6 +459,8 @@ void Font::drawComplexText(GraphicsContext* graphicsContext,
TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);
HDC hdc = painter.hdc();
+ if (!hdc)
+ return;
// TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
// Enforce non-transparent color.
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
index e99c12a..88035d5 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
@@ -36,6 +36,8 @@
#include "Base64.h"
#include "ChromiumBridge.h"
#include "OpenTypeUtilities.h"
+#elif PLATFORM(LINUX)
+#include "SkStream.h"
#endif
#include "FontPlatformData.h"
@@ -46,6 +48,8 @@
#include <objbase.h>
#include <t2embapi.h>
#pragma comment(lib, "t2embed")
+#elif PLATFORM(LINUX)
+#include <cstring>
#endif
namespace WebCore {
@@ -60,6 +64,9 @@ FontCustomPlatformData::~FontCustomPlatformData()
} else
RemoveFontMemResourceEx(m_fontReference);
}
+#elif PLATFORM(LINUX)
+ if (m_fontReference)
+ m_fontReference->unref();
#endif
}
@@ -102,6 +109,9 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
HFONT hfont = CreateFontIndirect(&logFont);
return FontPlatformData(hfont, size);
+#elif PLATFORM(LINUX)
+ ASSERT(m_fontReference);
+ return FontPlatformData(m_fontReference, size, bold && !m_fontReference->isBold(), italic && !m_fontReference->isItalic());
#else
notImplemented();
return FontPlatformData();
@@ -186,6 +196,51 @@ static String createUniqueFontName()
}
#endif
+#if PLATFORM(LINUX)
+class RemoteFontStream : public SkStream {
+public:
+ explicit RemoteFontStream(PassRefPtr<SharedBuffer> buffer)
+ : m_buffer(buffer)
+ , m_offset(0)
+ {
+ }
+
+ virtual ~RemoteFontStream()
+ {
+ }
+
+ virtual bool rewind()
+ {
+ m_offset = 0;
+ return true;
+ }
+
+ virtual size_t read(void* buffer, size_t size)
+ {
+ if (!buffer && !size) {
+ // This is request for the length of the stream.
+ return m_buffer->size();
+ }
+ if (!buffer) {
+ // This is a request to skip bytes. This operation is not supported.
+ return 0;
+ }
+ // This is a request to read bytes.
+ if (!m_buffer->data() || !m_buffer->size())
+ return 0;
+ size_t left = m_buffer->size() - m_offset;
+ size_t toRead = (left > size) ? size : left;
+ std::memcpy(buffer, m_buffer->data() + m_offset, toRead);
+ m_offset += toRead;
+ return toRead;
+ }
+
+private:
+ RefPtr<SharedBuffer> m_buffer;
+ size_t m_offset;
+};
+#endif
+
FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
{
ASSERT_ARG(buffer, buffer);
@@ -223,8 +278,14 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
}
return new FontCustomPlatformData(fontReference, fontName);
+#elif PLATFORM(LINUX)
+ RemoteFontStream stream(buffer);
+ SkTypeface* typeface = SkTypeface::CreateFromStream(&stream);
+ if (!typeface)
+ return 0;
+ return new FontCustomPlatformData(typeface);
#else
- notImplemented();;
+ notImplemented();
return 0;
#endif
}
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
index 2f1a597..a42f1ec 100644
--- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
@@ -32,12 +32,14 @@
#ifndef FontCustomPlatformData_h
#define FontCustomPlatformData_h
+#include "FontRenderingMode.h"
#include <wtf/Noncopyable.h>
#if PLATFORM(WIN_OS)
-#include "FontRenderingMode.h"
#include "PlatformString.h"
#include <windows.h>
+#elif PLATFORM(LINUX)
+#include "SkTypeface.h"
#endif
namespace WebCore {
@@ -51,6 +53,10 @@ struct FontCustomPlatformData : Noncopyable {
: m_fontReference(fontReference)
, m_name(name)
{}
+#elif PLATFORM(LINUX)
+ explicit FontCustomPlatformData(SkTypeface* typeface)
+ : m_fontReference(typeface)
+ {}
#endif
~FontCustomPlatformData();
@@ -61,6 +67,8 @@ struct FontCustomPlatformData : Noncopyable {
#if PLATFORM(WIN_OS)
HANDLE m_fontReference;
String m_name;
+#elif PLATFORM(LINUX)
+ SkTypeface* m_fontReference;
#endif
};
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index a952685..d4e45fb 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -34,6 +34,7 @@
#include "FloatRect.h"
#include "GlyphBuffer.h"
#include "GraphicsContext.h"
+#include "HarfbuzzSkia.h"
#include "NotImplemented.h"
#include "PlatformContextSkia.h"
#include "SimpleFontData.h"
@@ -54,7 +55,7 @@ bool Font::canReturnFallbackFontsForComplexText()
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
const FloatPoint& point) const {
- SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
SkScalar x = SkFloatToScalar(point.x());
@@ -96,7 +97,6 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
SkPaint paint;
gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
font->platformData().setupPaint(&paint);
- paint.setFlags(SkPaint::kAntiAlias_Flag);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setColor(gc->strokeColor().rgb());
@@ -110,31 +110,503 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
}
}
-void Font::drawComplexText(GraphicsContext* context, const TextRun& run,
+// Harfbuzz uses 26.6 fixed point values for pixel offsets. However, we don't
+// handle subpixel positioning so this function is used to truncate Harfbuzz
+// values to a number of pixels.
+static int truncateFixedPointToInteger(HB_Fixed value)
+{
+ return value >> 6;
+}
+
+// TextRunWalker walks a TextRun and presents each script run in sequence. A
+// TextRun is a sequence of code-points with the same embedding level (i.e. they
+// are all left-to-right or right-to-left). A script run is a subsequence where
+// all the characters have the same script (e.g. Arabic, Thai etc). Shaping is
+// only ever done with script runs since the shapers only know how to deal with
+// a single script.
+//
+// After creating it, the script runs are either iterated backwards or forwards.
+// It defaults to backwards for RTL and forwards otherwise (which matches the
+// presentation order), however you can set it with |setBackwardsIteration|.
+//
+// Once you have setup the object, call |nextScriptRun| to get the first script
+// run. This will return false when the iteration is complete. At any time you
+// can call |reset| to start over again.
+class TextRunWalker {
+public:
+ TextRunWalker(const TextRun& run, unsigned startingX, const Font* font)
+ : m_font(font)
+ , m_run(run)
+ , m_startingX(startingX)
+ , m_offsetX(m_startingX)
+ , m_iterateBackwards(run.rtl())
+ {
+ memset(&m_item, 0, sizeof(m_item));
+ // We cannot know, ahead of time, how many glyphs a given script run
+ // will produce. We take a guess that script runs will not produce more
+ // than twice as many glyphs as there are code points and fallback if
+ // we find that we are wrong.
+ m_maxGlyphs = run.length() * 2;
+ createGlyphArrays();
+
+ m_item.log_clusters = new unsigned short[run.length()];
+
+ m_item.face = 0;
+ m_item.font = allocHarfbuzzFont();
+
+ m_item.string = run.characters();
+ m_item.stringLength = run.length();
+ m_item.item.bidiLevel = run.rtl();
+
+ reset();
+ }
+
+ ~TextRunWalker()
+ {
+ fastFree(m_item.font);
+ deleteGlyphArrays();
+ delete[] m_item.log_clusters;
+ }
+
+ void reset()
+ {
+ if (m_iterateBackwards)
+ m_indexOfNextScriptRun = m_run.length() - 1;
+ else
+ m_indexOfNextScriptRun = 0;
+ m_offsetX = m_startingX;
+ }
+
+ // Set the x offset for the next script run. This affects the values in
+ // |xPositions|
+ void setXOffsetToZero()
+ {
+ m_offsetX = 0;
+ }
+
+ bool rtl() const
+ {
+ return m_run.rtl();
+ }
+
+ void setBackwardsIteration(bool isBackwards)
+ {
+ m_iterateBackwards = isBackwards;
+ reset();
+ }
+
+ // Advance to the next script run, returning false when the end of the
+ // TextRun has been reached.
+ bool nextScriptRun()
+ {
+ if (m_iterateBackwards) {
+ // In right-to-left mode we need to render the shaped glyph backwards and
+ // also render the script runs themselves backwards. So given a TextRun:
+ // AAAAAAACTTTTTTT (A = Arabic, C = Common, T = Thai)
+ // we render:
+ // TTTTTTCAAAAAAA
+ // (and the glyphs in each A, C and T section are backwards too)
+ if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+ return false;
+ } else {
+ if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun))
+ return false;
+ }
+
+ setupFontForScriptRun();
+
+ if (!shapeGlyphs())
+ return false;
+ setGlyphXPositions(rtl());
+ return true;
+ }
+
+ const uint16_t* glyphs() const
+ {
+ return m_glyphs16;
+ }
+
+ // Return the length of the array returned by |glyphs|
+ const unsigned length() const
+ {
+ return m_item.num_glyphs;
+ }
+
+ // Return the x offset for each of the glyphs. Note that this is translated
+ // by the current x offset and that the x offset is updated for each script
+ // run.
+ const SkScalar* xPositions() const
+ {
+ return m_xPositions;
+ }
+
+ // Get the advances (widths) for each glyph.
+ const HB_Fixed* advances() const
+ {
+ return m_item.advances;
+ }
+
+ // Return the width (in px) of the current script run.
+ const unsigned width() const
+ {
+ return m_pixelWidth;
+ }
+
+ // Return the cluster log for the current script run. For example:
+ // script run: f i a n c é (fi gets ligatured)
+ // log clutrs: 0 0 1 2 3 4
+ // So, for each input code point, the log tells you which output glyph was
+ // generated for it.
+ const unsigned short* logClusters() const
+ {
+ return m_item.log_clusters;
+ }
+
+ // return the number of code points in the current script run
+ const unsigned numCodePoints() const
+ {
+ return m_numCodePoints;
+ }
+
+ const FontPlatformData* fontPlatformDataForScriptRun()
+ {
+ return reinterpret_cast<FontPlatformData*>(m_item.font->userData);
+ }
+
+ float widthOfFullRun()
+ {
+ float widthSum = 0;
+ while (nextScriptRun())
+ widthSum += width();
+
+ return widthSum;
+ }
+
+private:
+ void setupFontForScriptRun()
+ {
+ const FontData* fontData = m_font->fontDataAt(0);
+ if (!fontData->containsCharacters(m_item.string + m_item.item.pos, m_item.item.length))
+ fontData = m_font->fontDataForCharacters(m_item.string + m_item.item.pos, m_item.item.length);
+ const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData();
+ m_item.face = platformData.harfbuzzFace();
+ void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData);
+ m_item.font->userData = opaquePlatformData;
+ }
+
+ HB_FontRec* allocHarfbuzzFont()
+ {
+ HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec)));
+ memset(font, 0, sizeof(HB_FontRec));
+ font->klass = &harfbuzzSkiaClass;
+ font->userData = 0;
+ // The values which harfbuzzSkiaClass returns are already scaled to
+ // pixel units, so we just set all these to one to disable further
+ // scaling.
+ font->x_ppem = 1;
+ font->y_ppem = 1;
+ font->x_scale = 1;
+ font->y_scale = 1;
+
+ return font;
+ }
+
+ void deleteGlyphArrays()
+ {
+ delete[] m_item.glyphs;
+ delete[] m_item.attributes;
+ delete[] m_item.advances;
+ delete[] m_item.offsets;
+ delete[] m_glyphs16;
+ delete[] m_xPositions;
+ }
+
+ bool createGlyphArrays()
+ {
+ m_item.glyphs = new HB_Glyph[m_maxGlyphs];
+ m_item.attributes = new HB_GlyphAttributes[m_maxGlyphs];
+ m_item.advances = new HB_Fixed[m_maxGlyphs];
+ m_item.offsets = new HB_FixedPoint[m_maxGlyphs];
+ m_glyphs16 = new uint16_t[m_maxGlyphs];
+ m_xPositions = new SkScalar[m_maxGlyphs];
+
+ return m_item.glyphs
+ && m_item.attributes
+ && m_item.advances
+ && m_item.offsets
+ && m_glyphs16
+ && m_xPositions;
+ }
+
+ bool expandGlyphArrays()
+ {
+ deleteGlyphArrays();
+ m_maxGlyphs <<= 1;
+ return createGlyphArrays();
+ }
+
+ bool shapeGlyphs()
+ {
+ for (;;) {
+ m_item.num_glyphs = m_maxGlyphs;
+ HB_ShapeItem(&m_item);
+ if (m_item.num_glyphs < m_maxGlyphs)
+ break;
+
+ // We overflowed our arrays. Resize and retry.
+ if (!expandGlyphArrays())
+ return false;
+ }
+
+ return true;
+ }
+
+ void setGlyphXPositions(bool isRTL)
+ {
+ m_pixelWidth = 0;
+ for (unsigned i = 0; i < m_item.num_glyphs; ++i) {
+ int index;
+ if (isRTL)
+ index = m_item.num_glyphs - (i + 1);
+ else
+ index = i;
+
+ m_glyphs16[i] = m_item.glyphs[i];
+ m_xPositions[index] = m_offsetX + m_pixelWidth;
+ m_pixelWidth += truncateFixedPointToInteger(m_item.advances[index]);
+ }
+ m_offsetX += m_pixelWidth;
+ }
+
+ const Font* const m_font;
+ const TextRun& m_run;
+ HB_ShaperItem m_item;
+ uint16_t* m_glyphs16; // A vector of 16-bit glyph ids.
+ SkScalar* m_xPositions; // A vector of x positions for each glyph.
+ ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|.
+ const unsigned m_startingX; // Offset in pixels of the first script run.
+ unsigned m_offsetX; // Offset in pixels to the start of the next script run.
+ unsigned m_pixelWidth; // Width (in px) of the current script run.
+ unsigned m_numCodePoints; // Code points in current script run.
+ unsigned m_maxGlyphs; // Current size of all the Harfbuzz arrays.
+ bool m_iterateBackwards;
+};
+
+static void setupForTextPainting(SkPaint* paint, SkColor color)
+{
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint->setColor(color);
+}
+
+void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
const FloatPoint& point, int from, int to) const
{
- notImplemented();
+ if (!run.length())
+ return;
+
+ SkCanvas* canvas = gc->platformContext()->canvas();
+ int textMode = gc->platformContext()->getTextDrawingMode();
+ bool fill = textMode & cTextFill;
+ bool stroke = (textMode & cTextStroke)
+ && gc->platformContext()->getStrokeStyle() != NoStroke
+ && gc->platformContext()->getStrokeThickness() > 0;
+
+ if (!fill && !stroke)
+ return;
+
+ SkPaint strokePaint, fillPaint;
+ if (fill) {
+ gc->platformContext()->setupPaintForFilling(&fillPaint);
+ setupForTextPainting(&fillPaint, gc->fillColor().rgb());
+ }
+ if (stroke) {
+ gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0);
+ setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
+ }
+
+ TextRunWalker walker(run, point.x(), this);
+
+ while (walker.nextScriptRun()) {
+ if (fill) {
+ walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
+ canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint);
+ }
+
+ if (stroke) {
+ walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
+ canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint);
+ }
+ }
}
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */) const
{
- notImplemented();
- return 0;
+ TextRunWalker walker(run, 0, this);
+ return walker.widthOfFullRun();
}
+static int glyphIndexForXPositionInScriptRun(const TextRunWalker& walker, int x)
+{
+ const HB_Fixed* advances = walker.advances();
+ int glyphIndex;
+ if (walker.rtl()) {
+ for (glyphIndex = walker.length() - 1; glyphIndex >= 0; --glyphIndex) {
+ if (x < truncateFixedPointToInteger(advances[glyphIndex]))
+ break;
+ x -= truncateFixedPointToInteger(advances[glyphIndex]);
+ }
+ } else {
+ for (glyphIndex = 0; glyphIndex < walker.length(); ++glyphIndex) {
+ if (x < truncateFixedPointToInteger(advances[glyphIndex]))
+ break;
+ x -= truncateFixedPointToInteger(advances[glyphIndex]);
+ }
+ }
+
+ return glyphIndex;
+}
+
+// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, int x,
bool includePartialGlyphs) const
{
- notImplemented();
- return 0;
+ // (Mac code ignores includePartialGlyphs, and they don't know what it's
+ // supposed to do, so we just ignore it as well.)
+ TextRunWalker walker(run, 0, this);
+
+ // If this is RTL text, the first glyph from the left is actually the last
+ // code point. So we need to know how many code points there are total in
+ // order to subtract. This is different from the length of the TextRun
+ // because UTF-16 surrogate pairs are a single code point, but 32-bits long.
+ // In LTR we leave this as 0 so that we get the correct value for
+ // |basePosition|, below.
+ unsigned totalCodePoints = 0;
+ if (walker.rtl()) {
+ ssize_t offset = 0;
+ while (offset < run.length()) {
+ utf16_to_code_point(run.characters(), run.length(), &offset);
+ totalCodePoints++;
+ }
+ }
+
+ unsigned basePosition = totalCodePoints;
+
+ // For RTL:
+ // code-point order: abcd efg hijkl
+ // on screen: lkjih gfe dcba
+ // ^ ^
+ // | |
+ // basePosition--| |
+ // totalCodePoints----|
+ // Since basePosition is currently the total number of code-points, the
+ // first thing we do is decrement it so that it's pointing to the start of
+ // the current script-run.
+ //
+ // For LTR, basePosition is zero so it already points to the start of the
+ // first script run.
+ while (walker.nextScriptRun()) {
+ if (walker.rtl())
+ basePosition -= walker.numCodePoints();
+
+ if (x < walker.width()) {
+ // The x value in question is within this script run. We consider
+ // each glyph in presentation order and stop when we find the one
+ // covering this position.
+ const int glyphIndex = glyphIndexForXPositionInScriptRun(walker, x);
+
+ // Now that we have a glyph index, we have to turn that into a
+ // code-point index. Because of ligatures, several code-points may
+ // have gone into a single glyph. We iterate over the clusters log
+ // and find the first code-point which contributed to the glyph.
+
+ // Some shapers (i.e. Khmer) will produce cluster logs which report
+ // that /no/ code points contributed to certain glyphs. Because of
+ // this, we take any code point which contributed to the glyph in
+ // question, or any subsequent glyph. If we run off the end, then
+ // we take the last code point.
+ const unsigned short* log = walker.logClusters();
+ for (unsigned j = 0; j < walker.numCodePoints(); ++j) {
+ if (log[j] >= glyphIndex)
+ return basePosition + j;
+ }
+
+ return basePosition + walker.numCodePoints() - 1;
+ }
+
+ x -= walker.width();
+
+ if (!walker.rtl())
+ basePosition += walker.numCodePoints();
+ }
+
+ return basePosition;
}
+// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
- const IntPoint& point, int h,
+ const IntPoint& point, int height,
int from, int to) const
{
- notImplemented();
- return FloatRect();
+ int fromX = -1, toX = -1, fromAdvance = -1, toAdvance = -1;
+ TextRunWalker walker(run, 0, this);
+
+ // Base will point to the x offset for the current script run. Note that, in
+ // the LTR case, width will be 0.
+ int base = walker.rtl() ? walker.widthOfFullRun() : 0;
+ const int leftEdge = base;
+
+ // We want to enumerate the script runs in code point order in the following
+ // code. This call also resets |walker|.
+ walker.setBackwardsIteration(false);
+
+ while (walker.nextScriptRun() && (fromX == -1 || toX == -1)) {
+ // TextRunWalker will helpfully accululate the x offsets for different
+ // script runs for us. For this code, however, we always want the x offsets
+ // to start from zero so we call this before each script run.
+ walker.setXOffsetToZero();
+
+ if (walker.rtl())
+ base -= walker.width();
+
+ if (fromX == -1 && from < walker.numCodePoints()) {
+ // |from| is within this script run. So we index the clusters log to
+ // find which glyph this code-point contributed to and find its x
+ // position.
+ int glyph = walker.logClusters()[from];
+ fromX = base + walker.xPositions()[glyph];
+ fromAdvance = walker.advances()[glyph];
+ } else
+ from -= walker.numCodePoints();
+
+ if (toX == -1 && to < walker.numCodePoints()) {
+ int glyph = walker.logClusters()[to];
+ toX = base + walker.xPositions()[glyph];
+ toAdvance = walker.advances()[glyph];
+ } else
+ to -= walker.numCodePoints();
+
+ if (!walker.rtl())
+ base += walker.width();
+ }
+
+ // The position in question might be just after the text.
+ const int rightEdge = base;
+ if (fromX == -1 && !from)
+ fromX = leftEdge;
+ else if (walker.rtl())
+ fromX += truncateFixedPointToInteger(fromAdvance);
+
+ if (toX == -1 && !to)
+ toX = rightEdge;
+ else if (!walker.rtl())
+ toX += truncateFixedPointToInteger(toAdvance);
+
+ ASSERT(fromX != -1 && toX != -1);
+
+ if (fromX < toX)
+ return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
+
+ return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
}
-} // namespace WebCore
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
index 767fe76..d6c83ec 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
@@ -141,7 +141,7 @@ SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
hr = ScriptGetFontProperties(dc, scriptCache(),
m_scriptFontProperties);
if (S_OK != hr) {
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the font properties after second attempt");
}
}
}
@@ -153,4 +153,11 @@ SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
return m_scriptFontProperties;
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
}
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
index ce15a93..25c9cf8 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
@@ -45,6 +45,7 @@ typedef struct HFONT__ *HFONT;
namespace WebCore {
class FontDescription;
+class String;
class FontPlatformData {
public:
@@ -78,6 +79,10 @@ public:
return m_font == other.m_font && m_size == other.m_size;
}
+#ifndef NDEBUG
+ String description() const;
+#endif
+
SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
index e6a61f6..bf4697f 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
@@ -31,19 +31,45 @@
#include "config.h"
#include "FontPlatformData.h"
-#include "StringImpl.h"
+#include "HarfbuzzSkia.h"
#include "NotImplemented.h"
+#include "PlatformString.h"
+#include "StringImpl.h"
#include "SkPaint.h"
#include "SkTypeface.h"
namespace WebCore {
+static SkPaint::Hinting skiaHinting = SkPaint::kNormal_Hinting;
+static bool isSkiaAntiAlias = true, isSkiaSubpixelGlyphs;
+
+void FontPlatformData::setHinting(SkPaint::Hinting hinting)
+{
+ skiaHinting = hinting;
+}
+
+void FontPlatformData::setAntiAlias(bool isAntiAlias)
+{
+ isSkiaAntiAlias = isAntiAlias;
+}
+
+void FontPlatformData::setSubpixelGlyphs(bool isSubpixelGlyphs)
+{
+ isSkiaSubpixelGlyphs = isSubpixelGlyphs;
+}
+
+FontPlatformData::RefCountedHarfbuzzFace::~RefCountedHarfbuzzFace()
+{
+ HB_FreeFace(m_harfbuzzFace);
+}
+
FontPlatformData::FontPlatformData(const FontPlatformData& src)
: m_typeface(src.m_typeface)
, m_textSize(src.m_textSize)
, m_fakeBold(src.m_fakeBold)
, m_fakeItalic(src.m_fakeItalic)
+ , m_harfbuzzFace(src.m_harfbuzzFace)
{
m_typeface->safeRef();
}
@@ -62,6 +88,7 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
, m_textSize(textSize)
, m_fakeBold(src.m_fakeBold)
, m_fakeItalic(src.m_fakeItalic)
+ , m_harfbuzzFace(src.m_harfbuzzFace)
{
m_typeface->safeRef();
}
@@ -78,21 +105,29 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
m_textSize = src.m_textSize;
m_fakeBold = src.m_fakeBold;
m_fakeItalic = src.m_fakeItalic;
+ m_harfbuzzFace = src.m_harfbuzzFace;
return *this;
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
void FontPlatformData::setupPaint(SkPaint* paint) const
{
const float ts = m_textSize > 0 ? m_textSize : 12;
- paint->setAntiAlias(true);
- paint->setSubpixelText(false);
+ paint->setAntiAlias(isSkiaAntiAlias);
+ paint->setHinting(skiaHinting);
+ paint->setLCDRenderText(isSkiaSubpixelGlyphs);
paint->setTextSize(SkFloatToScalar(ts));
paint->setTypeface(m_typeface);
paint->setFakeBoldText(m_fakeBold);
paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
- paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
}
SkFontID FontPlatformData::uniqueID() const
@@ -141,4 +176,12 @@ bool FontPlatformData::isFixedPitch() const
return false;
}
+HB_FaceRec_* FontPlatformData::harfbuzzFace() const
+{
+ if (!m_harfbuzzFace)
+ m_harfbuzzFace = RefCountedHarfbuzzFace::create(HB_NewFace(const_cast<FontPlatformData*>(this), harfbuzzSkiaGetTable));
+
+ return m_harfbuzzFace->face();
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
index c63a860..29ce8e7 100644
--- a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
@@ -33,14 +33,17 @@
#include "StringImpl.h"
#include <wtf/RefPtr.h>
+#include <SkPaint.h>
-class SkPaint;
class SkTypeface;
typedef uint32_t SkFontID;
+struct HB_FaceRec_;
+
namespace WebCore {
class FontDescription;
+class String;
// -----------------------------------------------------------------------------
// FontPlatformData is the handle which WebKit has on a specific face. A face
@@ -104,12 +107,45 @@ public:
FontPlatformData& operator=(const FontPlatformData&);
bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); }
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ HB_FaceRec_* harfbuzzFace() const;
+
+ // -------------------------------------------------------------------------
+ // Global font preferences...
+
+ static void setHinting(SkPaint::Hinting);
+ static void setAntiAlias(bool on);
+ static void setSubpixelGlyphs(bool on);
+
private:
+ class RefCountedHarfbuzzFace : public RefCounted<RefCountedHarfbuzzFace> {
+ public:
+ static PassRefPtr<RefCountedHarfbuzzFace> create(HB_FaceRec_* harfbuzzFace)
+ {
+ return adoptRef(new RefCountedHarfbuzzFace(harfbuzzFace));
+ }
+
+ ~RefCountedHarfbuzzFace();
+
+ HB_FaceRec_* face() const { return m_harfbuzzFace; }
+
+ private:
+ RefCountedHarfbuzzFace(HB_FaceRec_* harfbuzzFace) : m_harfbuzzFace(harfbuzzFace)
+ {
+ }
+
+ HB_FaceRec_* m_harfbuzzFace;
+ };
+
// FIXME: Could SkAutoUnref be used here?
SkTypeface* m_typeface;
float m_textSize;
bool m_fakeBold;
bool m_fakeItalic;
+ mutable RefPtr<RefCountedHarfbuzzFace> m_harfbuzzFace;
SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); }
};
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
index 2cb1cc5..e2c47c1 100644
--- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -87,10 +87,9 @@ static bool fillBMPGlyphs(unsigned offset,
return false;
}
} else {
- // FIXME: This should never happen. We want to crash the
- // process and receive a crash dump. We should revisit this code later.
+ // FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the text metrics after second attempt");
fillEmptyGlyphs(page);
return false;
}
diff --git a/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
new file mode 100644
index 0000000..621d674
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/HarfbuzzSkia.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "Font.h"
+#include "FontPlatformData.h"
+#include "wtf/OwnArrayPtr.h"
+
+#include "SkFontHost.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-unicode.h"
+}
+
+// This file implements the callbacks which Harfbuzz requires by using Skia
+// calls. See the Harfbuzz source for references about what these callbacks do.
+
+namespace WebCore {
+
+static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
+{
+ // HB_Fixed is a 26.6 fixed point format.
+ return value * 64;
+}
+
+static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs));
+
+ // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
+ // |glyphs| array needs to be converted.
+ // Additionally, if the CSS white-space property is inhibiting line
+ // breaking, we might find end-of-line charactors rendered via the complex
+ // text path. Fonts don't provide glyphs for these code points so, if we
+ // find one, we simulate the space glyph being interposed in this case.
+ // Because the input is variable-length per code point, we walk the input
+ // in step with the output.
+ // FIXME: it seems that this logic is duplicated in CoreTextController and UniscribeController
+ ssize_t indexOfNextCodePoint = 0;
+ uint16_t spaceGlyphNumber = 0;
+ for (int i = numGlyphs - 1; i >= 0; --i) {
+ const uint32_t currentCodePoint = utf16_to_code_point(characters, length, &indexOfNextCodePoint);
+
+ uint16_t value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t));
+
+ if (!value && Font::treatAsSpace(currentCodePoint)) {
+ static const uint16_t spaceUTF16 = ' ';
+ if (!spaceGlyphNumber)
+ paint.textToGlyphs(&spaceUTF16, sizeof(spaceUTF16), &spaceGlyphNumber);
+ value = spaceGlyphNumber;
+ }
+
+ glyphs[i] = value;
+ }
+
+ *glyphsSize = numGlyphs;
+ return 1;
+}
+
+static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ OwnArrayPtr<uint16_t> glyphs16(new uint16_t[numGlyphs]);
+ if (!glyphs16.get())
+ return;
+ for (unsigned i = 0; i < numGlyphs; ++i)
+ glyphs16[i] = glyphs[i];
+ paint.getTextWidths(glyphs16.get(), numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+
+ // The |advances| values which Skia outputs are SkScalars, which are floats
+ // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
+ // These two formats are both 32-bits long.
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ float value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(float));
+ advances[i] = SkiaScalarToHarfbuzzFixed(value);
+ }
+}
+
+static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ OwnArrayPtr<uint16_t> glyphs16(new uint16_t[length]);
+ if (!glyphs16.get())
+ return 0;
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16.get());
+
+ bool canRender = true;
+ for (int i = 0; i < numGlyphs; ++i) {
+ if (!glyphs16[i]) {
+ canRender = false;
+ break;
+ }
+ }
+
+ return canRender;
+}
+
+static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ if (flags & HB_ShaperFlag_UseDesignMetrics)
+ return HB_Err_Invalid_Argument; // This is requesting pre-hinted positions. We can't support this.
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkPath path;
+ paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
+ int numPoints = path.getPoints(NULL, 0);
+ if (point >= numPoints)
+ return HB_Err_Invalid_SubTable;
+ SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1)));
+ if (!points)
+ return HB_Err_Invalid_SubTable;
+ // Skia does let us get a single point from the path.
+ path.getPoints(points, point + 1);
+ *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
+ *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+ *resultingNumPoints = numPoints;
+ fastFree(points);
+
+ return HB_Err_Ok;
+}
+
+static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkScalar width;
+ SkRect bounds;
+ paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
+
+ metrics->x = SkiaScalarToHarfbuzzFixed(width);
+ // We can't actually get the |y| correct because Skia doesn't export
+ // the vertical advance. However, nor we do ever render vertical text at
+ // the moment so it's unimportant.
+ metrics->y = 0;
+ metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
+ metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+ metrics->xOffset = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
+ metrics->yOffset = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+}
+
+static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
+ SkPaint paint;
+
+ font->setupPaint(&paint);
+ SkPaint::FontMetrics skiaMetrics;
+ paint.getFontMetrics(&skiaMetrics);
+
+ switch (metric) {
+ case HB_FontAscent:
+ return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
+ // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
+ default:
+ return 0;
+ }
+}
+
+HB_FontClass harfbuzzSkiaClass = {
+ stringToGlyphs,
+ glyphsToAdvances,
+ canRender,
+ getOutlinePoint,
+ getGlyphMetrics,
+ getFontMetric,
+};
+
+HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
+{
+ FontPlatformData* font = reinterpret_cast<FontPlatformData*>(voidface);
+
+ const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag);
+ if (!tableSize)
+ return HB_Err_Invalid_Argument;
+ // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
+ if (!buffer) {
+ *len = tableSize;
+ return HB_Err_Ok;
+ }
+
+ if (*len < tableSize)
+ return HB_Err_Invalid_Argument;
+ SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer);
+ return HB_Err_Ok;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.h b/WebCore/platform/graphics/chromium/HarfbuzzSkia.h
index 9cb4a95..f7e0496 100644
--- a/WebCore/platform/graphics/skia/ImageSourceSkia.h
+++ b/WebCore/platform/graphics/chromium/HarfbuzzSkia.h
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2008, Google Inc. All rights reserved.
- *
+ * Copyright (c) 2009, Google Inc. All rights reserved.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
@@ -14,7 +14,7 @@
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -28,33 +28,17 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "ImageSource.h"
+#ifndef HarfbuzzSkia_h
+#define HarfbuzzSkia_h
-namespace WebCore {
+extern "C" {
+#include "harfbuzz-shaper.h"
+#include "harfbuzz-unicode.h"
+}
-class ImageSourceSkia : public ImageSource {
-public:
- // FIXME: This class is a hack to support Chromium's ICO decoder
- // Currently our ICO decoder decodes all data during setData() instead of
- // being lazy. In addition, it only decodes one frame (closest to the size
- // passed to the decoder during createDecoder, called from setData) and
- // discards all other data in the file.
- //
- // To fix this will require fixing the ICO decoder to be lazy, or to decode
- // all frames. Apple's decoders (ImageIO) decode all frames, and return
- // them all sorted in decreasing size. WebCore always draws the first frame.
- //
- // This is a special-purpose routine for the favicon decoder, which is used
- // to specify a particular icon size for the ICOImageDecoder to prefer
- // decoding. Note that not all favicons are ICOs, so this won't
- // necessarily do anything differently than ImageSource::setData().
- //
- // Passing an empty IntSize for |preferredIconSize| here is exactly
- // equivalent to just calling ImageSource::setData(). See also comments in
- // ICOImageDecoder.cpp.
- void setData(SharedBuffer* data,
- bool allDataReceived,
- const IntSize& preferredIconSize);
-};
+namespace WebCore {
+ HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+ extern const HB_FontClass harfbuzzSkiaClass;
+} // namespace WebCore
-}
+#endif
diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
index 6f5ce90..3d68ea8 100644
--- a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
@@ -63,7 +63,7 @@ void SimpleFontData::platformInit()
// FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401.
if (!GetTextMetrics(dc, &textMetric))
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the text metrics after second attempt");
}
}
@@ -141,7 +141,7 @@ void SimpleFontData::determinePitch()
// FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401.
if (!GetTextMetrics(dc, &textMetric))
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the text metrics after second attempt");
}
}
@@ -163,7 +163,7 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
// FIXME: Handle gracefully the error if this call also fails.
// See http://crbug.com/6401.
if (!GetCharWidthI(dc, glyph, 1, 0, &width))
- ASSERT_NOT_REACHED();
+ LOG_ERROR("Unable to get the char width after second attempt");
}
}
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
index d3ced81..7957d5a 100644
--- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp
@@ -109,7 +109,7 @@ class TransparencyWin::OwnedBuffers {
public:
OwnedBuffers(const IntSize& size, bool needReferenceBuffer)
{
- m_destBitmap = ImageBuffer::create(size, false);
+ m_destBitmap = ImageBuffer::create(size);
if (needReferenceBuffer) {
m_referenceBitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
@@ -152,6 +152,7 @@ TransparencyWin::TransparencyWin()
, m_savedOnDrawContext(false)
, m_layerBuffer(0)
, m_referenceBitmap(0)
+ , m_validLayer(false)
{
}
@@ -237,11 +238,14 @@ void TransparencyWin::setupLayer()
void TransparencyWin::setupLayerForNoLayer()
{
m_drawContext = m_destContext; // Draw to the source context.
+ m_validLayer = true;
}
void TransparencyWin::setupLayerForOpaqueCompositeLayer()
{
initializeNewContext();
+ if (!m_validLayer)
+ return;
TransformationMatrix mapping;
mapping.translate(-m_transformedSourceRect.x(), -m_transformedSourceRect.y());
@@ -268,6 +272,9 @@ void TransparencyWin::setupLayerForTextComposite()
void TransparencyWin::setupLayerForWhiteLayer()
{
initializeNewContext();
+ if (!m_validLayer)
+ return;
+
m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white);
// Layer rect represents the part of the original layer.
}
@@ -289,6 +296,9 @@ void TransparencyWin::setupTransform(const IntRect& region)
void TransparencyWin::setupTransformForKeepTransform(const IntRect& region)
{
+ if (!m_validLayer)
+ return;
+
if (m_layerMode != NoLayer) {
// Need to save things since we're modifying the transform.
m_drawContext->save();
@@ -319,6 +329,9 @@ void TransparencyWin::setupTransformForUntransform()
void TransparencyWin::setupTransformForScaleTransform()
{
+ if (!m_validLayer)
+ return;
+
if (m_layerMode == NoLayer) {
// Need to save things since we're modifying the layer.
m_drawContext->save();
@@ -345,16 +358,22 @@ void TransparencyWin::setTextCompositeColor(Color color)
void TransparencyWin::initializeNewContext()
{
int pixelSize = m_layerSize.width() * m_layerSize.height();
+ if (pixelSize <= 0)
+ return;
+
if (pixelSize > maxCachedBufferPixelSize) {
// Create a 1-off buffer for drawing into. We only need the reference
// buffer if we're making an OpaqueCompositeLayer.
bool needReferenceBitmap = m_layerMode == OpaqueCompositeLayer;
m_ownedBuffers.set(new OwnedBuffers(m_layerSize, needReferenceBitmap));
-
m_layerBuffer = m_ownedBuffers->destBitmap();
+ if (!m_layerBuffer)
+ return;
+
m_drawContext = m_layerBuffer->context();
if (needReferenceBitmap)
m_referenceBitmap = m_ownedBuffers->referenceBitmap();
+ m_validLayer = true;
return;
}
@@ -366,6 +385,7 @@ void TransparencyWin::initializeNewContext()
bitmapForContext(*m_drawContext).eraseARGB(0, 0, 0, 0);
m_referenceBitmap = m_cachedBuffers->referenceBitmap();
m_referenceBitmap->eraseARGB(0, 0, 0, 0);
+ m_validLayer = true;
return;
}
@@ -377,10 +397,14 @@ void TransparencyWin::initializeNewContext()
m_layerBuffer = m_cachedBuffers->destBitmap();
m_drawContext = m_cachedBuffers->destBitmap()->context();
m_referenceBitmap = m_cachedBuffers->referenceBitmap();
+ m_validLayer = true;
}
void TransparencyWin::compositeOpaqueComposite()
{
+ if (!m_validLayer)
+ return;
+
SkCanvas* destCanvas = canvasForContext(*m_destContext);
destCanvas->save();
@@ -436,6 +460,9 @@ void TransparencyWin::compositeOpaqueComposite()
void TransparencyWin::compositeTextComposite()
{
+ if (!m_validLayer)
+ return;
+
const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopPlatformDevice().accessBitmap(true);
SkColor textColor = m_textCompositeColor.rgb();
for (int y = 0; y < m_layerSize.height(); y++) {
@@ -451,6 +478,7 @@ void TransparencyWin::compositeTextComposite()
// Now the layer has text with the proper color and opacity.
SkCanvas* destCanvas = canvasForContext(*m_destContext);
+ destCanvas->save();
// We want to use Untransformed space (see above)
SkMatrix identity;
@@ -467,6 +495,9 @@ void TransparencyWin::compositeTextComposite()
void TransparencyWin::makeLayerOpaque()
{
+ if (!m_validLayer)
+ return;
+
SkBitmap& bitmap = const_cast<SkBitmap&>(m_drawContext->platformContext()->
canvas()->getTopPlatformDevice().accessBitmap(true));
for (int y = 0; y < m_layerSize.height(); y++) {
@@ -477,4 +508,3 @@ void TransparencyWin::makeLayerOpaque()
}
} // namespace WebCore
-
diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.h b/WebCore/platform/graphics/chromium/TransparencyWin.h
index e1963b3..ab75375 100644
--- a/WebCore/platform/graphics/chromium/TransparencyWin.h
+++ b/WebCore/platform/graphics/chromium/TransparencyWin.h
@@ -135,13 +135,16 @@ public:
const IntRect& region);
// Combines the source and destination bitmaps using the given mode.
+ // Calling this function before the destructor runs is mandatory in most
+ // cases, and harmless otherwise. The mandatory cases are:
+ // (m_layerMode != NoLayer) || (m_transformMode == ScaleTransform)
void composite();
// Returns the context for drawing into, which may be the destination
// context, or a temporary one.
GraphicsContext* context() const { return m_drawContext; }
- PlatformGraphicsContext* platformContext() const { return m_drawContext->platformContext(); }
+ PlatformGraphicsContext* platformContext() const { return m_drawContext ? m_drawContext->platformContext() : 0; }
// When the mode is TextComposite, this sets the color that the text will
// get. See the enum above for more.
@@ -245,6 +248,12 @@ private:
// m_layerBuffer, which will either point to this object, or the statically
// cached one. Don't access directly.
OwnPtr<OwnedBuffers> m_ownedBuffers;
+
+ // Sometimes we're asked to create layers that have negative dimensions.
+ // This API is not designed to fail to initialize, so we hide the fact
+ // that they are illegal and can't be rendered (failing silently, drawing
+ // nothing).
+ bool m_validLayer;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h
index dec04ac..b09cd72 100644
--- a/WebCore/platform/graphics/filters/FEBlend.h
+++ b/WebCore/platform/graphics/filters/FEBlend.h
@@ -47,7 +47,8 @@ namespace WebCore {
BlendModeType blendMode() const;
void setBlendMode(BlendModeType);
-
+
+ virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get(), m_in2.get()); }
void apply(Filter*);
void dump();
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
index 8704e64..fb0a194 100644
--- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
@@ -2,6 +2,7 @@
Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
2004, 2005 Rob Buis <buis@kde.org>
2005 Eric Seidel <eric@webkit.org>
+ 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -24,7 +25,11 @@
#if ENABLE(FILTERS)
#include "FEColorMatrix.h"
+#include "CanvasPixelArray.h"
#include "Filter.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include <math.h>
namespace WebCore {
@@ -61,8 +66,127 @@ void FEColorMatrix::setValues(const Vector<float> &values)
m_values = values;
}
-void FEColorMatrix::apply(Filter*)
+inline void matrix(double& red, double& green, double& blue, double& alpha, const Vector<float>& values)
{
+ double r = values[0] * red + values[1] * green + values[2] * blue + values[3] * alpha;
+ double g = values[5] * red + values[6] * green + values[7] * blue + values[8] * alpha;
+ double b = values[10] * red + values[11] * green + values[12] * blue + values[13] * alpha;
+ double a = values[15] * red + values[16] * green + values[17] * blue + values[18] * alpha;
+
+ red = r;
+ green = g;
+ blue = b;
+ alpha = a;
+}
+
+inline void saturate(double& red, double& green, double& blue, const float& s)
+{
+ double r = (0.213 + 0.787 * s) * red + (0.715 - 0.715 * s) * green + (0.072 - 0.072 * s) * blue;
+ double g = (0.213 - 0.213 * s) * red + (0.715 + 0.285 * s) * green + (0.072 - 0.072 * s) * blue;
+ double b = (0.213 - 0.213 * s) * red + (0.715 - 0.715 * s) * green + (0.072 + 0.928 * s) * blue;
+
+ red = r;
+ green = g;
+ blue = b;
+}
+
+inline void huerotate(double& red, double& green, double& blue, const float& hue)
+{
+ double cosHue = cos(hue * M_PI / 180);
+ double sinHue = sin(hue * M_PI / 180);
+ double r = red * (0.213 + cosHue * 0.787 - sinHue * 0.213) +
+ green * (0.715 - cosHue * 0.715 - sinHue * 0.715) +
+ blue * (0.072 - cosHue * 0.072 + sinHue * 0.928);
+ double g = red * (0.213 - cosHue * 0.213 + sinHue * 0.143) +
+ green * (0.715 + cosHue * 0.285 + sinHue * 0.140) +
+ blue * (0.072 - cosHue * 0.072 - sinHue * 0.283);
+ double b = red * (0.213 - cosHue * 0.213 - sinHue * 0.787) +
+ green * (0.715 - cosHue * 0.715 + sinHue * 0.715) +
+ blue * (0.072 + cosHue * 0.928 + sinHue * 0.072);
+
+ red = r;
+ green = g;
+ blue = b;
+}
+
+inline void luminance(double& red, double& green, double& blue, double& alpha)
+{
+ alpha = 0.2125 * red + 0.7154 * green + 0.0721 * blue;
+ red = 0.;
+ green = 0.;
+ blue = 0.;
+}
+
+template<ColorMatrixType filterType>
+void effectType(const PassRefPtr<CanvasPixelArray>& srcPixelArray, PassRefPtr<ImageData>& imageData, const Vector<float>& values)
+{
+ for (unsigned pixelOffset = 0; pixelOffset < srcPixelArray->length(); pixelOffset++) {
+ unsigned pixelByteOffset = pixelOffset * 4;
+
+ unsigned char r = 0, g = 0, b = 0, a = 0;
+ srcPixelArray->get(pixelByteOffset, r);
+ srcPixelArray->get(pixelByteOffset + 1, g);
+ srcPixelArray->get(pixelByteOffset + 2, b);
+ srcPixelArray->get(pixelByteOffset + 3, a);
+
+ double red = r, green = g, blue = b, alpha = a;
+
+ switch (filterType) {
+ case FECOLORMATRIX_TYPE_MATRIX:
+ matrix(red, green, blue, alpha, values);
+ break;
+ case FECOLORMATRIX_TYPE_SATURATE:
+ saturate(red, green, blue, values[0]);
+ break;
+ case FECOLORMATRIX_TYPE_HUEROTATE:
+ huerotate(red, green, blue, values[0]);
+ break;
+ case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
+ luminance(red, green, blue, alpha);
+ break;
+ }
+
+ imageData->data()->set(pixelByteOffset, red);
+ imageData->data()->set(pixelByteOffset + 1, green);
+ imageData->data()->set(pixelByteOffset + 2, blue);
+ imageData->data()->set(pixelByteOffset + 3, alpha);
+ }
+}
+
+void FEColorMatrix::apply(Filter* filter)
+{
+ m_in->apply(filter);
+ if (!m_in->resultImage())
+ return;
+
+ GraphicsContext* filterContext = getEffectContext();
+ if (!filterContext)
+ return;
+
+ filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()));
+
+ IntRect imageRect(IntPoint(), resultImage()->size());
+ PassRefPtr<ImageData> imageData(resultImage()->getImageData(imageRect));
+ PassRefPtr<CanvasPixelArray> srcPixelArray(imageData->data());
+
+ switch (m_type) {
+ case FECOLORMATRIX_TYPE_UNKNOWN:
+ break;
+ case FECOLORMATRIX_TYPE_MATRIX:
+ effectType<FECOLORMATRIX_TYPE_MATRIX>(srcPixelArray, imageData, m_values);
+ break;
+ case FECOLORMATRIX_TYPE_SATURATE:
+ effectType<FECOLORMATRIX_TYPE_SATURATE>(srcPixelArray, imageData, m_values);
+ break;
+ case FECOLORMATRIX_TYPE_HUEROTATE:
+ effectType<FECOLORMATRIX_TYPE_HUEROTATE>(srcPixelArray, imageData, m_values);
+ break;
+ case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
+ effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(srcPixelArray, imageData, m_values);
+ break;
+ }
+
+ resultImage()->putImageData(imageData.get(), imageRect, IntPoint());
}
void FEColorMatrix::dump()
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.h b/WebCore/platform/graphics/filters/FEColorMatrix.h
index eeb3557..106b2fa 100644
--- a/WebCore/platform/graphics/filters/FEColorMatrix.h
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.h
@@ -47,7 +47,8 @@ namespace WebCore {
const Vector<float>& values() const;
void setValues(const Vector<float>&);
-
+
+ virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); }
void apply(Filter*);
void dump();
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.h b/WebCore/platform/graphics/filters/FEComponentTransfer.h
index cc1d1f8..773aba7 100644
--- a/WebCore/platform/graphics/filters/FEComponentTransfer.h
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.h
@@ -78,7 +78,8 @@ namespace WebCore {
ComponentTransferFunction alphaFunction() const;
void setAlphaFunction(const ComponentTransferFunction&);
-
+
+ virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); }
void apply(Filter*);
void dump();
diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h
index b623cce..ad096f2 100644
--- a/WebCore/platform/graphics/filters/FEComposite.h
+++ b/WebCore/platform/graphics/filters/FEComposite.h
@@ -59,7 +59,8 @@ namespace WebCore {
float k4() const;
void setK4(float);
-
+
+ virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get(), m_in2.get()); }
void apply(Filter*);
void dump();
diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h
index 84909da..ee97afc 100644
--- a/WebCore/platform/graphics/filters/Filter.h
+++ b/WebCore/platform/graphics/filters/Filter.h
@@ -21,7 +21,8 @@
#define Filter_h
#if ENABLE(FILTERS)
-#include "Image.h"
+#include "FloatRect.h"
+#include "ImageBuffer.h"
#include "StringHash.h"
#include <wtf/PassRefPtr.h>
@@ -36,13 +37,18 @@ namespace WebCore {
public:
virtual ~Filter() { }
- void setSourceImage(PassRefPtr<Image> image) { m_image = image; }
- Image* sourceImage() { return m_image.get(); }
+ void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; }
+ ImageBuffer* sourceImage() { return m_sourceImage.get(); }
+ virtual FloatRect sourceImageRect() = 0;
+ virtual FloatRect filterRegion() = 0;
+
+ // SVG specific
virtual void calculateEffectSubRegion(FilterEffect*) = 0;
+ virtual bool effectBoundingBoxMode() = 0;
private:
- RefPtr<Image> m_image;
+ OwnPtr<ImageBuffer> m_sourceImage;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp
index cd74992..41e8a39 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.cpp
+++ b/WebCore/platform/graphics/filters/FilterEffect.cpp
@@ -29,6 +29,10 @@ FilterEffect::FilterEffect()
, m_yBBoxMode(false)
, m_widthBBoxMode(false)
, m_heightBBoxMode(false)
+ , m_hasX(false)
+ , m_hasY(false)
+ , m_hasWidth(false)
+ , m_hasHeight(false)
{
}
@@ -36,6 +40,39 @@ FilterEffect::~FilterEffect()
{
}
+FloatRect FilterEffect::calculateUnionOfChildEffectSubregions(Filter* filter, FilterEffect* in)
+{
+ return in->calculateEffectRect(filter);
+}
+
+FloatRect FilterEffect::calculateUnionOfChildEffectSubregions(Filter* filter, FilterEffect* in, FilterEffect* in2)
+{
+ FloatRect uniteEffectRect = in->calculateEffectRect(filter);
+ uniteEffectRect.unite(in2->calculateEffectRect(filter));
+ return uniteEffectRect;
+}
+
+FloatRect FilterEffect::calculateEffectRect(Filter* filter)
+{
+ setUnionOfChildEffectSubregions(uniteChildEffectSubregions(filter));
+ filter->calculateEffectSubRegion(this);
+ return subRegion();
+}
+
+FloatRect FilterEffect::calculateDrawingRect(const FloatRect& srcRect)
+{
+ FloatPoint startPoint = FloatPoint(srcRect.x() - subRegion().x(), srcRect.y() - subRegion().y());
+ FloatRect drawingRect = FloatRect(startPoint, srcRect.size());
+ return drawingRect;
+}
+
+GraphicsContext* FilterEffect::getEffectContext()
+{
+ IntRect bufferRect = enclosingIntRect(subRegion());
+ m_effectBuffer = ImageBuffer::create(bufferRect.size(), LinearRGB);
+ return m_effectBuffer->context();
+}
+
TextStream& FilterEffect::externalRepresentation(TextStream& ts) const
{
return ts;
diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h
index e2a058d..8dc6233 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.h
+++ b/WebCore/platform/graphics/filters/FilterEffect.h
@@ -24,9 +24,11 @@
#if ENABLE(FILTERS)
#include "Filter.h"
#include "FloatRect.h"
+#include "GraphicsContext.h"
#include "ImageBuffer.h"
#include "TextStream.h"
+#include <wtf/PassOwnPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
@@ -48,16 +50,41 @@ namespace WebCore {
bool heightBoundingBoxMode() const { return m_heightBBoxMode; }
void setHeightBoundingBoxMode(bool bboxMode) { m_heightBBoxMode = bboxMode; }
+ void setUnionOfChildEffectSubregions(const FloatRect& uniteRect) { m_unionOfChildEffectSubregions = uniteRect; }
+ FloatRect unionOfChildEffectSubregions() const { return m_unionOfChildEffectSubregions; }
+
FloatRect subRegion() const { return m_subRegion; }
void setSubRegion(const FloatRect& subRegion) { m_subRegion = subRegion; }
+ bool hasX() { return m_hasX; }
+ void setHasX(bool value) { m_hasX = value; }
+
+ bool hasY() { return m_hasY; }
+ void setHasY(bool value) { m_hasY = value; }
+
+ bool hasWidth() { return m_hasWidth; }
+ void setHasWidth(bool value) { m_hasWidth = value; }
+
+ bool hasHeight() { return m_hasHeight; }
+ void setHasHeight(bool value) { m_hasHeight = value; }
+
// The result is bounded by the size of the filter primitive to save resources
ImageBuffer* resultImage() { return m_effectBuffer.get(); }
- void setEffectBuffer(ImageBuffer* effectBuffer) { m_effectBuffer.set(effectBuffer); }
+ void setEffectBuffer(PassOwnPtr<ImageBuffer> effectBuffer) { m_effectBuffer = effectBuffer; }
+ FloatRect calculateUnionOfChildEffectSubregions(Filter*, FilterEffect*, FilterEffect*);
+ FloatRect calculateUnionOfChildEffectSubregions(Filter*, FilterEffect*);
+
+ GraphicsContext* getEffectContext();
+ FloatRect calculateDrawingRect(const FloatRect&);
+
+ virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return filter->filterRegion(); }
+ virtual FloatRect calculateEffectRect(Filter*);
virtual void apply(Filter*) = 0;
virtual void dump() = 0;
+ virtual bool isSourceInput() { return false; }
+
virtual TextStream& externalRepresentation(TextStream&) const;
protected:
FilterEffect();
@@ -69,7 +96,13 @@ namespace WebCore {
bool m_widthBBoxMode : 1;
bool m_heightBBoxMode : 1;
+ bool m_hasX : 1;
+ bool m_hasY : 1;
+ bool m_hasWidth : 1;
+ bool m_hasHeight : 1;
+
FloatRect m_subRegion;
+ FloatRect m_unionOfChildEffectSubregions;
mutable OwnPtr<ImageBuffer> m_effectBuffer;
};
diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h
index 21497aa..5341562 100644
--- a/WebCore/platform/graphics/filters/SourceAlpha.h
+++ b/WebCore/platform/graphics/filters/SourceAlpha.h
@@ -34,6 +34,8 @@ namespace WebCore {
static const AtomicString& effectName();
+ virtual bool isSourceInput() { return true; }
+ virtual FloatRect calculateEffectRect(Filter* filter) { return filter->sourceImageRect(); }
void apply(Filter*);
void dump();
diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp
index 39d4810..023eeac 100644
--- a/WebCore/platform/graphics/filters/SourceGraphic.cpp
+++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp
@@ -41,8 +41,24 @@ const AtomicString& SourceGraphic::effectName()
return s_effectName;
}
-void SourceGraphic::apply(Filter*)
+FloatRect SourceGraphic::calculateEffectRect(Filter* filter)
{
+ FloatRect clippedSourceRect = filter->sourceImageRect();
+ if (filter->sourceImageRect().x() < filter->filterRegion().x())
+ clippedSourceRect.setX(filter->filterRegion().x());
+ if (filter->sourceImageRect().y() < filter->filterRegion().y())
+ clippedSourceRect.setY(filter->filterRegion().y());
+ setSubRegion(clippedSourceRect);
+ return filter->filterRegion();
+}
+
+void SourceGraphic::apply(Filter* filter)
+{
+ GraphicsContext* filterContext = getEffectContext();
+ if (!filterContext)
+ return;
+
+ filterContext->drawImage(filter->sourceImage()->image(), IntPoint());
}
void SourceGraphic::dump()
diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h
index 363fb97..0c8095e 100644
--- a/WebCore/platform/graphics/filters/SourceGraphic.h
+++ b/WebCore/platform/graphics/filters/SourceGraphic.h
@@ -24,8 +24,8 @@
#if ENABLE(FILTERS)
#include "FilterEffect.h"
-#include "PlatformString.h"
#include "Filter.h"
+#include "PlatformString.h"
namespace WebCore {
@@ -35,6 +35,8 @@ namespace WebCore {
static const AtomicString& effectName();
+ virtual bool isSourceInput() { return true; }
+ virtual FloatRect calculateEffectRect(Filter*);
void apply(Filter*);
void dump();
diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp
index 6561f02..ee86f96 100644
--- a/WebCore/platform/graphics/gtk/FontGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontGtk.cpp
@@ -44,12 +44,6 @@
#include <pango/pangofc-fontmap.h>
#endif
-#if !defined(PANGO_VERSION_CHECK)
-// PANGO_VERSION_CHECK() and pango_layout_get_line_readonly() appeared in 1.5.2
-#define pango_layout_get_line_readonly pango_layout_get_line
-#define PANGO_VERSION_CHECK(major,minor,micro) 0
-#endif
-
namespace WebCore {
#define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h
index ae1f134..2a65f1e 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformData.h
+++ b/WebCore/platform/graphics/gtk/FontPlatformData.h
@@ -42,6 +42,8 @@
namespace WebCore {
+class String;
+
class FontPlatformData {
public:
FontPlatformData(WTF::HashTableDeletedValueType)
@@ -107,6 +109,10 @@ public:
#endif
};
+#ifndef NDEBUG
+ String description() const;
+#endif
+
#if defined(USE_FREETYPE)
FcPattern* m_pattern;
FcFontSet* m_fallbacks;
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
index f0f0dd5..f2c5f0c 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
@@ -259,4 +259,11 @@ bool FontPlatformData::operator==(const FontPlatformData& other) const
return FcPatternEqual(m_pattern, other.m_pattern);
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
}
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
index 88bf427..9ea6811 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
@@ -34,10 +34,6 @@
#include <pango/pango.h>
#include <pango/pangocairo.h>
-#if !defined(PANGO_VERSION_CHECK)
-#define PANGO_VERSION_CHECK(major,minor,micro) 0
-#endif
-
// Use cairo-ft i a recent enough Pango version isn't available
#if !PANGO_VERSION_CHECK(1,18,0)
#include <cairo-ft.h>
@@ -113,14 +109,14 @@ FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const
cairo_font_face_t* face = cairo_ft_font_face_create_for_pattern(fcfont->font_pattern);
double size;
if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
- size = 12.0;
+ size = 12.0;
cairo_matrix_t fontMatrix;
cairo_matrix_init_scale(&fontMatrix, size, size);
cairo_font_options_t* fontOptions;
if (pango_cairo_context_get_font_options(m_context))
- fontOptions = cairo_font_options_copy(pango_cairo_context_get_font_options(m_context));
+ fontOptions = cairo_font_options_copy(pango_cairo_context_get_font_options(m_context));
else
- fontOptions = cairo_font_options_create();
+ fontOptions = cairo_font_options_create();
cairo_matrix_t ctm;
cairo_matrix_init_identity(&ctm);
m_scaledFont = cairo_scaled_font_create(face, &fontMatrix, &ctm, fontOptions);
@@ -279,4 +275,11 @@ bool FontPlatformData::operator==(const FontPlatformData& other) const
return result;
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
}
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index 8dd1333..4e4bda9 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -24,7 +24,6 @@
#if ENABLE(VIDEO)
#include "MediaPlayerPrivateGStreamer.h"
-#include "VideoSinkGStreamer.h"
#include "CString.h"
#include "GraphicsContext.h"
@@ -34,10 +33,9 @@
#include "MediaPlayer.h"
#include "NotImplemented.h"
#include "ScrollView.h"
+#include "VideoSinkGStreamer.h"
#include "Widget.h"
-#include <wtf/GOwnPtr.h>
-#include <gdk/gdkx.h>
#include <gst/base/gstbasesrc.h>
#include <gst/gst.h>
#include <gst/interfaces/mixer.h>
@@ -45,6 +43,7 @@
#include <gst/video/video.h>
#include <limits>
#include <math.h>
+#include <wtf/GOwnPtr.h>
using namespace std;
@@ -52,8 +51,7 @@ namespace WebCore {
gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data)
{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR)
- {
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) {
GOwnPtr<GError> err;
GOwnPtr<gchar> debug;
@@ -71,8 +69,7 @@ gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpoin
gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data)
{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS)
- {
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) {
LOG_VERBOSE(Media, "End of Stream");
MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
mp->didEnd();
@@ -82,8 +79,7 @@ gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointe
gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data)
{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED)
- {
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) {
MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
mp->updateStates();
}
@@ -92,8 +88,7 @@ gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpoin
gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data)
{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING)
- {
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING) {
gint percent = 0;
gst_message_parse_buffering(message, &percent);
LOG_VERBOSE(Media, "Buffering %d", percent);
@@ -106,8 +101,8 @@ static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, MediaPlayerPriva
playerPrivate->repaint();
}
-MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
-{
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
return new MediaPlayerPrivate(player);
}
@@ -137,7 +132,7 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
static bool gstInitialized = false;
// FIXME: We should pass the arguments from the command line
if (!gstInitialized) {
- gst_init(0, NULL);
+ gst_init(0, 0);
gstInitialized = true;
}
@@ -229,7 +224,7 @@ float MediaPlayerPrivate::currentTime() const
GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
if (gst_element_query(m_playBin, query)) {
gint64 position;
- gst_query_parse_position(query, NULL, &position);
+ gst_query_parse_position(query, 0, &position);
ret = (float) (position / 1000000000.0);
LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
} else {
@@ -277,7 +272,7 @@ void MediaPlayerPrivate::setEndTime(float time)
GST_FORMAT_TIME,
(GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
GST_SEEK_TYPE_SET, start,
- GST_SEEK_TYPE_SET, end ))
+ GST_SEEK_TYPE_SET, end))
LOG_VERBOSE(Media, "Seek to %f failed", time);
}
}
@@ -345,9 +340,9 @@ void MediaPlayerPrivate::setMuted(bool b)
if (b) {
g_object_get(G_OBJECT(m_playBin), "volume", &m_volume, NULL);
g_object_set(G_OBJECT(m_playBin), "volume", (double)0.0, NULL);
- } else {
+ } else
g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL);
- }
+
}
void MediaPlayerPrivate::setRate(float rate)
@@ -465,10 +460,10 @@ void MediaPlayerPrivate::updateStates()
if (!m_playBin)
return;
- GstStateChangeReturn ret = gst_element_get_state (m_playBin,
+ GstStateChangeReturn ret = gst_element_get_state(m_playBin,
&state, &pending, 250 * GST_NSECOND);
- switch(ret) {
+ switch (ret) {
case GST_STATE_CHANGE_SUCCESS:
LOG_VERBOSE(Media, "State: %s, pending: %s",
gst_element_state_get_name(state),
@@ -476,14 +471,14 @@ void MediaPlayerPrivate::updateStates()
if (state == GST_STATE_READY) {
m_readyState = MediaPlayer::HaveEnoughData;
- } else if (state == GST_STATE_PAUSED) {
+ } else if (state == GST_STATE_PAUSED)
m_readyState = MediaPlayer::HaveEnoughData;
- }
+
m_networkState = MediaPlayer::Loaded;
g_object_get(m_playBin, "source", &m_source, NULL);
if (!m_source)
- LOG_VERBOSE(Media, "m_source is NULL");
+ LOG_VERBOSE(Media, "m_source is 0");
break;
case GST_STATE_CHANGE_ASYNC:
LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
@@ -498,9 +493,9 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(pending));
if (state == GST_STATE_READY) {
m_readyState = MediaPlayer::HaveFutureData;
- } else if (state == GST_STATE_PAUSED) {
+ } else if (state == GST_STATE_PAUSED)
m_readyState = MediaPlayer::HaveCurrentData;
- }
+
m_networkState = MediaPlayer::Loading;
break;
default:
@@ -614,7 +609,7 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c
{
// FIXME: query the engine to see what types are supported
notImplemented();
- return type == "video/x-theora+ogg" ? (!codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+ return type == "video/x-theora+ogg" ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
}
void MediaPlayerPrivate::createGSTPlayBin(String url)
@@ -632,7 +627,7 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL);
- GstElement* audioSink = gst_element_factory_make("gconfaudiosink", NULL);
+ GstElement* audioSink = gst_element_factory_make("gconfaudiosink", 0);
m_videoSink = webkit_video_sink_new(m_surface);
g_object_set(m_playBin, "audio-sink", audioSink, NULL);
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
index 628f0ac..8842f84 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -27,7 +27,8 @@
#include "MediaPlayerPrivate.h"
#include "Timer.h"
-#include <gtk/gtk.h>
+#include <cairo.h>
+#include <glib.h>
typedef struct _GstElement GstElement;
typedef struct _GstMessage GstMessage;
@@ -44,96 +45,93 @@ namespace WebCore {
gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
- class MediaPlayerPrivate : public MediaPlayerPrivateInterface
- {
- friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
- friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
- friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
-
- 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);
- void setEndTime(float);
-
- void setRate(float);
- void setVolume(float);
- void setMuted(bool);
-
- int dataRate() const;
-
- MediaPlayer::NetworkState networkState() const;
- MediaPlayer::ReadyState readyState() const;
-
- float maxTimeBuffered() const;
- float maxTimeSeekable() const;
- unsigned bytesLoaded() const;
- bool totalBytesKnown() const;
- unsigned totalBytes() const;
-
- void setVisible(bool);
- void setSize(const IntSize&);
-
- void loadStateChanged();
- void rateChanged();
- void sizeChanged();
- void timeChanged();
- void volumeChanged();
- void didEnd();
- void loadingFailed();
-
- void repaint();
- void paint(GraphicsContext*, const IntRect&);
-
- private:
-
- MediaPlayerPrivate(MediaPlayer*);
- static MediaPlayerPrivateInterface* create(MediaPlayer* player);
-
- static void getSupportedTypes(HashSet<String>&);
- static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
- static bool isAvailable() { return true; }
-
- void updateStates();
- void cancelSeek();
- void endPointTimerFired(Timer<MediaPlayerPrivate>*);
- float maxTimeLoaded() const;
- void startEndPointTimerIfNeeded();
-
- void createGSTPlayBin(String url);
-
- private:
- MediaPlayer* m_player;
- GstElement* m_playBin;
- GstElement* m_videoSink;
- GstElement* m_source;
- float m_rate;
- float m_endTime;
- bool m_isEndReached;
- double m_volume;
- MediaPlayer::NetworkState m_networkState;
- MediaPlayer::ReadyState m_readyState;
- bool m_startedPlaying;
- mutable bool m_isStreaming;
- IntSize m_size;
- bool m_visible;
- cairo_surface_t* m_surface;
+ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
+ friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
+ friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
+ friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
+
+ 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);
+ void setEndTime(float);
+
+ void setRate(float);
+ void setVolume(float);
+ void setMuted(bool);
+
+ int dataRate() const;
+
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
+
+ float maxTimeBuffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ bool totalBytesKnown() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setSize(const IntSize&);
+
+ void loadStateChanged();
+ void rateChanged();
+ void sizeChanged();
+ void timeChanged();
+ void volumeChanged();
+ void didEnd();
+ void loadingFailed();
+
+ void repaint();
+ void paint(GraphicsContext*, const IntRect&);
+
+ private:
+ MediaPlayerPrivate(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static bool isAvailable() { return true; }
+
+ void updateStates();
+ void cancelSeek();
+ void endPointTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded() const;
+ void startEndPointTimerIfNeeded();
+
+ void createGSTPlayBin(String url);
+
+ private:
+ MediaPlayer* m_player;
+ GstElement* m_playBin;
+ GstElement* m_videoSink;
+ GstElement* m_source;
+ float m_rate;
+ float m_endTime;
+ bool m_isEndReached;
+ double m_volume;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ bool m_startedPlaying;
+ mutable bool m_isStreaming;
+ IntSize m_size;
+ bool m_visible;
+ cairo_surface_t* m_surface;
};
}
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
index 6684108..a77c1cf 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
@@ -99,7 +99,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con
if (!face)
return false;
- for (unsigned i = 0; i < length; i++) {
+ for (int i = 0; i < length; i++) {
if (FcFreeTypeCharIndex(face, characters[i]) == 0) {
cairo_ft_scaled_font_unlock_face(m_platformData.m_scaledFont);
return false;
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
index 436841c..f049998 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
@@ -40,10 +40,10 @@ GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug);
#define GST_CAT_DEFAULT webkit_video_sink_debug
static GstElementDetails webkit_video_sink_details =
- GST_ELEMENT_DETAILS((gchar*) "WebKit video sink",
- (gchar*) "Sink/Video",
- (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface",
- (gchar*) "Alp Toker <alp@atoker.com>");
+ GST_ELEMENT_DETAILS((gchar*) "WebKit video sink",
+ (gchar*) "Sink/Video",
+ (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface",
+ (gchar*) "Alp Toker <alp@atoker.com>");
enum {
REPAINT_REQUESTED,
@@ -70,10 +70,10 @@ struct _WebKitVideoSinkPrivate {
};
#define _do_init(bla) \
- GST_DEBUG_CATEGORY_INIT (webkit_video_sink_debug, \
- "webkitsink", \
- 0, \
- "webkit video sink")
+ GST_DEBUG_CATEGORY_INIT(webkit_video_sink_debug, \
+ "webkitsink", \
+ 0, \
+ "webkit video sink")
GST_BOILERPLATE_FULL(WebKitVideoSink,
webkit_video_sink,
@@ -110,11 +110,11 @@ webkit_video_sink_idle_func(gpointer data)
return FALSE;
buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue);
- if (buffer == NULL || G_UNLIKELY(!GST_IS_BUFFER(buffer)))
+ if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer)))
return FALSE;
// TODO: consider priv->rgb_ordering?
- cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~ 3);
+ cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~3);
// TODO: We copy the data twice right now. This could be easily improved.
cairo_t* cr = cairo_create(priv->surface);
@@ -139,7 +139,7 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
WebKitVideoSinkPrivate* priv = sink->priv;
g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer));
- g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, NULL);
+ g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, 0);
return GST_FLOW_OK;
}
@@ -168,7 +168,7 @@ webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps)
ret = gst_structure_get_int(structure, "width", &width);
ret &= gst_structure_get_int(structure, "height", &height);
fps = gst_structure_get_value(structure, "framerate");
- ret &= (fps != NULL);
+ ret &= (fps != 0);
par = gst_structure_get_value(structure, "pixel-aspect-ratio");
@@ -202,12 +202,12 @@ webkit_video_sink_dispose(GObject* object)
if (priv->surface) {
cairo_surface_destroy(priv->surface);
- priv->surface = NULL;
+ priv->surface = 0;
}
if (priv->async_queue) {
g_async_queue_unref(priv->async_queue);
- priv->async_queue = NULL;
+ priv->async_queue = 0;
}
G_OBJECT_CLASS(parent_class)->dispose(object);
@@ -260,7 +260,7 @@ webkit_video_sink_stop(GstBaseSink* base_sink)
g_async_queue_lock(priv->async_queue);
/* Remove all remaining objects from the queue */
- while(GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue))
+ while (GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue))
gst_buffer_unref(buffer);
g_async_queue_unlock(priv->async_queue);
@@ -291,8 +291,8 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
G_TYPE_FROM_CLASS(klass),
(GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
0,
- NULL,
- NULL,
+ 0,
+ 0,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -314,7 +314,7 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
GstElement*
webkit_video_sink_new(cairo_surface_t* surface)
{
- return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, NULL);
+ return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, 0);
}
void
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
index 2a706fb..be2c94c 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
@@ -29,54 +29,52 @@ G_BEGIN_DECLS
#define WEBKIT_TYPE_VIDEO_SINK webkit_video_sink_get_type()
#define WEBKIT_VIDEO_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
- WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSink))
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSink))
#define WEBKIT_VIDEO_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), \
- WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
#define WEBKIT_IS_VIDEO_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
- WEBKIT_TYPE_VIDEO_SINK))
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ WEBKIT_TYPE_VIDEO_SINK))
#define WEBKIT_IS_VIDEO_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), \
- WEBKIT_TYPE_VIDEO_SINK))
+ (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ WEBKIT_TYPE_VIDEO_SINK))
#define WEBKIT_VIDEO_SINK_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), \
- WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
+ (G_TYPE_INSTANCE_GET_CLASS((obj), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
typedef struct _WebKitVideoSink WebKitVideoSink;
typedef struct _WebKitVideoSinkClass WebKitVideoSinkClass;
typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate;
-struct _WebKitVideoSink
-{
- /*< private >*/
- GstBaseSink parent;
- WebKitVideoSinkPrivate *priv;
+struct _WebKitVideoSink {
+ /*< private >*/
+ GstBaseSink parent;
+ WebKitVideoSinkPrivate *priv;
};
-struct _WebKitVideoSinkClass
-{
- /*< private >*/
- GstBaseSinkClass parent_class;
-
- /* Future padding */
- void (* _webkit_reserved1) (void);
- void (* _webkit_reserved2) (void);
- void (* _webkit_reserved3) (void);
- void (* _webkit_reserved4) (void);
- void (* _webkit_reserved5) (void);
- void (* _webkit_reserved6) (void);
+struct _WebKitVideoSinkClass {
+ /*< private >*/
+ GstBaseSinkClass parent_class;
+
+ /* Future padding */
+ void (* _webkit_reserved1)(void);
+ void (* _webkit_reserved2)(void);
+ void (* _webkit_reserved3)(void);
+ void (* _webkit_reserved4)(void);
+ void (* _webkit_reserved5)(void);
+ void (* _webkit_reserved6)(void);
};
-GType webkit_video_sink_get_type (void) G_GNUC_CONST;
-GstElement *webkit_video_sink_new (cairo_surface_t *surface);
+GType webkit_video_sink_get_type(void) G_GNUC_CONST;
+GstElement *webkit_video_sink_new(cairo_surface_t *surface);
-void webkit_video_sink_set_surface (WebKitVideoSink *sink, cairo_surface_t *surface);
+void webkit_video_sink_set_surface(WebKitVideoSink *sink, cairo_surface_t *surface);
G_END_DECLS
diff --git a/WebCore/platform/graphics/mac/ColorMac.h b/WebCore/platform/graphics/mac/ColorMac.h
index 8a5ce31..b68b157 100644
--- a/WebCore/platform/graphics/mac/ColorMac.h
+++ b/WebCore/platform/graphics/mac/ColorMac.h
@@ -46,6 +46,9 @@ namespace WebCore {
bool usesTestModeFocusRingColor();
void setUsesTestModeFocusRingColor(bool);
+ // Focus ring color used for testing purposes.
+ RGBA32 oldAquaFocusRingColor();
+
}
#endif
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm
index 05dd78d..c8ea9b1 100644
--- a/WebCore/platform/graphics/mac/ColorMac.mm
+++ b/WebCore/platform/graphics/mac/ColorMac.mm
@@ -29,18 +29,26 @@
#import <wtf/RetainPtr.h>
#import <wtf/StdLibExtras.h>
-@interface WebCoreControlTintObserver : NSObject
-+ (void)controlTintDidChange;
-@end
-
namespace WebCore {
// NSColor calls don't throw, so no need to block Cocoa exceptions in this file
-static RGBA32 oldAquaFocusRingColor = 0xFF7DADD9;
-static RGBA32 systemFocusRingColor;
static bool useOldAquaFocusRingColor;
+RGBA32 oldAquaFocusRingColor()
+{
+ return 0xFF7DADD9;
+}
+
+void setUsesTestModeFocusRingColor(bool newValue)
+{
+ useOldAquaFocusRingColor = newValue;
+}
+
+bool usesTestModeFocusRingColor()
+{
+ return useOldAquaFocusRingColor;
+}
static RGBA32 makeRGBAFromNSColor(NSColor *c)
{
@@ -119,42 +127,4 @@ CGColorRef createCGColor(const Color& c)
return CGColorFromNSColor(nsColor(c));
}
-Color focusRingColor()
-{
- static bool tintIsKnown = false;
- if (!tintIsKnown) {
- [[NSNotificationCenter defaultCenter] addObserver:[WebCoreControlTintObserver class]
- selector:@selector(controlTintDidChange)
- name:NSControlTintDidChangeNotification
- object:NSApp];
- [WebCoreControlTintObserver controlTintDidChange];
- tintIsKnown = true;
- }
-
- if (usesTestModeFocusRingColor())
- return oldAquaFocusRingColor;
-
- return systemFocusRingColor;
-}
-
-bool usesTestModeFocusRingColor()
-{
- return useOldAquaFocusRingColor;
-}
-
-void setUsesTestModeFocusRingColor(bool newValue)
-{
- useOldAquaFocusRingColor = newValue;
-}
-
-}
-
-@implementation WebCoreControlTintObserver
-
-+ (void)controlTintDidChange
-{
- NSColor *color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
- WebCore::systemFocusRingColor = WebCore::makeRGBAFromNSColor(color);
-}
-
-@end
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h
index 1b7b884..faf5f2e 100644
--- a/WebCore/platform/graphics/mac/FontPlatformData.h
+++ b/WebCore/platform/graphics/mac/FontPlatformData.h
@@ -45,6 +45,8 @@ typedef UInt32 ATSUFontID;
namespace WebCore {
+class String;
+
#ifndef BUILDING_ON_TIGER
inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); }
#endif
@@ -118,6 +120,10 @@ struct FontPlatformData {
CGFontRef cgFont() const { return m_cgFont; }
#endif
+#ifndef NDEBUG
+ String description() const;
+#endif
+
private:
static NSFont *hashTableDeletedFontValue() { return reinterpret_cast<NSFont *>(-1); }
diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
index 83da4a9..0118c8b 100644
--- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
+++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
@@ -23,6 +23,7 @@
#import "config.h"
#import "FontPlatformData.h"
+#import "PlatformString.h"
#import "WebCoreSystemInterface.h"
#import <AppKit/NSFont.h>
@@ -107,4 +108,12 @@ bool FontPlatformData::allowsLigatures() const
return ![[m_font coveredCharacterSet] characterIsMember:'a'];
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ RetainPtr<CFStringRef> cgFontDescription(AdoptCF, CFCopyDescription(cgFont()));
+ return String(cgFontDescription.get()) + " " + String::number(m_size) + (m_syntheticBold ? " synthetic bold" : "") + (m_syntheticOblique ? " syntheitic oblique" : "");
+}
+#endif
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
index 50138d5..ebdc6ac 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
@@ -29,8 +29,15 @@
#if USE(ACCELERATED_COMPOSITING)
#include "GraphicsLayer.h"
+#include "StringHash.h"
+#include <wtf/HashSet.h>
#include <wtf/RetainPtr.h>
+@class CABasicAnimation;
+@class CAKeyframeAnimation;
+@class CALayer;
+@class CAMediaTimingFunction;
+@class CAPropertyAnimation;
@class WebAnimationDelegate;
@class WebLayer;
@@ -67,66 +74,192 @@ public:
virtual void setMasksToBounds(bool);
virtual void setDrawsContent(bool);
- virtual void setBackgroundColor(const Color&, const Animation* anim = 0, double beginTime = 0);
+ virtual void setBackgroundColor(const Color&);
virtual void clearBackgroundColor();
virtual void setContentsOpaque(bool);
virtual void setBackfaceVisibility(bool);
// return true if we started an animation
- virtual bool setOpacity(float, const Animation* anim = 0, double beginTime = 0);
+ virtual void setOpacity(float);
virtual void setNeedsDisplay();
virtual void setNeedsDisplayInRect(const FloatRect&);
- virtual void suspendAnimations();
+ virtual void setContentsRect(const IntRect&);
+
+ virtual void suspendAnimations(double time);
virtual void resumeAnimations();
- virtual bool animateTransform(const TransformValueList&, const IntSize&, const Animation*, double beginTime, bool isTransition);
- virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&, const Animation*, double beginTime);
-
+ virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double beginTime);
+ virtual void removeAnimationsForProperty(AnimatedPropertyID);
+ virtual void removeAnimationsForKeyframes(const String& keyframesName);
+ virtual void pauseAnimation(const String& keyframesName);
+
virtual void setContentsToImage(Image*);
virtual void setContentsToVideo(PlatformLayer*);
- virtual void clearContents();
- virtual void updateContentsRect();
-
virtual PlatformLayer* platformLayer() const;
#ifndef NDEBUG
virtual void setDebugBackgroundColor(const Color&);
virtual void setDebugBorder(const Color&, float borderWidth);
- virtual void setZPosition(float);
#endif
+ virtual void setGeometryOrientation(CompositingCoordinatesOrientation);
+
+ void recursiveCommitChanges();
+ void commitLayerChanges();
+
+ virtual void syncCompositingState();
+
+protected:
+ virtual void setOpacityInternal(float);
+
private:
- WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
+ void updateOpacityOnLayer();
+
+ WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); }
WebLayer* hostLayerForSublayers() const;
WebLayer* layerForSuperlayer() const;
+ CALayer* animatedLayer(AnimatedPropertyID property) const;
- WebLayer* animatedLayer(AnimatedPropertyID property) const
- {
- return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
- }
+ bool createAnimationFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double beginTime);
+ bool createTransformAnimationsFromKeyframes(const KeyframeValueList&, const Animation*, const String& keyframesName, double beginTime, const IntSize& boxSize);
- void setBasicAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation*, double time);
- void setKeyframeAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* keys, void* values, void* timingFunctions, bool isTransition, const Animation*, double time);
+ // Return autoreleased animation (use RetainPtr?)
+ CABasicAnimation* createBasicAnimation(const Animation*, AnimatedPropertyID, bool additive);
+ CAKeyframeAnimation* createKeyframeAnimation(const Animation*, AnimatedPropertyID, bool additive);
+ void setupAnimation(CAPropertyAnimation*, const Animation*, bool additive);
+
+ CAMediaTimingFunction* timingFunctionForAnimationValue(const AnimationValue*, const Animation*);
+
+ bool setAnimationEndpoints(const KeyframeValueList&, const Animation*, CABasicAnimation*);
+ bool setAnimationKeyframes(const KeyframeValueList&, const Animation*, CAKeyframeAnimation*);
- virtual void removeAnimation(int index, bool reset);
+ bool setTransformAnimationEndpoints(const KeyframeValueList&, const Animation*, CABasicAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize);
+ bool setTransformAnimationKeyframes(const KeyframeValueList&, const Animation*, CAKeyframeAnimation*, int functionIndex, TransformOperation::OperationType, bool isMatrixAnimation, const IntSize& boxSize);
+
+ bool animationIsRunning(const String& keyframesName) const
+ {
+ return m_runningKeyframeAnimations.find(keyframesName) != m_runningKeyframeAnimations.end();
+ }
bool requiresTiledLayer(const FloatSize&) const;
void swapFromOrToTiledLayer(bool useTiledLayer);
- void setContentsLayer(WebLayer*);
- WebLayer* contentsLayer() const { return m_contentsLayer.get(); }
+ CompositingCoordinatesOrientation defaultContentsOrientation() const;
+ void updateContentsTransform();
+ void setupContentsLayer(CALayer*);
+ CALayer* contentsLayer() const { return m_contentsLayer.get(); }
+
+ // All these "update" methods will be called inside a BEGIN_BLOCK_OBJC_EXCEPTIONS/END_BLOCK_OBJC_EXCEPTIONS block.
+ void updateSublayerList();
+ void updateLayerPosition();
+ void updateLayerSize();
+ void updateAnchorPoint();
+ void updateTransform();
+ void updateChildrenTransform();
+ void updateMasksToBounds();
+ void updateContentsOpaque();
+ void updateBackfaceVisibility();
+ void updateLayerPreserves3D();
+ void updateLayerDrawsContent();
+ void updateLayerBackgroundColor();
+
+ void updateContentsImage();
+ void updateContentsVideo();
+ void updateContentsRect();
+ void updateGeometryOrientation();
+
+ void updateLayerAnimations();
+
+ void setAnimationOnLayer(CAPropertyAnimation*, AnimatedPropertyID, int index, double beginTime);
+ bool removeAnimationFromLayer(AnimatedPropertyID, int index);
+ void pauseAnimationOnLayer(AnimatedPropertyID, int index);
+
+ enum LayerChange {
+ NoChange = 0,
+ NameChanged = 1 << 1,
+ ChildrenChanged = 1 << 2, // also used for content layer, and preserves-3d, and size if tiling changes?
+ PositionChanged = 1 << 3,
+ AnchorPointChanged = 1 << 4,
+ SizeChanged = 1 << 5,
+ TransformChanged = 1 << 6,
+ ChildrenTransformChanged = 1 << 7,
+ Preserves3DChanged = 1 << 8,
+ MasksToBoundsChanged = 1 << 9,
+ DrawsContentChanged = 1 << 10, // need this?
+ BackgroundColorChanged = 1 << 11,
+ ContentsOpaqueChanged = 1 << 12,
+ BackfaceVisibilityChanged = 1 << 13,
+ OpacityChanged = 1 << 14,
+ AnimationChanged = 1 << 15,
+ DirtyRectsChanged = 1 << 16,
+ ContentsImageChanged = 1 << 17,
+ ContentsVideoChanged = 1 << 18,
+ ContentsRectChanged = 1 << 19,
+ GeometryOrientationChanged = 1 << 20
+ };
+ typedef unsigned LayerChangeFlags;
+ void noteLayerPropertyChanged(LayerChangeFlags flags);
+
+ void repaintLayerDirtyRects();
+
RetainPtr<WebLayer> m_layer;
RetainPtr<WebLayer> m_transformLayer;
- RetainPtr<WebLayer> m_contentsLayer;
+ RetainPtr<CALayer> m_contentsLayer;
+
+ enum ContentsLayerPurpose {
+ NoContentsLayer = 0,
+ ContentsLayerForImage,
+ ContentsLayerForVideo
+ };
+
+ ContentsLayerPurpose m_contentsLayerPurpose;
+ bool m_contentsLayerHasBackgroundColor : 1;
RetainPtr<WebAnimationDelegate> m_animationDelegate;
- bool m_contentLayerForImageOrVideo;
+ RetainPtr<CGImageRef> m_pendingContentsImage;
+
+ struct LayerAnimation {
+ LayerAnimation(CAPropertyAnimation* caAnim, const String& keyframesName, AnimatedPropertyID property, int index, double beginTime)
+ : m_animation(caAnim)
+ , m_keyframesName(keyframesName)
+ , m_property(property)
+ , m_index(index)
+ , m_beginTime(beginTime)
+ { }
+
+ RetainPtr<CAPropertyAnimation*> m_animation;
+ String m_keyframesName;
+ AnimatedPropertyID m_property;
+ int m_index;
+ double m_beginTime;
+ };
+
+ Vector<LayerAnimation> m_uncomittedAnimations;
+
+ // Animations on the layer are identified by property + index.
+ typedef int AnimatedProperty; // std containers choke on the AnimatedPropertyID enum
+ typedef pair<AnimatedProperty, int> AnimationPair;
+
+ HashSet<AnimatedProperty> m_transitionPropertiesToRemove;
+
+ enum { Remove, Pause };
+ typedef int AnimationProcessingAction;
+ typedef HashMap<String, AnimationProcessingAction> AnimationsToProcessMap;
+ AnimationsToProcessMap m_keyframeAnimationsToProcess;
+
+ // Map of keyframe names to their associated lists of animations for running animations, so we can remove/pause them.
+ typedef HashMap<String, Vector<AnimationPair> > KeyframeAnimationsMap;
+ KeyframeAnimationsMap m_runningKeyframeAnimations;
+
+ Vector<FloatRect> m_dirtyRects;
+
+ LayerChangeFlags m_uncommittedChanges;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
index f361437..e5b9035 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -43,8 +43,10 @@
#import "TranslateTransformOperation.h"
#import "WebLayer.h"
#import "WebTiledLayer.h"
+#import <limits.h>
#import <wtf/CurrentTime.h>
#import <wtf/UnusedParam.h>
+#import <wtf/RetainPtr.h>
using namespace std;
@@ -80,8 +82,6 @@ static double mediaTimeToCurrentTime(CFTimeInterval t)
} // namespace WebCore
-static NSString* const WebAnimationCSSPropertyKey = @"GraphicsLayerCA_property";
-
@interface WebAnimationDelegate : NSObject {
WebCore::GraphicsLayerCA* m_graphicsLayer;
}
@@ -137,27 +137,25 @@ static inline void copyTransform(CATransform3D& toT3D, const TransformationMatri
toT3D.m44 = narrowPrecisionToFloat(t.m44());
}
-static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue& transformValue, size_t index, const IntSize& size, TransformOperation::OperationType transformType)
+static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, TransformOperation::OperationType transformType, const IntSize& size)
{
- TransformOperation* op = (index >= transformValue.value()->operations().size()) ? 0 : transformValue.value()->operations()[index].get();
-
switch (transformType) {
case TransformOperation::ROTATE:
case TransformOperation::ROTATE_X:
case TransformOperation::ROTATE_Y:
- return [NSNumber numberWithDouble:op ? deg2rad(static_cast<RotateTransformOperation*>(op)->angle()) : 0];
+ return [NSNumber numberWithDouble:transformOp ? deg2rad(static_cast<const RotateTransformOperation*>(transformOp)->angle()) : 0];
case TransformOperation::SCALE_X:
- return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->x() : 0];
+ return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 0];
case TransformOperation::SCALE_Y:
- return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->y() : 0];
+ return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 0];
case TransformOperation::SCALE_Z:
- return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->z() : 0];
+ return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 0];
case TransformOperation::TRANSLATE_X:
- return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0];
+ return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0];
case TransformOperation::TRANSLATE_Y:
- return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->y(size) : 0];
+ return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->y(size) : 0];
case TransformOperation::TRANSLATE_Z:
- return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->z(size) : 0];
+ return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0];
case TransformOperation::SCALE:
case TransformOperation::TRANSLATE:
case TransformOperation::SKEW_X:
@@ -171,12 +169,12 @@ static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue& t
case TransformOperation::PERSPECTIVE:
case TransformOperation::IDENTITY:
case TransformOperation::NONE: {
- TransformationMatrix t;
- if (op)
- op->apply(t, size);
- CATransform3D cat;
- copyTransform(cat, t);
- return [NSValue valueWithCATransform3D:cat];
+ TransformationMatrix transform;
+ if (transformOp)
+ transformOp->apply(transform, size);
+ CATransform3D caTransform;
+ copyTransform(caTransform, transform);
+ return [NSValue valueWithCATransform3D:caTransform];
}
}
@@ -212,6 +210,39 @@ static NSString* getValueFunctionNameForTransformOperation(TransformOperation::O
}
#endif
+static String propertyIdToString(AnimatedPropertyID property)
+{
+ switch (property) {
+ case AnimatedPropertyWebkitTransform:
+ return "transform";
+ case AnimatedPropertyOpacity:
+ return "opacity";
+ case AnimatedPropertyBackgroundColor:
+ return "backgroundColor";
+ case AnimatedPropertyInvalid:
+ ASSERT_NOT_REACHED();
+ }
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+static String animationIdentifier(AnimatedPropertyID property, int index)
+{
+ String animationId = propertyIdToString(property);
+ animationId.append("_");
+ animationId.append(String::number(index));
+ return animationId;
+}
+
+#if !HAVE_MODERN_QUARTZCORE
+static TransformationMatrix flipTransform()
+{
+ TransformationMatrix flipper;
+ flipper.flipY();
+ return flipper;
+}
+#endif
+
static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction)
{
switch (timingFunction.type()) {
@@ -250,15 +281,6 @@ static void clearLayerBackgroundColor(PlatformLayer* layer)
[layer setBackgroundColor:0];
}
-static CALayer* getPresentationLayer(CALayer* layer)
-{
- CALayer* presLayer = [layer presentationLayer];
- if (!presLayer)
- presLayer = layer;
-
- return presLayer;
-}
-
static bool caValueFunctionSupported()
{
static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
@@ -304,9 +326,7 @@ static NSDictionary* nullActionsDictionary()
nullValue, @"sublayerTransform",
nullValue, @"sublayers",
nullValue, @"transform",
-#ifndef NDEBUG
nullValue, @"zPosition",
-#endif
nil];
return actions;
}
@@ -318,12 +338,18 @@ GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client)
GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
: GraphicsLayer(client)
-, m_contentLayerForImageOrVideo(false)
+, m_contentsLayerPurpose(NoContentsLayer)
+, m_contentsLayerHasBackgroundColor(false)
+, m_uncommittedChanges(NoChange)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS
m_layer.adoptNS([[WebLayer alloc] init]);
[m_layer.get() setLayerOwner:this];
+#if !HAVE_MODERN_QUARTZCORE
+ setContentsOrientation(defaultContentsOrientation());
+#endif
+
#ifndef NDEBUG
updateDebugIndicators();
#endif
@@ -336,21 +362,18 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
GraphicsLayerCA::~GraphicsLayerCA()
{
- // Remove a inner layer if there is one.
- clearContents();
-
+ // We release our references to the CALayers here, but do not actively unparent them,
+ // since that will cause a commit and break our batched commit model. The layers will
+ // get released when the rootmost modified GraphicsLayerCA rebuilds its child layers.
+
BEGIN_BLOCK_OBJC_EXCEPTIONS
// Clean up the WK layer.
if (m_layer) {
WebLayer* layer = m_layer.get();
[layer setLayerOwner:nil];
- [layer removeFromSuperlayer];
}
- if (m_transformLayer)
- [m_transformLayer.get() removeFromSuperlayer];
-
// animationDidStart: can fire after this, so we need to clear out the layer on the delegate.
[m_animationDelegate.get() setLayer:0];
@@ -361,10 +384,7 @@ void GraphicsLayerCA::setName(const String& name)
{
String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name;
GraphicsLayer::setName(longName);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [m_layer.get() setName:name];
- END_BLOCK_OBJC_EXCEPTIONS
+ noteLayerPropertyChanged(NameChanged);
}
NativeLayer GraphicsLayerCA::nativeLayer() const
@@ -375,176 +395,485 @@ NativeLayer GraphicsLayerCA::nativeLayer() const
void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
{
GraphicsLayer::addChild(childLayer);
-
- GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
- END_BLOCK_OBJC_EXCEPTIONS
+ noteLayerPropertyChanged(ChildrenChanged);
}
void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index)
{
GraphicsLayer::addChildAtIndex(childLayer, index);
-
- GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() atIndex:index];
- END_BLOCK_OBJC_EXCEPTIONS
+ noteLayerPropertyChanged(ChildrenChanged);
}
void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling)
{
- // FIXME: share code with base class
- ASSERT(childLayer != this);
- childLayer->removeFromParent();
+ GraphicsLayer::addChildBelow(childLayer, sibling);
+ noteLayerPropertyChanged(ChildrenChanged);
+}
- bool found = false;
- for (unsigned i = 0; i < m_children.size(); i++) {
- if (sibling == m_children[i]) {
- m_children.insert(i, childLayer);
- found = true;
- break;
- }
+void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildAbove(childLayer, sibling);
+ noteLayerPropertyChanged(ChildrenChanged);
+}
+
+bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ noteLayerPropertyChanged(ChildrenChanged);
+ return true;
}
- childLayer->setParent(this);
+ return false;
+}
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+void GraphicsLayerCA::removeFromParent()
+{
+ if (m_parent)
+ static_cast<GraphicsLayerCA*>(m_parent)->noteLayerPropertyChanged(ChildrenChanged);
+ GraphicsLayer::removeFromParent();
+}
- GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
- GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
- if (found)
- [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() below:siblingLayerCA->layerForSuperlayer()];
- else {
- m_children.append(childLayer);
- [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
- }
+void GraphicsLayerCA::setPosition(const FloatPoint& point)
+{
+ if (point == m_position)
+ return;
- END_BLOCK_OBJC_EXCEPTIONS
+ GraphicsLayer::setPosition(point);
+ noteLayerPropertyChanged(PositionChanged);
}
-void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling)
+void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
{
- // FIXME: share code with base class
- ASSERT(childLayer != this);
- childLayer->removeFromParent();
+ if (point == m_anchorPoint)
+ return;
+
+ GraphicsLayer::setAnchorPoint(point);
+ noteLayerPropertyChanged(AnchorPointChanged);
+}
- unsigned i;
- bool found = false;
- for (i = 0; i < m_children.size(); i++) {
- if (sibling == m_children[i]) {
- m_children.insert(i+1, childLayer);
- found = true;
+void GraphicsLayerCA::setSize(const FloatSize& size)
+{
+ if (size == m_size)
+ return;
+
+ GraphicsLayer::setSize(size);
+ noteLayerPropertyChanged(SizeChanged);
+}
+
+void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
+{
+ if (t == m_transform)
+ return;
+
+ GraphicsLayer::setTransform(t);
+ noteLayerPropertyChanged(TransformChanged);
+}
+
+void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
+{
+ if (t == m_childrenTransform)
+ return;
+
+ GraphicsLayer::setChildrenTransform(t);
+ noteLayerPropertyChanged(ChildrenTransformChanged);
+}
+
+static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
+{
+ for (int index = 0; ; ++index) {
+ String animName = animationIdentifier(property, index);
+
+ CAAnimation* anim = [fromLayer animationForKey:animName];
+ if (!anim)
break;
- }
+
+ [anim retain];
+ [fromLayer removeAnimationForKey:animName];
+ [toLayer addAnimation:anim forKey:animName];
+ [anim release];
}
- childLayer->setParent(this);
+}
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+void GraphicsLayerCA::setPreserves3D(bool preserves3D)
+{
+ if (preserves3D == m_preserves3D)
+ return;
- GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer);
- GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling);
- if (found) {
- [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() above:siblingLayerCA->layerForSuperlayer()];
- } else {
- m_children.append(childLayer);
- [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()];
+ GraphicsLayer::setPreserves3D(preserves3D);
+ noteLayerPropertyChanged(Preserves3DChanged);
+}
+
+void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
+{
+ if (masksToBounds == m_masksToBounds)
+ return;
+
+ GraphicsLayer::setMasksToBounds(masksToBounds);
+ noteLayerPropertyChanged(MasksToBoundsChanged);
+}
+
+void GraphicsLayerCA::setDrawsContent(bool drawsContent)
+{
+ if (drawsContent == m_drawsContent)
+ return;
+
+ GraphicsLayer::setDrawsContent(drawsContent);
+ noteLayerPropertyChanged(DrawsContentChanged);
+}
+
+void GraphicsLayerCA::setBackgroundColor(const Color& color)
+{
+ if (m_backgroundColorSet && m_backgroundColor == color)
+ return;
+
+ GraphicsLayer::setBackgroundColor(color);
+
+ m_contentsLayerHasBackgroundColor = true;
+ noteLayerPropertyChanged(BackgroundColorChanged);
+}
+
+void GraphicsLayerCA::clearBackgroundColor()
+{
+ if (!m_backgroundColorSet)
+ return;
+
+ GraphicsLayer::clearBackgroundColor();
+ m_contentsLayerHasBackgroundColor = false;
+ noteLayerPropertyChanged(BackgroundColorChanged);
+}
+
+void GraphicsLayerCA::setContentsOpaque(bool opaque)
+{
+ if (m_contentsOpaque == opaque)
+ return;
+
+ GraphicsLayer::setContentsOpaque(opaque);
+ noteLayerPropertyChanged(ContentsOpaqueChanged);
+}
+
+void GraphicsLayerCA::setBackfaceVisibility(bool visible)
+{
+ if (m_backfaceVisibility == visible)
+ return;
+
+ GraphicsLayer::setBackfaceVisibility(visible);
+ noteLayerPropertyChanged(BackfaceVisibilityChanged);
+}
+
+void GraphicsLayerCA::setOpacity(float opacity)
+{
+ float clampedOpacity = max(0.0f, min(opacity, 1.0f));
+
+ if (clampedOpacity == m_opacity)
+ return;
+
+ GraphicsLayer::setOpacity(clampedOpacity);
+ noteLayerPropertyChanged(OpacityChanged);
+}
+
+void GraphicsLayerCA::setNeedsDisplay()
+{
+ FloatRect hugeRect(-numeric_limits<float>::max() / 2, -numeric_limits<float>::max() / 2,
+ numeric_limits<float>::max(), numeric_limits<float>::max());
+
+ setNeedsDisplayInRect(hugeRect);
+}
+
+void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ if (!drawsContent())
+ return;
+
+ const size_t maxDirtyRects = 32;
+
+ for (size_t i = 0; i < m_dirtyRects.size(); ++i) {
+ if (m_dirtyRects[i].contains(rect))
+ return;
}
+
+ if (m_dirtyRects.size() < maxDirtyRects)
+ m_dirtyRects.append(rect);
+ else
+ m_dirtyRects[0].unite(rect);
- END_BLOCK_OBJC_EXCEPTIONS
+ noteLayerPropertyChanged(DirtyRectsChanged);
}
-bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+void GraphicsLayerCA::setContentsRect(const IntRect& rect)
{
- // FIXME: share code with base class
- ASSERT(!newChild->parent());
+ if (rect == m_contentsRect)
+ return;
- bool found = false;
- for (unsigned i = 0; i < m_children.size(); i++) {
- if (oldChild == m_children[i]) {
- m_children[i] = newChild;
- found = true;
- break;
+ GraphicsLayer::setContentsRect(rect);
+ noteLayerPropertyChanged(ContentsRectChanged);
+}
+
+bool GraphicsLayerCA::addAnimation(const KeyframeValueList& valueList, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double beginTime)
+{
+ if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
+ return false;
+
+#if !HAVE_MODERN_QUARTZCORE
+ // Older versions of QuartzCore do not handle opacity in transform layers properly, so we will
+ // always do software animation in that case.
+ if (valueList.property() == AnimatedPropertyOpacity)
+ return false;
+#endif
+
+ bool createdAnimations = false;
+ if (valueList.property() == AnimatedPropertyWebkitTransform)
+ createdAnimations = createTransformAnimationsFromKeyframes(valueList, anim, keyframesName, beginTime, boxSize);
+ else
+ createdAnimations = createAnimationFromKeyframes(valueList, anim, keyframesName, beginTime);
+
+ if (createdAnimations)
+ noteLayerPropertyChanged(AnimationChanged);
+
+ return createdAnimations;
+}
+
+void GraphicsLayerCA::removeAnimationsForProperty(AnimatedPropertyID property)
+{
+ if (m_transitionPropertiesToRemove.find(property) != m_transitionPropertiesToRemove.end())
+ return;
+
+ m_transitionPropertiesToRemove.add(property);
+ noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::removeAnimationsForKeyframes(const String& animationName)
+{
+ if (!animationIsRunning(animationName))
+ return;
+
+ m_keyframeAnimationsToProcess.add(animationName, Remove);
+ noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::pauseAnimation(const String& keyframesName)
+{
+ if (!animationIsRunning(keyframesName))
+ return;
+
+ AnimationsToProcessMap::iterator it = m_keyframeAnimationsToProcess.find(keyframesName);
+ if (it != m_keyframeAnimationsToProcess.end()) {
+ // If an animation is scheduled to be removed, don't change the remove to a pause.
+ if (it->second != Remove)
+ it->second = Pause;
+ } else
+ m_keyframeAnimationsToProcess.add(keyframesName, Pause);
+
+ noteLayerPropertyChanged(AnimationChanged);
+}
+
+void GraphicsLayerCA::setContentsToImage(Image* image)
+{
+ if (image) {
+ m_pendingContentsImage = image->nativeImageForCurrentFrame();
+ CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get());
+
+ static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ if (CFEqual(colorSpace, deviceRGB)) {
+ // CoreGraphics renders images tagged with DeviceRGB using GenericRGB. When we hand such
+ // images to CA we need to tag them similarly so CA rendering matches CG rendering.
+ static CGColorSpaceRef genericRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB));
}
+ m_contentsLayerPurpose = ContentsLayerForImage;
+ if (!m_contentsLayer)
+ noteLayerPropertyChanged(ChildrenChanged);
+ } else {
+ m_pendingContentsImage = 0;
+ m_contentsLayerPurpose = NoContentsLayer;
+ if (m_contentsLayer)
+ noteLayerPropertyChanged(ChildrenChanged);
}
- if (found) {
- oldChild->setParent(0);
+ noteLayerPropertyChanged(ContentsImageChanged);
+}
+
+void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
+{
+ if (videoLayer != m_contentsLayer.get())
+ noteLayerPropertyChanged(ChildrenChanged);
- newChild->removeFromParent();
- newChild->setParent(this);
+ m_contentsLayer = videoLayer;
+ noteLayerPropertyChanged(ContentsVideoChanged);
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- GraphicsLayerCA* oldChildCA = static_cast<GraphicsLayerCA*>(oldChild);
- GraphicsLayerCA* newChildCA = static_cast<GraphicsLayerCA*>(newChild);
- [hostLayerForSublayers() replaceSublayer:oldChildCA->layerForSuperlayer() with:newChildCA->layerForSuperlayer()];
- END_BLOCK_OBJC_EXCEPTIONS
- return true;
- }
- return false;
+ m_contentsLayerPurpose = videoLayer ? ContentsLayerForVideo : NoContentsLayer;
}
-void GraphicsLayerCA::removeFromParent()
+void GraphicsLayerCA::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
{
- GraphicsLayer::removeFromParent();
+ if (orientation == m_geometryOrientation)
+ return;
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [layerForSuperlayer() removeFromSuperlayer];
- END_BLOCK_OBJC_EXCEPTIONS
+ GraphicsLayer::setGeometryOrientation(orientation);
+ noteLayerPropertyChanged(GeometryOrientationChanged);
+
+#if !HAVE_MODERN_QUARTZCORE
+ // Geometry orientation is mapped onto children transform in older QuartzCores.
+ switch (m_geometryOrientation) {
+ case CompositingCoordinatesTopDown:
+ setChildrenTransform(TransformationMatrix());
+ break;
+
+ case CompositingCoordinatesBottomUp:
+ setChildrenTransform(flipTransform());
+ break;
+ }
+#endif
}
-void GraphicsLayerCA::setPosition(const FloatPoint& point)
+void GraphicsLayerCA::syncCompositingState()
{
- // Don't short-circuit here, because position and anchor point are inter-dependent.
- GraphicsLayer::setPosition(point);
+ recursiveCommitChanges();
+}
- // Position is offset on the layer by the layer anchor point.
- CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
- m_position.y() + m_anchorPoint.y() * m_size.height());
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [primaryLayer() setPosition:posPoint];
- END_BLOCK_OBJC_EXCEPTIONS
+void GraphicsLayerCA::recursiveCommitChanges()
+{
+ commitLayerChanges();
+
+ const Vector<GraphicsLayer*>& childLayers = children();
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+ curChild->recursiveCommitChanges();
+ }
}
-void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point)
+void GraphicsLayerCA::commitLayerChanges()
{
- // Don't short-circuit here, because position and anchor point are inter-dependent.
- bool zChanged = (point.z() != m_anchorPoint.z());
- GraphicsLayer::setAnchorPoint(point);
+ if (!m_uncommittedChanges)
+ return;
BEGIN_BLOCK_OBJC_EXCEPTIONS
- // set the value on the layer to the new transform.
- [primaryLayer() setAnchorPoint:FloatPoint(point.x(), point.y())];
- if (zChanged) {
-#if HAVE_MODERN_QUARTZCORE
- [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
-#endif
+ // Need to handle Preserves3DChanged first, because it affects which layers subsequent properties are applied to
+ if (m_uncommittedChanges & Preserves3DChanged)
+ updateLayerPreserves3D();
+
+ if (m_uncommittedChanges & NameChanged) {
+ if (m_transformLayer)
+ [m_transformLayer.get() setName:("Transform layer " + name())];
+ [m_layer.get() setName:name()];
}
- // Position depends on anchor point, so update it now.
- setPosition(m_position);
+ if (m_uncommittedChanges & ContentsImageChanged) // Needs to happen before ChildrenChanged
+ updateContentsImage();
+
+ if (m_uncommittedChanges & ContentsVideoChanged) // Needs to happen before ChildrenChanged
+ updateContentsVideo();
+
+ if (m_uncommittedChanges & BackgroundColorChanged) // Needs to happen before ChildrenChanged, and after updating image or video
+ updateLayerBackgroundColor();
+
+ if (m_uncommittedChanges & ChildrenChanged)
+ updateSublayerList();
+
+ if (m_uncommittedChanges & PositionChanged)
+ updateLayerPosition();
+
+ if (m_uncommittedChanges & AnchorPointChanged)
+ updateAnchorPoint();
+
+ if (m_uncommittedChanges & SizeChanged)
+ updateLayerSize();
+
+ if (m_uncommittedChanges & TransformChanged)
+ updateTransform();
+
+ if (m_uncommittedChanges & ChildrenTransformChanged)
+ updateChildrenTransform();
+
+ if (m_uncommittedChanges & MasksToBoundsChanged)
+ updateMasksToBounds();
+
+ if (m_uncommittedChanges & DrawsContentChanged)
+ updateLayerDrawsContent();
+
+ if (m_uncommittedChanges & ContentsOpaqueChanged)
+ updateContentsOpaque();
+
+ if (m_uncommittedChanges & BackfaceVisibilityChanged)
+ updateBackfaceVisibility();
+
+ if (m_uncommittedChanges & OpacityChanged)
+ updateOpacityOnLayer();
+
+ if (m_uncommittedChanges & AnimationChanged)
+ updateLayerAnimations();
+
+ if (m_uncommittedChanges & DirtyRectsChanged)
+ repaintLayerDirtyRects();
+
+ if (m_uncommittedChanges & ContentsRectChanged)
+ updateContentsRect();
+
+ if (m_uncommittedChanges & GeometryOrientationChanged)
+ updateGeometryOrientation();
+
+ m_uncommittedChanges = NoChange;
END_BLOCK_OBJC_EXCEPTIONS
}
-void GraphicsLayerCA::setSize(const FloatSize& size)
+void GraphicsLayerCA::updateSublayerList()
{
- GraphicsLayer::setSize(size);
+ NSMutableArray* newSublayers = nil;
- CGRect rect = CGRectMake(0.0f,
- 0.0f,
- m_size.width(),
- m_size.height());
+ if (m_transformLayer) {
+ // FIXME: add the primary layer in the correct order with negative z-order children.
+ newSublayers = [[NSMutableArray alloc] initWithObjects:m_layer.get(), nil];
+ } else if (m_contentsLayer) {
+ // FIXME: add the contents layer in the correct order with negative z-order children.
+ newSublayers = [[NSMutableArray alloc] initWithObjects:m_contentsLayer.get(), nil];
+ }
- CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
+ const Vector<GraphicsLayer*>& childLayers = children();
+ size_t numChildren = childLayers.size();
+ for (size_t i = 0; i < numChildren; ++i) {
+ GraphicsLayerCA* curChild = static_cast<GraphicsLayerCA*>(childLayers[i]);
+
+ CALayer* childLayer = curChild->layerForSuperlayer();
+ if (!newSublayers)
+ newSublayers = [[NSMutableArray alloc] initWithObjects:childLayer, nil];
+ else
+ [newSublayers addObject:childLayer];
+ }
+
+ [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
+
+ if (m_transformLayer) {
+ [m_transformLayer.get() setSublayers:newSublayers];
+
+ if (m_contentsLayer) {
+ // If we have a transform layer, then the contents layer is parented in the
+ // primary layer (which is itself a child of the transform layer).
+ [m_layer.get() setSublayers:nil];
+ [m_layer.get() addSublayer:m_contentsLayer.get()];
+ }
+ } else {
+ [m_layer.get() setSublayers:newSublayers];
+ }
+
+ [newSublayers release];
+}
+
+void GraphicsLayerCA::updateLayerPosition()
+{
+ // Position is offset on the layer by the layer anchor point.
+ CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(),
+ m_position.y() + m_anchorPoint.y() * m_size.height());
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [primaryLayer() setPosition:posPoint];
+}
+void GraphicsLayerCA::updateLayerSize()
+{
+ CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height());
if (m_transformLayer) {
[m_transformLayer.get() setBounds:rect];
-
- // the anchor of the contents layer is always at 0.5, 0.5, so the position
- // is center-relative
+ // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative.
+ CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
[m_layer.get() setPosition:centerPoint];
}
@@ -553,136 +882,88 @@ void GraphicsLayerCA::setSize(const FloatSize& size)
swapFromOrToTiledLayer(needTiledLayer);
[m_layer.get() setBounds:rect];
+
+ // Contents transform may depend on height.
+ updateContentsTransform();
// Note that we don't resize m_contentsLayer. It's up the caller to do that.
- END_BLOCK_OBJC_EXCEPTIONS
-
// if we've changed the bounds, we need to recalculate the position
- // of the layer, taking anchor point into account
- setPosition(m_position);
+ // of the layer, taking anchor point into account.
+ updateLayerPosition();
}
-void GraphicsLayerCA::setTransform(const TransformationMatrix& t)
+void GraphicsLayerCA::updateAnchorPoint()
+{
+ [primaryLayer() setAnchorPoint:FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())];
+#if HAVE_MODERN_QUARTZCORE
+ [primaryLayer() setAnchorPointZ:m_anchorPoint.z()];
+#endif
+ updateLayerPosition();
+}
+
+void GraphicsLayerCA::updateTransform()
{
- GraphicsLayer::setTransform(t);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
CATransform3D transform;
- copyTransform(transform, t);
+ copyTransform(transform, m_transform);
[primaryLayer() setTransform:transform];
- END_BLOCK_OBJC_EXCEPTIONS
-
- // Remove any old transition entries for transform.
- removeAllAnimationsForProperty(AnimatedPropertyWebkitTransform);
-
- // Even if we don't have a transition in the list, the layer may still have one.
- // This happens when we are setting the final transform value after an animation or
- // transition has ended. In removeAnimation we toss the entry from the list but don't
- // remove it from the list. That way we aren't in danger of displaying a stale transform
- // in the time between removing the animation and setting the new unanimated value. We
- // can't do this in removeAnimation because we don't know the new transform value there.
- String keyPath = propertyIdToString(AnimatedPropertyWebkitTransform);
- CALayer* layer = animatedLayer(AnimatedPropertyWebkitTransform);
-
- for (int i = 0; ; ++i) {
- String animName = keyPath + "_" + String::number(i);
- if (![layer animationForKey: animName])
- break;
- [layer removeAnimationForKey:animName];
- }
}
-void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t)
+void GraphicsLayerCA::updateChildrenTransform()
{
- if (t == m_childrenTransform)
- return;
-
- GraphicsLayer::setChildrenTransform(t);
-
CATransform3D transform;
- copyTransform(transform, t);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- // Set the value on the layer to the new transform.
+ copyTransform(transform, m_childrenTransform);
[primaryLayer() setSublayerTransform:transform];
- END_BLOCK_OBJC_EXCEPTIONS
}
-static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer)
+void GraphicsLayerCA::updateMasksToBounds()
{
- String keyPath = GraphicsLayer::propertyIdToString(property);
- for (short index = 0; ; ++index) {
- String animName = keyPath + "_" + String::number(index);
- CAAnimation* anim = [fromLayer animationForKey:animName];
- if (!anim)
- break;
-
- [anim retain];
- [fromLayer removeAnimationForKey:animName];
- [toLayer addAnimation:anim forKey:animName];
- [anim release];
- }
+ [m_layer.get() setMasksToBounds:m_masksToBounds];
+#ifndef NDEBUG
+ updateDebugIndicators();
+#endif
}
-static void moveSublayers(CALayer* fromLayer, CALayer* toLayer)
+void GraphicsLayerCA::updateContentsOpaque()
{
- NSArray* sublayersCopy = [[fromLayer sublayers] copy]; // Avoid mutation while enumerating, and keep the sublayers alive.
- NSEnumerator* childrenEnumerator = [sublayersCopy objectEnumerator];
-
- CALayer* layer;
- while ((layer = [childrenEnumerator nextObject]) != nil) {
- [layer removeFromSuperlayer];
- [toLayer addSublayer:layer];
- }
- [sublayersCopy release];
+ [m_layer.get() setOpaque:m_contentsOpaque];
}
-void GraphicsLayerCA::setPreserves3D(bool preserves3D)
+void GraphicsLayerCA::updateBackfaceVisibility()
{
- GraphicsLayer::setPreserves3D(preserves3D);
-
- CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
- CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+ [m_layer.get() setDoubleSided:m_backfaceVisibility];
+}
+void GraphicsLayerCA::updateLayerPreserves3D()
+{
Class transformLayerClass = NSClassFromString(@"CATransformLayer");
- if (preserves3D && !m_transformLayer && transformLayerClass) {
+ if (!transformLayerClass)
+ return;
+
+ if (m_preserves3D && !m_transformLayer) {
// Create the transform layer.
m_transformLayer.adoptNS([[transformLayerClass alloc] init]);
// Turn off default animations.
[m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
-
+
#ifndef NDEBUG
[m_transformLayer.get() setName:[NSString stringWithFormat:@"Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this]];
#endif
// Copy the position from this layer.
- [m_transformLayer.get() setBounds:[m_layer.get() bounds]];
- [m_transformLayer.get() setPosition:[m_layer.get() position]];
- [m_transformLayer.get() setAnchorPoint:[m_layer.get() anchorPoint]];
-#if HAVE_MODERN_QUARTZCORE
- [m_transformLayer.get() setAnchorPointZ:[m_layer.get() anchorPointZ]];
-#endif
- [m_transformLayer.get() setContentsRect:[m_layer.get() contentsRect]];
-#ifndef NDEBUG
- [m_transformLayer.get() setZPosition:[m_layer.get() zPosition]];
-#endif
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
- // The contents layer is positioned at (0,0) relative to the transformLayer.
+ CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f);
[m_layer.get() setPosition:point];
- [m_layer.get() setAnchorPoint:centerPoint];
-#ifndef NDEBUG
- [m_layer.get() setZPosition:0.0f];
-#endif
-
- // Transfer the transform over.
- [m_transformLayer.get() setTransform:[m_layer.get() transform]];
+
+ [m_layer.get() setAnchorPoint:CGPointMake(0.5f, 0.5f)];
[m_layer.get() setTransform:CATransform3DIdentity];
- // Transfer the opacity from the old layer to the transform layer.
- [m_transformLayer.get() setOpacity:m_opacity];
+ // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer.
[m_layer.get() setOpacity:1];
// Move this layer to be a child of the transform layer.
@@ -690,600 +971,584 @@ void GraphicsLayerCA::setPreserves3D(bool preserves3D)
[m_transformLayer.get() addSublayer:m_layer.get()];
moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get());
- moveSublayers(m_layer.get(), m_transformLayer.get());
-
- } else if (!preserves3D && m_transformLayer) {
+
+ updateSublayerList();
+ } else if (!m_preserves3D && m_transformLayer) {
// Relace the transformLayer in the parent with this layer.
[m_layer.get() removeFromSuperlayer];
[[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()];
moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get());
- moveSublayers(m_transformLayer.get(), m_layer.get());
-
- // Reset the layer position and transform.
- [m_layer.get() setPosition:[m_transformLayer.get() position]];
- [m_layer.get() setAnchorPoint:[m_transformLayer.get() anchorPoint]];
-#if HAVE_MODERN_QUARTZCORE
- [m_layer.get() setAnchorPointZ:[m_transformLayer.get() anchorPointZ]];
-#endif
- [m_layer.get() setContentsRect:[m_transformLayer.get() contentsRect]];
- [m_layer.get() setTransform:[m_transformLayer.get() transform]];
- [m_layer.get() setOpacity:[m_transformLayer.get() opacity]];
-#ifndef NDEBUG
- [m_layer.get() setZPosition:[m_transformLayer.get() zPosition]];
-#endif
// Release the transform layer.
m_transformLayer = 0;
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+
+ updateSublayerList();
}
- END_BLOCK_OBJC_EXCEPTIONS
+ updateOpacityOnLayer();
}
-void GraphicsLayerCA::setMasksToBounds(bool masksToBounds)
+void GraphicsLayerCA::updateLayerDrawsContent()
{
- if (masksToBounds == m_masksToBounds)
- return;
-
- GraphicsLayer::setMasksToBounds(masksToBounds);
+ bool needTiledLayer = requiresTiledLayer(m_size);
+ if (needTiledLayer != m_usingTiledLayer)
+ swapFromOrToTiledLayer(needTiledLayer);
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [m_layer.get() setMasksToBounds:masksToBounds];
- END_BLOCK_OBJC_EXCEPTIONS
+ if (m_drawsContent)
+ [m_layer.get() setNeedsDisplay];
+ else
+ [m_layer.get() setContents:nil];
#ifndef NDEBUG
updateDebugIndicators();
#endif
}
-void GraphicsLayerCA::setDrawsContent(bool drawsContent)
+void GraphicsLayerCA::updateLayerBackgroundColor()
{
- if (drawsContent != m_drawsContent) {
- GraphicsLayer::setDrawsContent(drawsContent);
-
- bool needTiledLayer = requiresTiledLayer(m_size);
- if (needTiledLayer != m_usingTiledLayer)
- swapFromOrToTiledLayer(needTiledLayer);
+ if (!m_contentsLayer)
+ return;
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- if (m_drawsContent)
- [m_layer.get() setNeedsDisplay];
- else
- [m_layer.get() setContents:nil];
-
-#ifndef NDEBUG
- updateDebugIndicators();
-#endif
- END_BLOCK_OBJC_EXCEPTIONS
- }
+ // We never create the contents layer just for background color yet.
+ if (m_backgroundColorSet)
+ setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
+ else
+ clearLayerBackgroundColor(m_contentsLayer.get());
}
-void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* transition, double beginTime)
+void GraphicsLayerCA::updateContentsImage()
{
- GraphicsLayer::setBackgroundColor(color, transition, beginTime);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
-
- if (!m_contentsLayer.get()) {
- WebLayer* colorLayer = [WebLayer layer];
+ if (m_pendingContentsImage) {
+ if (!m_contentsLayer.get()) {
+ WebLayer* imageLayer = [WebLayer layer];
#ifndef NDEBUG
- [colorLayer setName:@"Color Layer"];
+ [imageLayer setName:@"Image Layer"];
#endif
- setContentsLayer(colorLayer);
- }
-
- if (transition && !transition->isEmptyOrZeroDuration()) {
- CALayer* presLayer = [m_contentsLayer.get() presentationLayer];
- // If we don't have a presentationLayer, just use the CALayer
- if (!presLayer)
- presLayer = m_contentsLayer.get();
-
- // Get the current value of the background color from the layer
- CGColorRef fromBackgroundColor = [presLayer backgroundColor];
-
- CGColorRef bgColor = createCGColor(color);
- setBasicAnimation(AnimatedPropertyBackgroundColor, TransformOperation::NONE, 0, fromBackgroundColor, bgColor, true, transition, beginTime);
- CGColorRelease(bgColor);
+ setupContentsLayer(imageLayer);
+ m_contentsLayer.adoptNS([imageLayer retain]);
+ // m_contentsLayer will be parented by updateSublayerList
+ }
+
+ // FIXME: maybe only do trilinear if the image is being scaled down,
+ // but then what if the layer size changes?
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
+#endif
+ [m_contentsLayer.get() setContents:(id)m_pendingContentsImage.get()];
+ m_pendingContentsImage = 0;
+
+ updateContentsRect();
} else {
- removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor);
- setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor);
+ // No image.
+ // m_contentsLayer will be removed via updateSublayerList.
+ m_contentsLayer = 0;
}
-
- END_BLOCK_OBJC_EXCEPTIONS
}
-void GraphicsLayerCA::clearBackgroundColor()
+void GraphicsLayerCA::updateContentsVideo()
{
- if (!m_contentLayerForImageOrVideo)
- setContentsLayer(0);
- else
- clearLayerBackgroundColor(m_contentsLayer.get());
+ // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList().
+ if (m_contentsLayer) {
+ setupContentsLayer(m_contentsLayer.get());
+ updateContentsRect();
+ }
}
-void GraphicsLayerCA::setContentsOpaque(bool opaque)
+void GraphicsLayerCA::updateContentsRect()
{
- GraphicsLayer::setContentsOpaque(opaque);
+ if (!m_contentsLayer)
+ return;
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [m_layer.get() setOpaque:m_contentsOpaque];
- END_BLOCK_OBJC_EXCEPTIONS
+ CGPoint point = CGPointMake(m_contentsRect.x(),
+ m_contentsRect.y());
+ CGRect rect = CGRectMake(0.0f,
+ 0.0f,
+ m_contentsRect.width(),
+ m_contentsRect.height());
+
+ [m_contentsLayer.get() setPosition:point];
+ [m_contentsLayer.get() setBounds:rect];
}
-void GraphicsLayerCA::setBackfaceVisibility(bool visible)
+void GraphicsLayerCA::updateGeometryOrientation()
{
- if (m_backfaceVisibility == visible)
- return;
-
- GraphicsLayer::setBackfaceVisibility(visible);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [m_layer.get() setDoubleSided:visible];
- END_BLOCK_OBJC_EXCEPTIONS
+#if HAVE_MODERN_QUARTZCORE
+ switch (geometryOrientation()) {
+ case CompositingCoordinatesTopDown:
+ [m_layer.get() setGeometryFlipped:NO];
+ break;
+
+ case CompositingCoordinatesBottomUp:
+ [m_layer.get() setGeometryFlipped:YES];
+ break;
+ }
+ // Geometry orientation is mapped onto children transform in older QuartzCores,
+ // so is handled via setGeometryOrientation().
+#endif
}
-bool GraphicsLayerCA::setOpacity(float opacity, const Animation* transition, double beginTime)
+void GraphicsLayerCA::updateLayerAnimations()
{
- if (forceSoftwareAnimation())
- return false;
-
- float clampedOpacity = max(0.0f, min(opacity, 1.0f));
-
- bool opacitiesDiffer = (m_opacity != clampedOpacity);
-
- GraphicsLayer::setOpacity(clampedOpacity, transition, beginTime);
-
- int animIndex = findAnimationEntry(AnimatedPropertyOpacity, 0);
-
- // If we don't have a transition just set the opacity
- if (!transition || transition->isEmptyOrZeroDuration()) {
- // Three cases:
- // 1) no existing animation or transition: just set opacity
- // 2) existing transition: clear it and set opacity
- // 3) existing animation: just return
- //
- if (animIndex < 0 || m_animations[animIndex].isTransition()) {
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [primaryLayer() setOpacity:opacity];
- if (animIndex >= 0) {
- removeAllAnimationsForProperty(AnimatedPropertyOpacity);
- animIndex = -1;
- } else {
- String keyPath = propertyIdToString(AnimatedPropertyOpacity);
-
- // FIXME: using hardcoded '0' here. We should be clearing all animations. For now there is only 1.
- String animName = keyPath + "_0";
- [animatedLayer(AnimatedPropertyOpacity) removeAnimationForKey:animName];
+ if (m_transitionPropertiesToRemove.size()) {
+ HashSet<int>::const_iterator end = m_transitionPropertiesToRemove.end();
+ for (HashSet<AnimatedProperty>::const_iterator it = m_transitionPropertiesToRemove.begin(); it != end; ++it) {
+ AnimatedPropertyID currProperty = static_cast<AnimatedPropertyID>(*it);
+ // Remove all animations with this property in the key.
+ // We can't tell if this property is animating via a transition or animation here, but
+ // that's OK because the style system never sends both transitions and animations for the same property.
+ for (int index = 0; ; ++index) {
+ if (!removeAnimationFromLayer(currProperty, index))
+ break;
}
- END_BLOCK_OBJC_EXCEPTIONS
- } else {
- // We have an animation, so don't set the opacity directly.
- return false;
- }
- } else {
- // At this point, we know we have a transition. But if it is the same and
- // the opacity value has not changed, don't do anything.
- if (!opacitiesDiffer &&
- ((animIndex == -1) ||
- (m_animations[animIndex].isTransition() && *(m_animations[animIndex].animation()) == *transition))) {
- return false;
}
+
+ m_transitionPropertiesToRemove.clear();
}
-
- // If an animation is running, ignore this transition, but still save the value.
- if (animIndex >= 0 && !m_animations[animIndex].isTransition())
- return false;
- bool didAnimate = false;
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+ if (m_keyframeAnimationsToProcess.size()) {
+ AnimationsToProcessMap::const_iterator end = m_keyframeAnimationsToProcess.end();
+ for (AnimationsToProcessMap::const_iterator it = m_keyframeAnimationsToProcess.begin(); it != end; ++it) {
+ const String& currKeyframeName = it->first;
+ KeyframeAnimationsMap::iterator animationIt = m_runningKeyframeAnimations.find(currKeyframeName);
+ if (animationIt == m_runningKeyframeAnimations.end())
+ continue;
+
+ AnimationProcessingAction action = it->second;
+ const Vector<AnimationPair>& animations = animationIt->second;
+ for (size_t i = 0; i < animations.size(); ++i) {
+ const AnimationPair& currPair = animations[i];
+ switch (action) {
+ case Remove:
+ removeAnimationFromLayer(static_cast<AnimatedPropertyID>(currPair.first), currPair.second);
+ break;
+ case Pause:
+ pauseAnimationOnLayer(static_cast<AnimatedPropertyID>(currPair.first), currPair.second);
+ break;
+ }
+ }
+
+ if (action == Remove)
+ m_runningKeyframeAnimations.remove(currKeyframeName);
+ }
- NSNumber* fromOpacityValue = nil;
- NSNumber* toOpacityValue = [NSNumber numberWithFloat:opacity];
+ m_keyframeAnimationsToProcess.clear();
+ }
- if (transition && !transition->isEmptyOrZeroDuration()) {
- CALayer* presLayer = getPresentationLayer(primaryLayer());
- float fromOpacity = [presLayer opacity];
- fromOpacityValue = [NSNumber numberWithFloat:fromOpacity];
- setBasicAnimation(AnimatedPropertyOpacity, TransformOperation::NONE, 0, fromOpacityValue, toOpacityValue, true, transition, beginTime);
- didAnimate = true;
+ size_t numAnimations;
+ if ((numAnimations = m_uncomittedAnimations.size())) {
+ for (size_t i = 0; i < numAnimations; ++i) {
+ const LayerAnimation& pendingAnimation = m_uncomittedAnimations[i];
+ setAnimationOnLayer(pendingAnimation.m_animation.get(), pendingAnimation.m_property, pendingAnimation.m_index, pendingAnimation.m_beginTime);
+
+ if (!pendingAnimation.m_keyframesName.isEmpty()) {
+ // If this is a keyframe anim, we have to remember the association of keyframes name to property/index pairs,
+ // so we can remove the animations later if needed.
+ // For transitions, we can just generate animation names with property and index.
+ KeyframeAnimationsMap::iterator it = m_runningKeyframeAnimations.find(pendingAnimation.m_keyframesName);
+ if (it == m_runningKeyframeAnimations.end()) {
+ Vector<AnimationPair> firstPair;
+ firstPair.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index));
+ m_runningKeyframeAnimations.add(pendingAnimation.m_keyframesName, firstPair);
+ } else {
+ Vector<AnimationPair>& animPairs = it->second;
+ animPairs.append(AnimationPair(pendingAnimation.m_property, pendingAnimation.m_index));
+ }
+ }
+ }
+
+ m_uncomittedAnimations.clear();
}
+}
- END_BLOCK_OBJC_EXCEPTIONS
+void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedPropertyID property, int index, double beginTime)
+{
+ PlatformLayer* layer = animatedLayer(property);
+
+ if (beginTime) {
+ NSTimeInterval time = [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil];
+ [caAnim setBeginTime:time];
+ }
- return didAnimate;
+ String animationName = animationIdentifier(property, index);
+
+ [layer removeAnimationForKey:animationName];
+ [layer addAnimation:caAnim forKey:animationName];
}
-void GraphicsLayerCA::setNeedsDisplay()
+bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int index)
{
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+ PlatformLayer* layer = animatedLayer(property);
+
+ String animationName = animationIdentifier(property, index);
+
+ if (![layer animationForKey:animationName])
+ return false;
- if (drawsContent())
- [m_layer.get() setNeedsDisplay];
+ [layer removeAnimationForKey:animationName];
+ return true;
+}
- END_BLOCK_OBJC_EXCEPTIONS
+
+static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimation* to)
+{
+ [to setBeginTime:[from beginTime]];
+ [to setDuration:[from duration]];
+ [to setRepeatCount:[from repeatCount]];
+ [to setAutoreverses:[from autoreverses]];
+ [to setFillMode:[from fillMode]];
+ [to setRemovedOnCompletion:[from isRemovedOnCompletion]];
+ [to setAdditive:[from isAdditive]];
+ [to setTimingFunction:[from timingFunction]];
+
+#if HAVE_MODERN_QUARTZCORE
+ [to setValueFunction:[from valueFunction]];
+#endif
}
-void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect)
+void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int index)
{
- BEGIN_BLOCK_OBJC_EXCEPTIONS
-
- if (drawsContent())
- [m_layer.get() setNeedsDisplayInRect:rect];
+ PlatformLayer* layer = animatedLayer(property);
- END_BLOCK_OBJC_EXCEPTIONS
+ String animationName = animationIdentifier(property, index);
+
+ CAAnimation* caAnim = [layer animationForKey:animationName];
+ if (!caAnim)
+ return;
+
+ // Animations on the layer are immutable, so we have to clone and modify.
+ CAPropertyAnimation* pausedAnim = nil;
+ if ([caAnim isKindOfClass:[CAKeyframeAnimation class]]) {
+ CAKeyframeAnimation* existingKeyframeAnim = static_cast<CAKeyframeAnimation*>(caAnim);
+ CAKeyframeAnimation* newAnim = [CAKeyframeAnimation animationWithKeyPath:[existingKeyframeAnim keyPath]];
+ copyAnimationProperties(existingKeyframeAnim, newAnim);
+ [newAnim setValues:[existingKeyframeAnim values]];
+ [newAnim setKeyTimes:[existingKeyframeAnim keyTimes]];
+ [newAnim setTimingFunctions:[existingKeyframeAnim timingFunctions]];
+ pausedAnim = newAnim;
+ } else if ([caAnim isKindOfClass:[CABasicAnimation class]]) {
+ CABasicAnimation* existingPropertyAnim = static_cast<CABasicAnimation*>(caAnim);
+ CABasicAnimation* newAnim = [CABasicAnimation animationWithKeyPath:[existingPropertyAnim keyPath]];
+ copyAnimationProperties(existingPropertyAnim, newAnim);
+ [newAnim setFromValue:[existingPropertyAnim fromValue]];
+ [newAnim setToValue:[existingPropertyAnim toValue]];
+ pausedAnim = newAnim;
+ }
+
+ double t = [layer convertTime:currentTimeToMediaTime(currentTime()) fromLayer:nil];
+ [pausedAnim setSpeed:0];
+ [pausedAnim setTimeOffset:t - [caAnim beginTime]];
+ [layer addAnimation:pausedAnim forKey:animationName]; // This will replace the running animation.
}
+void GraphicsLayerCA::repaintLayerDirtyRects()
+{
+ if (!m_dirtyRects.size())
+ return;
+
+ for (size_t i = 0; i < m_dirtyRects.size(); ++i)
+ [m_layer.get() setNeedsDisplayInRect:m_dirtyRects[i]];
+
+ m_dirtyRects.clear();
+}
-bool GraphicsLayerCA::animateTransform(const TransformValueList& valueList, const IntSize& size, const Animation* anim, double beginTime, bool isTransition)
+bool GraphicsLayerCA::createAnimationFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime)
{
- if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
+ ASSERT(valueList.property() != AnimatedPropertyWebkitTransform);
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ bool isKeyframe = valueList.size() > 2;
+ bool valuesOK;
+
+ bool additive = false;
+ int animationIndex = 0;
+
+ CAPropertyAnimation* caAnimation;
+ if (isKeyframe) {
+ CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive);
+ valuesOK = setAnimationKeyframes(valueList, animation, keyframeAnim);
+ caAnimation = keyframeAnim;
+ } else {
+ CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive);
+ valuesOK = setAnimationEndpoints(valueList, animation, basicAnim);
+ caAnimation = basicAnim;
+ }
+
+ if (!valuesOK)
return false;
-
- TransformValueList::FunctionList functionList;
- bool isValid, hasBigRotation;
- valueList.makeFunctionList(functionList, isValid, hasBigRotation);
+
+ m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime));
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return true;
+}
+
+bool GraphicsLayerCA::createTransformAnimationsFromKeyframes(const KeyframeValueList& valueList, const Animation* animation, const String& keyframesName, double beginTime, const IntSize& boxSize)
+{
+ ASSERT(valueList.property() == AnimatedPropertyWebkitTransform);
+
+ TransformOperationList functionList;
+ bool listsMatch, hasBigRotation;
+ fetchTransformOperationList(valueList, functionList, listsMatch, hasBigRotation);
// We need to fall back to software animation if we don't have setValueFunction:, and
// we would need to animate each incoming transform function separately. This is the
// case if we have a rotation >= 180 or we have more than one transform function.
if ((hasBigRotation || functionList.size() > 1) && !caValueFunctionSupported())
return false;
+
+ bool validMatrices = true;
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ // If functionLists don't match we do a matrix animation, otherwise we do a component hardware animation.
+ // Also, we can't do component animation unless we have valueFunction, so we need to do matrix animation
+ // if that's not true as well.
+ bool isMatrixAnimation = !listsMatch || !caValueFunctionSupported();
- BEGIN_BLOCK_OBJC_EXCEPTIONS
-
- // Rules for animation:
- //
- // 1) If functionList is empty or we don't have a big rotation, we do a matrix animation. We could
- // use component animation for lists without a big rotation, but there is no need to, and this
- // is more efficient.
- //
- // 2) Otherwise we do a component hardware animation.
- bool isMatrixAnimation = !isValid || !hasBigRotation;
-
- // Set transform to identity since we are animating components and we need the base
- // to be the identity transform.
- TransformationMatrix t;
- CATransform3D toT3D;
- copyTransform(toT3D, t);
- [primaryLayer() setTransform:toT3D];
-
+ size_t numAnimations = isMatrixAnimation ? 1 : functionList.size();
bool isKeyframe = valueList.size() > 2;
-
+
// Iterate through the transform functions, sending an animation for each one.
- for (int functionIndex = 0; ; ++functionIndex) {
- if (functionIndex >= static_cast<int>(functionList.size()) && !isMatrixAnimation)
- break;
-
- TransformOperation::OperationType opType = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[functionIndex];
+ for (size_t animationIndex = 0; animationIndex < numAnimations; ++animationIndex) {
+ TransformOperation::OperationType transformOp = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[animationIndex];
+ CAPropertyAnimation* caAnimation;
+ // CA applies animations in reverse order (<rdar://problem/7095638>) so we need the last one we add (per property)
+ // to be non-additive.
+ bool additive = animationIndex < (numAnimations - 1);
if (isKeyframe) {
- NSMutableArray* timesArray = [[NSMutableArray alloc] init];
- NSMutableArray* valArray = [[NSMutableArray alloc] init];
- NSMutableArray* tfArray = [[NSMutableArray alloc] init];
-
- // Iterate through the keyframes, building arrays for the animation.
- for (Vector<TransformValue>::const_iterator it = valueList.values().begin(); it != valueList.values().end(); ++it) {
- const TransformValue& curValue = (*it);
-
- // fill in the key time and timing function
- [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
-
- const TimingFunction* tf = 0;
- if (curValue.timingFunction())
- tf = curValue.timingFunction();
- else if (anim->isTimingFunctionSet())
- tf = &anim->timingFunction();
-
- CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction(LinearTimingFunction));
- [tfArray addObject:timingFunction];
-
- // fill in the function
- if (isMatrixAnimation) {
- TransformationMatrix t;
- curValue.value()->apply(size, t);
- CATransform3D cat;
- copyTransform(cat, t);
- [valArray addObject:[NSValue valueWithCATransform3D:cat]];
- } else
- [valArray addObject:getTransformFunctionValue(curValue, functionIndex, size, opType)];
- }
-
- // We toss the last tfArray value because it has to one shorter than the others.
- [tfArray removeLastObject];
-
- setKeyframeAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, timesArray, valArray, tfArray, isTransition, anim, beginTime);
-
- [timesArray release];
- [valArray release];
- [tfArray release];
+ CAKeyframeAnimation* keyframeAnim = createKeyframeAnimation(animation, valueList.property(), additive);
+ validMatrices = setTransformAnimationKeyframes(valueList, animation, keyframeAnim, animationIndex, transformOp, isMatrixAnimation, boxSize);
+ caAnimation = keyframeAnim;
} else {
- // Is a transition
- id fromValue, toValue;
-
- if (isMatrixAnimation) {
- TransformationMatrix fromt, tot;
- valueList.at(0).value()->apply(size, fromt);
- valueList.at(1).value()->apply(size, tot);
-
- CATransform3D cat;
- copyTransform(cat, fromt);
- fromValue = [NSValue valueWithCATransform3D:cat];
- copyTransform(cat, tot);
- toValue = [NSValue valueWithCATransform3D:cat];
- } else {
- fromValue = getTransformFunctionValue(valueList.at(0), functionIndex, size, opType);
- toValue = getTransformFunctionValue(valueList.at(1), functionIndex, size, opType);
- }
-
- setBasicAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, fromValue, toValue, isTransition, anim, beginTime);
+ CABasicAnimation* basicAnim = createBasicAnimation(animation, valueList.property(), additive);
+ validMatrices = setTransformAnimationEndpoints(valueList, animation, basicAnim, animationIndex, transformOp, isMatrixAnimation, boxSize);
+ caAnimation = basicAnim;
}
- if (isMatrixAnimation)
+ if (!validMatrices)
break;
+
+ m_uncomittedAnimations.append(LayerAnimation(caAnimation, keyframesName, valueList.property(), animationIndex, beginTime));
}
- END_BLOCK_OBJC_EXCEPTIONS
- return true;
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return validMatrices;
}
-bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValueList& valueList, const Animation* animation, double beginTime)
+CABasicAnimation* GraphicsLayerCA::createBasicAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
{
- if (forceSoftwareAnimation() || valueList.size() < 2)
- return false;
-
- // if there is already is an animation for this property and it hasn't changed, ignore it.
- int i = findAnimationEntry(property, 0);
- if (i >= 0 && *m_animations[i].animation() == *animation) {
- m_animations[i].setIsCurrent();
- return false;
- }
-
- if (valueList.size() == 2) {
- float fromVal = valueList.at(0).value();
- float toVal = valueList.at(1).value();
- if (isnan(toVal) && isnan(fromVal))
- return false;
-
- // initialize the property to 0
- [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
- setBasicAnimation(property, TransformOperation::NONE, 0, isnan(fromVal) ? nil : [NSNumber numberWithFloat:fromVal], isnan(toVal) ? nil : [NSNumber numberWithFloat:toVal], false, animation, beginTime);
- return true;
- }
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
-
- NSMutableArray* timesArray = [[NSMutableArray alloc] init];
- NSMutableArray* valArray = [[NSMutableArray alloc] init];
- NSMutableArray* tfArray = [[NSMutableArray alloc] init];
-
- for (unsigned i = 0; i < valueList.values().size(); ++i) {
- const FloatValue& curValue = valueList.values()[i];
- [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]];
- [valArray addObject:[NSNumber numberWithFloat:curValue.value()]];
-
- const TimingFunction* tf = 0;
- if (curValue.timingFunction())
- tf = curValue.timingFunction();
- else if (animation->isTimingFunctionSet())
- tf = &animation->timingFunction();
-
- CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
- [tfArray addObject:timingFunction];
- }
-
- // We toss the last tfArray value because it has to one shorter than the others.
- [tfArray removeLastObject];
-
- // Initialize the property to 0.
- [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)];
- // Then set the animation.
- setKeyframeAnimation(property, TransformOperation::NONE, 0, timesArray, valArray, tfArray, false, animation, beginTime);
-
- [timesArray release];
- [valArray release];
- [tfArray release];
+ CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:propertyIdToString(property)];
+ setupAnimation(basicAnim, anim, additive);
+ return basicAnim;
+}
- END_BLOCK_OBJC_EXCEPTIONS
- return true;
+CAKeyframeAnimation* GraphicsLayerCA::createKeyframeAnimation(const Animation* anim, AnimatedPropertyID property, bool additive)
+{
+ CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:propertyIdToString(property)];
+ setupAnimation(keyframeAnim, anim, additive);
+ return keyframeAnim;
}
-void GraphicsLayerCA::setContentsToImage(Image* image)
+void GraphicsLayerCA::setupAnimation(CAPropertyAnimation* propertyAnim, const Animation* anim, bool additive)
{
- if (image) {
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- {
- if (!m_contentsLayer.get()) {
- WebLayer* imageLayer = [WebLayer layer];
-#ifndef NDEBUG
- [imageLayer setName:@"Image Layer"];
-#endif
- setContentsLayer(imageLayer);
- }
+ double duration = anim->duration();
+ if (duration <= 0)
+ duration = cAnimationAlmostZeroDuration;
- // FIXME: maybe only do trilinear if the image is being scaled down,
- // but then what if the layer size changes?
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
- [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear];
-#endif
- CGImageRef theImage = image->nativeImageForCurrentFrame();
- [m_contentsLayer.get() setContents:(id)theImage];
- }
- END_BLOCK_OBJC_EXCEPTIONS
- } else
- setContentsLayer(0);
+ float repeatCount = anim->iterationCount();
+ if (repeatCount == Animation::IterationCountInfinite)
+ repeatCount = FLT_MAX;
+ else if (anim->direction() == Animation::AnimationDirectionAlternate)
+ repeatCount /= 2;
- m_contentLayerForImageOrVideo = (image != 0);
-}
+ [propertyAnim setDuration:duration];
+ [propertyAnim setRepeatCount:repeatCount];
+ [propertyAnim setAutoreverses:anim->direction()];
+ [propertyAnim setRemovedOnCompletion:NO];
+ [propertyAnim setAdditive:additive];
+ [propertyAnim setFillMode:@"extended"];
-void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer)
-{
- setContentsLayer(videoLayer);
- m_contentLayerForImageOrVideo = (videoLayer != 0);
+ [propertyAnim setDelegate:m_animationDelegate.get()];
}
-void GraphicsLayerCA::clearContents()
+CAMediaTimingFunction* GraphicsLayerCA::timingFunctionForAnimationValue(const AnimationValue* animValue, const Animation* anim)
{
- if (m_contentLayerForImageOrVideo) {
- setContentsLayer(0);
- m_contentLayerForImageOrVideo = false;
- }
+ const TimingFunction* tf = 0;
+ if (animValue->timingFunction())
+ tf = animValue->timingFunction();
+ else if (anim->isTimingFunctionSet())
+ tf = &anim->timingFunction();
+
+ return getCAMediaTimingFunction(tf ? *tf : TimingFunction());
}
-void GraphicsLayerCA::updateContentsRect()
+bool GraphicsLayerCA::setAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, CABasicAnimation* basicAnim)
{
- if (m_client && m_contentsLayer) {
- IntRect contentRect = m_client->contentsBox(this);
-
- CGPoint point = CGPointMake(contentRect.x(),
- contentRect.y());
- CGRect rect = CGRectMake(0.0f,
- 0.0f,
- contentRect.width(),
- contentRect.height());
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [m_contentsLayer.get() setPosition:point];
- [m_contentsLayer.get() setBounds:rect];
- END_BLOCK_OBJC_EXCEPTIONS
+ id fromValue = nil;
+ id toValue = nil;
+
+ switch (valueList.property()) {
+ case AnimatedPropertyOpacity: {
+ const FloatAnimationValue* startVal = static_cast<const FloatAnimationValue*>(valueList.at(0));
+ const FloatAnimationValue* endVal = static_cast<const FloatAnimationValue*>(valueList.at(1));
+ fromValue = [NSNumber numberWithFloat:startVal->value()];
+ toValue = [NSNumber numberWithFloat:endVal->value()];
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED(); // we don't animate color yet
+ break;
}
+
+ // This codepath is used for 2-keyframe animations, so we still need to look in the start
+ // for a timing function.
+ CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
+ [basicAnim setTimingFunction:timingFunction];
+
+ [basicAnim setFromValue:fromValue];
+ [basicAnim setToValue:toValue];
+
+ return true;
}
-void GraphicsLayerCA::setBasicAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation* transition, double beginTime)
+bool GraphicsLayerCA::setAnimationKeyframes(const KeyframeValueList& valueList, const Animation* anim, CAKeyframeAnimation* keyframeAnim)
{
- ASSERT(fromVal || toVal);
+ RetainPtr<NSMutableArray> keyTimes(AdoptNS, [[NSMutableArray alloc] init]);
+ RetainPtr<NSMutableArray> values(AdoptNS, [[NSMutableArray alloc] init]);
+ RetainPtr<NSMutableArray> timingFunctions(AdoptNS, [[NSMutableArray alloc] init]);
- WebLayer* layer = animatedLayer(property);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
-
- // add an entry for this animation
- addAnimationEntry(property, index, isTransition, transition);
+ for (unsigned i = 0; i < valueList.size(); ++i) {
+ const AnimationValue* curValue = valueList.at(i);
+ [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue->keyTime()]];
- String keyPath = propertyIdToString(property);
- String animName = keyPath + "_" + String::number(index);
+ switch (valueList.property()) {
+ case AnimatedPropertyOpacity: {
+ const FloatAnimationValue* floatValue = static_cast<const FloatAnimationValue*>(curValue);
+ [values.get() addObject:[NSNumber numberWithFloat:floatValue->value()]];
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED(); // we don't animate color yet
+ break;
+ }
- CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:keyPath];
+ CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, anim);
+ [timingFunctions.get() addObject:timingFunction];
+ }
- double duration = transition->duration();
- if (duration <= 0)
- duration = cAnimationAlmostZeroDuration;
-
- float repeatCount = transition->iterationCount();
- if (repeatCount == Animation::IterationCountInfinite)
- repeatCount = FLT_MAX;
- else if (transition->direction() == Animation::AnimationDirectionAlternate)
- repeatCount /= 2;
-
- [basicAnim setDuration:duration];
- [basicAnim setRepeatCount:repeatCount];
- [basicAnim setAutoreverses:transition->direction()];
- [basicAnim setRemovedOnCompletion:NO];
-
- // Note that currently transform is the only property which has animations
- // with an index > 0.
- [basicAnim setAdditive:property == AnimatedPropertyWebkitTransform];
- [basicAnim setFillMode:@"extended"];
-#if HAVE_MODERN_QUARTZCORE
- if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
- [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
-#else
- UNUSED_PARAM(operationType);
-#endif
+ // We toss the last tfArray value because it has to one shorter than the others.
+ [timingFunctions.get() removeLastObject];
+
+ [keyframeAnim setKeyTimes:keyTimes.get()];
+ [keyframeAnim setValues:values.get()];
+ [keyframeAnim setTimingFunctions:timingFunctions.get()];
- // Set the delegate (and property value).
- int prop = isTransition ? property : AnimatedPropertyInvalid;
- [basicAnim setValue:[NSNumber numberWithInt:prop] forKey:WebAnimationCSSPropertyKey];
- [basicAnim setDelegate:m_animationDelegate.get()];
+ return true;
+}
- NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
- [basicAnim setBeginTime:bt];
+bool GraphicsLayerCA::setTransformAnimationEndpoints(const KeyframeValueList& valueList, const Animation* anim, CABasicAnimation* basicAnim, int functionIndex, TransformOperation::OperationType transformOp, bool isMatrixAnimation, const IntSize& boxSize)
+{
+ id fromValue;
+ id toValue;
+
+ ASSERT(valueList.size() == 2);
+ const TransformAnimationValue* startValue = static_cast<const TransformAnimationValue*>(valueList.at(0));
+ const TransformAnimationValue* endValue = static_cast<const TransformAnimationValue*>(valueList.at(1));
- if (fromVal)
- [basicAnim setFromValue:reinterpret_cast<id>(fromVal)];
- if (toVal)
- [basicAnim setToValue:reinterpret_cast<id>(toVal)];
+ if (isMatrixAnimation) {
+ TransformationMatrix fromTransform, toTransform;
+ startValue->value()->apply(boxSize, fromTransform);
+ endValue->value()->apply(boxSize, toTransform);
- const TimingFunction* tf = 0;
- if (transition->isTimingFunctionSet())
- tf = &transition->timingFunction();
+ // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
+ if (!fromTransform.isInvertible() || !toTransform.isInvertible())
+ return false;
+
+ CATransform3D caTransform;
+ copyTransform(caTransform, fromTransform);
+ fromValue = [NSValue valueWithCATransform3D:caTransform];
- CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction());
+ copyTransform(caTransform, toTransform);
+ toValue = [NSValue valueWithCATransform3D:caTransform];
+ } else {
+ fromValue = getTransformFunctionValue(startValue->value()->at(functionIndex), transformOp, boxSize);
+ toValue = getTransformFunctionValue(endValue->value()->at(functionIndex), transformOp, boxSize);
+ }
+
+ // This codepath is used for 2-keyframe animations, so we still need to look in the start
+ // for a timing function.
+ CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(valueList.at(0), anim);
[basicAnim setTimingFunction:timingFunction];
- // Send over the animation.
- [layer removeAnimationForKey:animName];
- [layer addAnimation:basicAnim forKey:animName];
-
- END_BLOCK_OBJC_EXCEPTIONS
+ [basicAnim setFromValue:fromValue];
+ [basicAnim setToValue:toValue];
+
+#if HAVE_MODERN_QUARTZCORE
+ if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOp))
+ [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
+#endif
+
+ return true;
}
-void GraphicsLayerCA::setKeyframeAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* keys, void* values, void* timingFunctions,
- bool isTransition, const Animation* anim, double beginTime)
+bool GraphicsLayerCA::setTransformAnimationKeyframes(const KeyframeValueList& valueList, const Animation* animation, CAKeyframeAnimation* keyframeAnim, int functionIndex, TransformOperation::OperationType transformOpType, bool isMatrixAnimation, const IntSize& boxSize)
{
- PlatformLayer* layer = animatedLayer(property);
-
- // Add an entry for this animation (which may change beginTime).
- addAnimationEntry(property, index, isTransition, anim);
+ RetainPtr<NSMutableArray> keyTimes(AdoptNS, [[NSMutableArray alloc] init]);
+ RetainPtr<NSMutableArray> values(AdoptNS, [[NSMutableArray alloc] init]);
+ RetainPtr<NSMutableArray> timingFunctions(AdoptNS, [[NSMutableArray alloc] init]);
- String keyPath = propertyIdToString(property);
- String animName = keyPath + "_" + String::number(index);
+ for (unsigned i = 0; i < valueList.size(); ++i) {
+ const TransformAnimationValue* curValue = static_cast<const TransformAnimationValue*>(valueList.at(i));
+ [keyTimes.get() addObject:[NSNumber numberWithFloat:curValue->keyTime()]];
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+ if (isMatrixAnimation) {
+ TransformationMatrix transform;
+ curValue->value()->apply(boxSize, transform);
- CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:keyPath];
+ // If any matrix is singular, CA won't animate it correctly. So fall back to software animation
+ if (!transform.isInvertible())
+ return false;
- double duration = anim->duration();
- if (duration <= 0)
- duration = cAnimationAlmostZeroDuration;
+ CATransform3D caTransform;
+ copyTransform(caTransform, transform);
+ [values.get() addObject:[NSValue valueWithCATransform3D:caTransform]];
+ } else {
+ const TransformOperation* transformOp = curValue->value()->at(functionIndex);
+ [values.get() addObject:getTransformFunctionValue(transformOp, transformOpType, boxSize)];
+ }
- float repeatCount = anim->iterationCount();
- if (repeatCount == Animation::IterationCountInfinite)
- repeatCount = FLT_MAX;
- else if (anim->direction() == Animation::AnimationDirectionAlternate)
- repeatCount /= 2;
+ CAMediaTimingFunction* timingFunction = timingFunctionForAnimationValue(curValue, animation);
+ [timingFunctions.get() addObject:timingFunction];
+ }
+
+ // We toss the last tfArray value because it has to one shorter than the others.
+ [timingFunctions.get() removeLastObject];
- [keyframeAnim setDuration:duration];
- [keyframeAnim setRepeatCount:repeatCount];
- [keyframeAnim setAutoreverses:anim->direction()];
- [keyframeAnim setRemovedOnCompletion:NO];
+ [keyframeAnim setKeyTimes:keyTimes.get()];
+ [keyframeAnim setValues:values.get()];
+ [keyframeAnim setTimingFunctions:timingFunctions.get()];
- // The first animation is non-additive, all the rest are additive.
- // Note that currently transform is the only property which has animations
- // with an index > 0.
- [keyframeAnim setAdditive:(property == AnimatedPropertyWebkitTransform) ? YES : NO];
- [keyframeAnim setFillMode:@"extended"];
#if HAVE_MODERN_QUARTZCORE
- if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType))
+ if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(transformOpType))
[keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]];
-#else
- UNUSED_PARAM(operationType);
#endif
-
- [keyframeAnim setKeyTimes:reinterpret_cast<id>(keys)];
- [keyframeAnim setValues:reinterpret_cast<id>(values)];
-
- // Set the delegate (and property value).
- int prop = isTransition ? property : AnimatedPropertyInvalid;
- [keyframeAnim setValue:[NSNumber numberWithInt: prop] forKey:WebAnimationCSSPropertyKey];
- [keyframeAnim setDelegate:m_animationDelegate.get()];
-
- NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0;
- [keyframeAnim setBeginTime:bt];
-
- // Set the timing functions, if any.
- if (timingFunctions != nil)
- [keyframeAnim setTimingFunctions:(id)timingFunctions];
-
- // Send over the animation.
- [layer removeAnimationForKey:animName];
- [layer addAnimation:keyframeAnim forKey:animName];
-
- END_BLOCK_OBJC_EXCEPTIONS
+ return true;
}
-void GraphicsLayerCA::suspendAnimations()
+void GraphicsLayerCA::suspendAnimations(double time)
{
- double t = currentTimeToMediaTime(currentTime());
+ double t = currentTimeToMediaTime(time ? time : currentTime());
[primaryLayer() setSpeed:0];
[primaryLayer() setTimeOffset:t];
}
@@ -1294,64 +1559,12 @@ void GraphicsLayerCA::resumeAnimations()
[primaryLayer() setTimeOffset:0];
}
-void GraphicsLayerCA::removeAnimation(int index, bool reset)
-{
- ASSERT(index >= 0);
-
- AnimatedPropertyID property = m_animations[index].property();
-
- // Set the value of the property and remove the animation.
- String keyPath = propertyIdToString(property);
- String animName = keyPath + "_" + String::number(m_animations[index].index());
- CALayer* layer = animatedLayer(property);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
-
- // If we are not resetting, it means we are pausing. So we need to get the current presentation
- // value into the property before we remove the animation.
- if (!reset) {
- // Put the current value into the property.
- CALayer* presLayer = [layer presentationLayer];
- if (presLayer)
- [layer setValue:[presLayer valueForKeyPath:keyPath] forKeyPath:keyPath];
-
- // Make sure the saved values accurately reflect the value in the layer.
- id val = [layer valueForKeyPath:keyPath];
- switch (property) {
- case AnimatedPropertyWebkitTransform:
- // FIXME: needs comment explaining why the m_transform is not obtained from the layer
- break;
- case AnimatedPropertyBackgroundColor:
- m_backgroundColor = Color(reinterpret_cast<CGColorRef>(val));
- break;
- case AnimatedPropertyOpacity:
- m_opacity = [val floatValue];
- break;
- case AnimatedPropertyInvalid:
- ASSERT_NOT_REACHED();
- break;
- }
- }
-
- // If we have reached the end of an animation, we don't want to actually remove the
- // animation from the CALayer. At some point we will be setting the property to its
- // unanimated value and at that point we will remove the animation. That will avoid
- // any flashing between the time the animation is removed and the property is set.
- if (!reset || m_animations[index].isTransition())
- [layer removeAnimationForKey:animName];
-
- END_BLOCK_OBJC_EXCEPTIONS
-
- // Remove the animation entry.
- m_animations.remove(index);
-}
-
-PlatformLayer* GraphicsLayerCA::hostLayerForSublayers() const
+WebLayer* GraphicsLayerCA::hostLayerForSublayers() const
{
return m_transformLayer ? m_transformLayer.get() : m_layer.get();
}
-PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const
+WebLayer* GraphicsLayerCA::layerForSuperlayer() const
{
if (m_transformLayer)
return m_transformLayer.get();
@@ -1359,6 +1572,11 @@ PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const
return m_layer.get();
}
+CALayer* GraphicsLayerCA::animatedLayer(AnimatedPropertyID property) const
+{
+ return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer();
+}
+
PlatformLayer* GraphicsLayerCA::platformLayer() const
{
return primaryLayer();
@@ -1391,16 +1609,7 @@ void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
END_BLOCK_OBJC_EXCEPTIONS
}
-
-void GraphicsLayerCA::setZPosition(float position)
-{
- GraphicsLayer::setZPosition(position);
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
- [primaryLayer() setZPosition:position];
- END_BLOCK_OBJC_EXCEPTIONS
-}
-#endif
+#endif // NDEBUG
bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
{
@@ -1411,21 +1620,21 @@ bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension;
}
-void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
+void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
{
- if (userTiledLayer == m_usingTiledLayer)
+ if (useTiledLayer == m_usingTiledLayer)
return;
CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize);
- BEGIN_BLOCK_OBJC_EXCEPTIONS
-
RetainPtr<CALayer> oldLayer = m_layer.get();
- Class layerClass = userTiledLayer ? [WebTiledLayer self] : [WebLayer self];
+ Class layerClass = useTiledLayer ? [WebTiledLayer self] : [WebLayer self];
m_layer.adoptNS([[layerClass alloc] init]);
- if (userTiledLayer) {
+ m_usingTiledLayer = useTiledLayer;
+
+ if (useTiledLayer) {
WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get();
[tiledLayer setTileSize:tileSize];
[tiledLayer setLevelsOfDetail:1];
@@ -1435,24 +1644,35 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
[tiledLayer setContentsGravity:@"bottomLeft"];
else
[tiledLayer setContentsGravity:@"topLeft"];
+
+#if !HAVE_MODERN_QUARTZCORE
+ // Tiled layer has issues with flipped coordinates.
+ setContentsOrientation(CompositingCoordinatesTopDown);
+#endif
+ } else {
+#if !HAVE_MODERN_QUARTZCORE
+ setContentsOrientation(defaultContentsOrientation());
+#endif
}
[m_layer.get() setLayerOwner:this];
[m_layer.get() setSublayers:[oldLayer.get() sublayers]];
[[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
+
+ updateContentsTransform();
+
+ updateLayerPosition();
+ updateLayerSize();
+ updateAnchorPoint();
+ updateTransform();
+ updateChildrenTransform();
+ updateMasksToBounds();
+ updateContentsOpaque();
+ updateBackfaceVisibility();
+ updateLayerBackgroundColor();
- [m_layer.get() setBounds:[oldLayer.get() bounds]];
- [m_layer.get() setPosition:[oldLayer.get() position]];
- [m_layer.get() setAnchorPoint:[oldLayer.get() anchorPoint]];
- [m_layer.get() setOpaque:[oldLayer.get() isOpaque]];
- [m_layer.get() setOpacity:[oldLayer.get() opacity]];
- [m_layer.get() setTransform:[oldLayer.get() transform]];
- [m_layer.get() setSublayerTransform:[oldLayer.get() sublayerTransform]];
- [m_layer.get() setDoubleSided:[oldLayer.get() isDoubleSided]];
-#ifndef NDEBUG
- [m_layer.get() setZPosition:[oldLayer.get() zPosition]];
-#endif
+ updateOpacityOnLayer();
#ifndef NDEBUG
String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name;
@@ -1467,68 +1687,84 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer)
// need to tell new layer to draw itself
setNeedsDisplay();
- END_BLOCK_OBJC_EXCEPTIONS
-
- m_usingTiledLayer = userTiledLayer;
-
#ifndef NDEBUG
updateDebugIndicators();
#endif
}
-void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer)
+GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const
{
- if (contentsLayer == m_contentsLayer)
- return;
-
- BEGIN_BLOCK_OBJC_EXCEPTIONS
+#if !HAVE_MODERN_QUARTZCORE
+ // Older QuartzCore does not support -geometryFlipped, so we manually flip the root
+ // layer geometry, and then flip the contents of each layer back so that the CTM for CG
+ // is unflipped, allowing it to do the correct font auto-hinting.
+ return CompositingCoordinatesBottomUp;
+#else
+ return CompositingCoordinatesTopDown;
+#endif
+}
- if (m_contentsLayer) {
- [m_contentsLayer.get() removeFromSuperlayer];
- m_contentsLayer = 0;
+void GraphicsLayerCA::updateContentsTransform()
+{
+#if !HAVE_MODERN_QUARTZCORE
+ if (contentsOrientation() == CompositingCoordinatesBottomUp) {
+ CGAffineTransform contentsTransform = CGAffineTransformMakeScale(1, -1);
+ contentsTransform = CGAffineTransformTranslate(contentsTransform, 0, -[m_layer.get() bounds].size.height);
+ [m_layer.get() setContentsTransform:contentsTransform];
}
-
- if (contentsLayer) {
- // Turn off implicit animations on the inner layer.
- [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
-
- m_contentsLayer.adoptNS([contentsLayer retain]);
-
- bool needToFlip = GraphicsLayer::compositingCoordinatesOrientation() == GraphicsLayer::CompositingCoordinatesBottomUp;
- CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero;
-
- // If the layer world is flipped, we need to un-flip the contents layer
- if (needToFlip) {
- CATransform3D flipper = {
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, -1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f};
- [m_contentsLayer.get() setTransform:flipper];
- }
- [m_contentsLayer.get() setAnchorPoint:anchorPoint];
+#else
+ ASSERT(contentsOrientation() == CompositingCoordinatesTopDown);
+#endif
+}
- // Insert the content layer first. Video elements require this, because they have
- // shadow content that must display in front of the video.
- [m_layer.get() insertSublayer:m_contentsLayer.get() atIndex:0];
+void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer)
+{
+ // Turn off implicit animations on the inner layer.
+ [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]];
- updateContentsRect();
+ if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) {
+ CATransform3D flipper = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ [contentsLayer setTransform:flipper];
+ [contentsLayer setAnchorPoint:CGPointMake(0.0f, 1.0f)];
+ } else
+ [contentsLayer setAnchorPoint:CGPointZero];
#ifndef NDEBUG
- if (showDebugBorders()) {
- setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180));
- [m_contentsLayer.get() setBorderWidth:1.0f];
- }
-#endif
+ if (showDebugBorders()) {
+ setLayerBorderColor(contentsLayer, Color(0, 0, 128, 180));
+ [contentsLayer setBorderWidth:1.0f];
}
-#ifndef NDEBUG
- updateDebugIndicators();
#endif
+}
- END_BLOCK_OBJC_EXCEPTIONS
+void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
+{
+ [(preserves3D() ? m_layer.get() : primaryLayer()) setOpacity:accumulatedOpacity];
}
-} // namespace WebCore
+void GraphicsLayerCA::updateOpacityOnLayer()
+{
+#if !HAVE_MODERN_QUARTZCORE
+ // Distribute opacity either to our own layer or to our children. We pass in the
+ // contribution from our parent(s).
+ distributeOpacity(parent() ? parent()->accumulatedOpacity() : 1);
+#else
+ [primaryLayer() setOpacity:m_opacity];
+#endif
+}
+void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
+{
+ if (!m_uncommittedChanges && m_client)
+ m_client->notifySyncRequired(this);
+
+ m_uncommittedChanges |= flags;
+}
+
+} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index f90f258..54eea00 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -37,12 +37,14 @@
#import <QTKit/QTTime.h>
@class QTMovie;
@class QTMovieView;
+@class QTMovieLayer;
@class QTVideoRendererWebKitOnly;
@class WebCoreMovieObserver;
#else
class QTMovie;
class QTMovieView;
class QTTime;
+class QTMovieLayer;
class QTVideoRendererWebKitOnly;
class WebCoreMovieObserver;
#endif
@@ -93,6 +95,7 @@ private:
void setRate(float);
void setVolume(float);
+ void setPreservesPitch(bool);
void setEndTime(float time);
@@ -111,14 +114,37 @@ private:
void setSize(const IntSize&);
void paint(GraphicsContext*, const IntRect&);
+ void paintCurrentFrameInContext(GraphicsContext*, const IntRect&);
+
+#if USE(ACCELERATED_COMPOSITING)
+ bool supportsAcceleratedRendering() const;
+ void acceleratedRenderingStateChanged();
+#endif
+
+ bool hasSingleSecurityOrigin() const;
+ MediaPlayer::MovieLoadType movieLoadType() const;
void createQTMovie(const String& url);
+ void createQTMovie(NSURL *, NSDictionary *movieAttributes);
+
+ enum MediaRenderingMode { MediaRenderingNone, MediaRenderingMovieView, MediaRenderingSoftwareRenderer, MediaRenderingMovieLayer };
+ MediaRenderingMode currentRenderingMode() const;
+ MediaRenderingMode preferredRenderingMode() const;
+
void setUpVideoRendering();
void tearDownVideoRendering();
+ bool hasSetUpVideoRendering() const;
+
void createQTMovieView();
void detachQTMovieView();
- void createQTVideoRenderer();
+
+ enum QTVideoRendererMode { QTVideoRendererModeDefault, QTVideoRendererModeListensForNewImages };
+ void createQTVideoRenderer(QTVideoRendererMode rendererMode);
void destroyQTVideoRenderer();
+
+ void createQTMovieLayer();
+ void destroyQTMovieLayer();
+
QTTime createQTTime(float time) const;
void updateStates();
@@ -132,6 +158,8 @@ private:
void cacheMovieScale();
bool metaDataAvailable() const { return m_qtMovie && m_readyState >= MediaPlayer::HaveMetadata; }
+ bool isReadyForRendering() const;
+
MediaPlayer* m_player;
RetainPtr<QTMovie> m_qtMovie;
RetainPtr<QTMovieView> m_qtMovieView;
@@ -149,7 +177,10 @@ private:
unsigned m_enabledTrackCount;
unsigned m_totalTrackCount;
bool m_hasUnsupportedTracks;
- float m_duration;
+ float m_reportedDuration;
+ float m_cachedDuration;
+ float m_timeToRestore;
+ RetainPtr<QTMovieLayer> m_qtVideoLayer;
#if DRAW_FRAME_RATE
int m_frameCountWhilePlaying;
double m_timeStartedPlaying;
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index dd41ed3..c1d7fcb 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -44,6 +44,10 @@
#import <objc/objc-runtime.h>
#import <wtf/UnusedParam.h>
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayer.h"
+#endif
+
#if DRAW_FRAME_RATE
#import "Font.h"
#import "Frame.h"
@@ -67,6 +71,7 @@ SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (tim
SOFT_LINK_CLASS(QTKit, QTMovie)
SOFT_LINK_CLASS(QTKit, QTMovieView)
+SOFT_LINK_CLASS(QTKit, QTMovieLayer)
SOFT_LINK_POINTER(QTKit, QTTrackMediaTypeAttribute, NSString *)
SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *)
@@ -85,6 +90,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *)
SOFT_LINK_POINTER(QTKit, QTMovieNaturalSizeAttribute, NSString *)
SOFT_LINK_POINTER(QTKit, QTMovieCurrentSizeAttribute, NSString *)
SOFT_LINK_POINTER(QTKit, QTMoviePreventExternalURLLinksAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieRateChangesPreservePitchAttribute, NSString *)
SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *)
SOFT_LINK_POINTER(QTKit, QTMovieSizeDidChangeNotification, NSString *)
SOFT_LINK_POINTER(QTKit, QTMovieTimeDidChangeNotification, NSString *)
@@ -100,6 +106,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *)
#define QTMovie getQTMovieClass()
#define QTMovieView getQTMovieViewClass()
+#define QTMovieLayer getQTMovieLayerClass()
#define QTTrackMediaTypeAttribute getQTTrackMediaTypeAttribute()
#define QTMediaTypeAttribute getQTMediaTypeAttribute()
@@ -118,6 +125,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *)
#define QTMovieNaturalSizeAttribute getQTMovieNaturalSizeAttribute()
#define QTMovieCurrentSizeAttribute getQTMovieCurrentSizeAttribute()
#define QTMoviePreventExternalURLLinksAttribute getQTMoviePreventExternalURLLinksAttribute()
+#define QTMovieRateChangesPreservePitchAttribute getQTMovieRateChangesPreservePitchAttribute()
#define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification()
#define QTMovieSizeDidChangeNotification getQTMovieSizeDidChangeNotification()
#define QTMovieTimeDidChangeNotification getQTMovieTimeDidChangeNotification()
@@ -201,7 +209,9 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_enabledTrackCount(0)
, m_totalTrackCount(0)
, m_hasUnsupportedTracks(false)
- , m_duration(-1.0f)
+ , m_reportedDuration(-1.0f)
+ , m_cachedDuration(-1.0f)
+ , m_timeToRestore(-1.0f)
#if DRAW_FRAME_RATE
, m_frameCountWhilePlaying(0)
, m_timeStartedPlaying(0)
@@ -220,41 +230,49 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
void MediaPlayerPrivate::createQTMovie(const String& url)
{
+ NSURL *cocoaURL = KURL(url);
+ NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ cocoaURL, QTMovieURLAttribute,
+ [NSNumber numberWithBool:m_player->preservesPitch()], QTMovieRateChangesPreservePitchAttribute,
+ [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute,
+ [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute,
+ [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute,
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute",
+#endif
+#ifndef BUILDING_ON_TIGER
+ QTMovieApertureModeClean, QTMovieApertureModeAttribute,
+#endif
+ nil];
+
+ createQTMovie(cocoaURL, movieAttributes);
+}
+
+void MediaPlayerPrivate::createQTMovie(NSURL *url, NSDictionary *movieAttributes)
+{
[[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
+ bool recreating = false;
if (m_qtMovie) {
+ recreating = true;
destroyQTVideoRenderer();
m_qtMovie = 0;
}
- // Disable streaming support for now, <rdar://problem/5693967>
- if (protocolIs(url, "rtsp"))
+ // Disable rtsp streams for now, <rdar://problem/5693967>
+ if (protocolIs([url scheme], "rtsp"))
return;
-
- NSURL *cocoaURL = KURL(url);
- NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
- cocoaURL, QTMovieURLAttribute,
- [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute,
- [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute,
- [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute,
-#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
- [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute",
-#endif
-#ifndef BUILDING_ON_TIGER
- QTMovieApertureModeClean, QTMovieApertureModeAttribute,
-#endif
- nil];
NSError *error = nil;
m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]);
- // FIXME: Find a proper way to detect streaming content.
- m_isStreaming = protocolIs(url, "rtsp");
-
if (!m_qtMovie)
return;
[m_qtMovie.get() setVolume:m_player->volume()];
+
+ if (recreating && hasVideo())
+ createQTVideoRenderer(QTVideoRendererModeListensForNewImages);
[[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
selector:@selector(loadStateChanged:)
@@ -370,7 +388,7 @@ void MediaPlayerPrivate::detachQTMovieView()
}
}
-void MediaPlayerPrivate::createQTVideoRenderer()
+void MediaPlayerPrivate::createQTVideoRenderer(QTVideoRendererMode rendererMode)
{
destroyQTVideoRenderer();
@@ -381,11 +399,13 @@ void MediaPlayerPrivate::createQTVideoRenderer()
// associate our movie with our instance of QTVideoRendererWebKitOnly
[(id<WebKitVideoRenderingDetails>)m_qtVideoRenderer.get() setMovie:m_qtMovie.get()];
- // listen to QTVideoRendererWebKitOnly's QTVideoRendererWebKitOnlyNewImageDidBecomeAvailableNotification
- [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
- selector:@selector(newImageAvailable:)
- name:QTVideoRendererWebKitOnlyNewImageAvailableNotification
- object:m_qtVideoRenderer.get()];
+ if (rendererMode == QTVideoRendererModeListensForNewImages) {
+ // listen to QTVideoRendererWebKitOnly's QTVideoRendererWebKitOnlyNewImageDidBecomeAvailableNotification
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(newImageAvailable:)
+ name:QTVideoRendererWebKitOnlyNewImageAvailableNotification
+ object:m_qtVideoRenderer.get()];
+ }
}
void MediaPlayerPrivate::destroyQTVideoRenderer()
@@ -404,23 +424,114 @@ void MediaPlayerPrivate::destroyQTVideoRenderer()
m_qtVideoRenderer = nil;
}
-void MediaPlayerPrivate::setUpVideoRendering()
+void MediaPlayerPrivate::createQTMovieLayer()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_qtMovie)
+ return;
+
+ ASSERT(supportsAcceleratedRendering());
+
+ if (!m_qtVideoLayer) {
+ m_qtVideoLayer.adoptNS([[QTMovieLayer alloc] init]);
+ if (!m_qtVideoLayer)
+ return;
+
+ [m_qtVideoLayer.get() setMovie:m_qtMovie.get()];
+#ifndef NDEBUG
+ [(CALayer *)m_qtVideoLayer.get() setName:@"Video layer"];
+#endif
+
+ // Hang the video layer from the render layer, if we have one yet. If not, we'll do this
+ // later via acceleratedRenderingStateChanged().
+ GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
+ if (videoGraphicsLayer)
+ videoGraphicsLayer->setContentsToVideo((PlatformLayer *)m_qtVideoLayer.get());
+ }
+#endif
+}
+
+void MediaPlayerPrivate::destroyQTMovieLayer()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_qtVideoLayer)
+ return;
+
+ // disassociate our movie from our instance of QTMovieLayer
+ [m_qtVideoLayer.get() setMovie:nil];
+ m_qtVideoLayer = nil;
+#endif
+}
+
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::currentRenderingMode() const
+{
+ if (m_qtMovieView)
+ return MediaRenderingMovieView;
+
+ if (m_qtVideoLayer)
+ return MediaRenderingMovieLayer;
+
+ if (m_qtVideoRenderer)
+ return MediaRenderingSoftwareRenderer;
+
+ return MediaRenderingNone;
+}
+
+MediaPlayerPrivate::MediaRenderingMode MediaPlayerPrivate::preferredRenderingMode() const
{
if (!m_player->frameView() || !m_qtMovie)
+ return MediaRenderingNone;
+
+ if (m_player->inMediaDocument() || !QTVideoRendererClass())
+ return MediaRenderingMovieView;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
+ return MediaRenderingMovieLayer;
+#endif
+
+ return MediaRenderingSoftwareRenderer;
+}
+
+void MediaPlayerPrivate::setUpVideoRendering()
+{
+ MediaRenderingMode currentMode = currentRenderingMode();
+ MediaRenderingMode preferredMode = preferredRenderingMode();
+ if (currentMode == preferredMode && currentMode != MediaRenderingNone)
return;
- if (m_player->inMediaDocument() || !QTVideoRendererClass() )
+ if (currentMode != MediaRenderingNone)
+ tearDownVideoRendering();
+
+ switch (preferredMode) {
+ case MediaRenderingMovieView:
createQTMovieView();
- else
- createQTVideoRenderer();
+ break;
+ case MediaRenderingNone:
+ case MediaRenderingSoftwareRenderer:
+ createQTVideoRenderer(QTVideoRendererModeListensForNewImages);
+ break;
+ case MediaRenderingMovieLayer:
+ createQTMovieLayer();
+ break;
+ }
}
void MediaPlayerPrivate::tearDownVideoRendering()
{
if (m_qtMovieView)
detachQTMovieView();
- else
+ if (m_qtVideoRenderer)
destroyQTVideoRenderer();
+ if (m_qtVideoLayer)
+ destroyQTMovieLayer();
+}
+
+bool MediaPlayerPrivate::hasSetUpVideoRendering() const
+{
+ return m_qtMovieView
+ || m_qtVideoLayer
+ || m_qtVideoRenderer;
}
QTTime MediaPlayerPrivate::createQTTime(float time) const
@@ -481,6 +592,10 @@ float MediaPlayerPrivate::duration() const
{
if (!metaDataAvailable())
return 0;
+
+ if (m_cachedDuration != -1.0f)
+ return m_cachedDuration;
+
QTTime time = [m_qtMovie.get() duration];
if (time.flags == kQTTimeIsIndefinite)
return numeric_limits<float>::infinity();
@@ -497,6 +612,10 @@ float MediaPlayerPrivate::currentTime() const
void MediaPlayerPrivate::seek(float time)
{
+ // Nothing to do if we are already in the middle of a seek to the same time.
+ if (time == m_seekTo)
+ return;
+
cancelSeek();
if (!metaDataAvailable())
@@ -506,7 +625,7 @@ void MediaPlayerPrivate::seek(float time)
time = duration();
m_seekTo = time;
- if (maxTimeLoaded() >= m_seekTo)
+ if (maxTimeSeekable() >= m_seekTo)
doSeek();
else
m_seekTimer.start(0, 0.5f);
@@ -518,12 +637,16 @@ void MediaPlayerPrivate::doSeek()
// setCurrentTime generates several event callbacks, update afterwards
[m_objcObserver.get() setDelayCallbacks:YES];
float oldRate = [m_qtMovie.get() rate];
- [m_qtMovie.get() setRate:0];
+
+ if (oldRate)
+ [m_qtMovie.get() setRate:0];
[m_qtMovie.get() setCurrentTime:qttime];
- float timeAfterSeek = currentTime();
+
// restore playback only if not at end, othewise QTMovie will loop
+ float timeAfterSeek = currentTime();
if (oldRate && timeAfterSeek < duration())
[m_qtMovie.get() setRate:oldRate];
+
cancelSeek();
[m_objcObserver.get() setDelayCallbacks:NO];
}
@@ -542,8 +665,8 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
m_player->timeChanged();
return;
}
-
- if (maxTimeLoaded() >= m_seekTo)
+
+ if (maxTimeSeekable() >= m_seekTo)
doSeek();
else {
MediaPlayer::NetworkState state = networkState();
@@ -607,8 +730,25 @@ void MediaPlayerPrivate::setRate(float rate)
{
if (!metaDataAvailable())
return;
- if (!paused())
- [m_qtMovie.get() setRate:rate];
+ [m_qtMovie.get() setRate:rate];
+}
+
+void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_qtMovie)
+ return;
+
+ // QTMovieRateChangesPreservePitchAttribute cannot be changed dynamically after QTMovie creation.
+ // If the passed in value is different than what already exists, we need to recreate the QTMovie for it to take effect.
+ if ([[m_qtMovie.get() attributeForKey:QTMovieRateChangesPreservePitchAttribute] boolValue] == preservesPitch)
+ return;
+
+ NSDictionary *movieAttributes = [[m_qtMovie.get() movieAttributes] mutableCopy];
+ ASSERT(movieAttributes);
+ [movieAttributes setValue:[NSNumber numberWithBool:preservesPitch] forKey:QTMovieRateChangesPreservePitchAttribute];
+ m_timeToRestore = currentTime();
+
+ createQTMovie([movieAttributes valueForKey:QTMovieURLAttribute], movieAttributes);
}
int MediaPlayerPrivate::dataRate() const
@@ -621,8 +761,7 @@ int MediaPlayerPrivate::dataRate() const
float MediaPlayerPrivate::maxTimeBuffered() const
{
- // rtsp streams are not buffered
- return m_isStreaming ? 0 : maxTimeLoaded();
+ return maxTimeLoaded();
}
float MediaPlayerPrivate::maxTimeSeekable() const
@@ -701,6 +840,11 @@ void MediaPlayerPrivate::cacheMovieScale()
m_scaleFactor.setHeight(initialSize.height / naturalSize.height);
}
+bool MediaPlayerPrivate::isReadyForRendering() const
+{
+ return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
+}
+
void MediaPlayerPrivate::updateStates()
{
MediaPlayer::NetworkState oldNetworkState = m_networkState;
@@ -711,19 +855,33 @@ void MediaPlayerPrivate::updateStates()
if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) {
disableUnsupportedTracks();
if (m_player->inMediaDocument()) {
- if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) {
- // This is a type of media that we do not handle directly with a <video>
- // element, likely streamed media or QuickTime VR. Tell the MediaPlayerClient
+ if (!m_enabledTrackCount || m_hasUnsupportedTracks) {
+ // This has a type of media that we do not handle directly with a <video>
+ // element, eg. a rtsp track or QuickTime VR. Tell the MediaPlayerClient
// that we noticed.
sawUnsupportedTracks();
return;
}
- } else if (!m_enabledTrackCount) {
+ } else if (!m_enabledTrackCount)
loadState = QTMovieLoadStateError;
- }
-
- if (loadState != QTMovieLoadStateError)
+
+ if (loadState != QTMovieLoadStateError) {
cacheMovieScale();
+ MediaPlayer::MovieLoadType movieType = movieLoadType();
+ m_isStreaming = movieType == MediaPlayer::StoredStream || movieType == MediaPlayer::LiveStream;
+ }
+ }
+
+ // If this movie is reloading and we mean to restore the current time/rate, this might be the right time to do it.
+ if (loadState >= QTMovieLoadStateLoaded && oldNetworkState < MediaPlayer::Loaded && m_timeToRestore != -1.0f) {
+ QTTime qttime = createQTTime(m_timeToRestore);
+ m_timeToRestore = -1.0f;
+
+ // Disable event callbacks from setCurrentTime for restoring time in a recreated video
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ [m_qtMovie.get() setCurrentTime:qttime];
+ [m_qtMovie.get() setRate:m_player->rate()];
+ [m_objcObserver.get() setDelayCallbacks:NO];
}
BOOL completelyLoaded = !m_isStreaming && (loadState >= QTMovieLoadStateComplete);
@@ -751,6 +909,8 @@ void MediaPlayerPrivate::updateStates()
m_readyState = MediaPlayer::HaveNothing;
m_networkState = MediaPlayer::Loading;
} else {
+ // Loading or decoding failed.
+
if (m_player->inMediaDocument()) {
// Something went wrong in the loading of media within a standalone file.
// This can occur with chained refmovies pointing to streamed media.
@@ -773,23 +933,28 @@ void MediaPlayerPrivate::updateStates()
}
}
+ if (isReadyForRendering() && !hasSetUpVideoRendering())
+ setUpVideoRendering();
+
if (seeking())
- m_readyState = MediaPlayer::HaveNothing;
+ m_readyState = m_readyState >= MediaPlayer::HaveMetadata ? MediaPlayer::HaveMetadata : MediaPlayer::HaveNothing;
+
+ // Streaming movies don't use the network when paused.
+ if (m_isStreaming && m_readyState >= MediaPlayer::HaveMetadata && m_networkState >= MediaPlayer::Loading && [m_qtMovie.get() rate] == 0)
+ m_networkState = MediaPlayer::Idle;
if (m_networkState != oldNetworkState)
m_player->networkStateChanged();
+
if (m_readyState != oldReadyState)
m_player->readyStateChanged();
- if (loadState >= QTMovieLoadStateLoaded && (!m_qtMovieView && !m_qtVideoRenderer) && m_player->visible())
- setUpVideoRendering();
-
if (loadState >= QTMovieLoadStateLoaded) {
float dur = duration();
- if (dur != m_duration) {
- if (m_duration != -1.0f)
+ if (dur != m_reportedDuration) {
+ if (m_reportedDuration != -1.0f)
m_player->durationChanged();
- m_duration = dur;
+ m_reportedDuration = dur;
}
}
}
@@ -820,6 +985,13 @@ void MediaPlayerPrivate::timeChanged()
if (m_hasUnsupportedTracks)
return;
+ // It may not be possible to seek to a specific time in a streamed movie. When seeking in a
+ // stream QuickTime sets the movie time to closest time possible and posts a timechanged
+ // notification. Update m_seekTo so we can detect when the seek completes.
+ if (m_seekTo != -1)
+ m_seekTo = currentTime();
+
+ m_timeToRestore = -1.0f;
updateStates();
m_player->timeChanged();
}
@@ -833,6 +1005,12 @@ void MediaPlayerPrivate::didEnd()
#if DRAW_FRAME_RATE
m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
#endif
+
+ // Hang onto the current time and use it as duration from now on since QuickTime is telling us we
+ // are at the end. Do this because QuickTime sometimes reports one time for duration and stops
+ // playback at another time, which causes problems in HTMLMediaElement.
+ m_cachedDuration = currentTime();
+
updateStates();
m_player->timeChanged();
}
@@ -877,6 +1055,20 @@ void MediaPlayerPrivate::repaint()
m_player->repaint();
}
+void MediaPlayerPrivate::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& r)
+{
+ id qtVideoRenderer = m_qtVideoRenderer.get();
+ if (!qtVideoRenderer && currentRenderingMode() == MediaRenderingMovieLayer) {
+ // We're being told to render into a context, but we already have the
+ // MovieLayer going. This probably means we've been called from <canvas>.
+ // Set up a QTVideoRenderer to use, but one that doesn't register for
+ // update callbacks. That way, it won't bother us asking to repaint.
+ createQTVideoRenderer(QTVideoRendererModeDefault);
+ qtVideoRenderer = m_qtVideoRenderer.get();
+ }
+ paint(context, r);
+}
+
void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
{
if (context->paintingDisabled() || m_hasUnsupportedTracks)
@@ -944,12 +1136,11 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
TextRun textRun(text.characters(), text.length());
const Color color(255, 0, 0);
context->scale(FloatSize(1.0f, -1.0f));
- context->setFont(styleToUse->font());
context->setStrokeColor(color);
context->setStrokeStyle(SolidStroke);
context->setStrokeThickness(1.0f);
context->setFillColor(color);
- context->drawText(textRun, IntPoint(2, -3));
+ context->drawText(styleToUse->font(), textRun, IntPoint(2, -3));
}
}
#endif
@@ -1029,7 +1220,7 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c
// We check the "modern" type cache first, as it doesn't require QTKitServer to start.
if (mimeModernTypesCache().contains(type) || mimeCommonTypesCache().contains(type))
- return (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported);
+ return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
return MediaPlayer::IsNotSupported;
}
@@ -1092,8 +1283,10 @@ void MediaPlayerPrivate::disableUnsupportedTracks()
// Check to see if the track is disabled already, we should move along.
// We don't need to re-disable it.
- if (![track isEnabled])
+ if (![track isEnabled]) {
+ --m_enabledTrackCount;
continue;
+ }
// Get the track's media type.
NSString *mediaType = [track attributeForKey:QTTrackMediaTypeAttribute];
@@ -1105,6 +1298,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks()
// If this track type is not allowed, then we need to disable it.
[track setEnabled:NO];
--m_enabledTrackCount;
+ m_hasUnsupportedTracks = true;
}
// Disable chapter tracks. These are most likely to lead to trouble, as
@@ -1137,6 +1331,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks()
// Disable the evil, evil track.
[chapterTrack setEnabled:NO];
--m_enabledTrackCount;
+ m_hasUnsupportedTracks = true;
}
}
@@ -1146,8 +1341,50 @@ void MediaPlayerPrivate::sawUnsupportedTracks()
m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
}
+#if USE(ACCELERATED_COMPOSITING)
+bool MediaPlayerPrivate::supportsAcceleratedRendering() const
+{
+ // When in the media document we render via QTMovieView, which is already accelerated.
+ return isReadyForRendering() && getQTMovieLayerClass() != Nil && !m_player->inMediaDocument();
}
+void MediaPlayerPrivate::acceleratedRenderingStateChanged()
+{
+ // Set up or change the rendering path if necessary.
+ setUpVideoRendering();
+
+ if (currentRenderingMode() == MediaRenderingMovieLayer) {
+ GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
+ if (videoGraphicsLayer)
+ videoGraphicsLayer->setContentsToVideo((PlatformLayer *)m_qtVideoLayer.get());
+ }
+}
+#endif
+
+bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
+{
+ // We tell quicktime to disallow resources that come from different origins
+ // so we know all media is single origin.
+ return true;
+}
+
+MediaPlayer::MovieLoadType MediaPlayerPrivate::movieLoadType() const
+{
+ if (!m_qtMovie)
+ return MediaPlayer::Unknown;
+
+ MediaPlayer::MovieLoadType movieType = (MediaPlayer::MovieLoadType)wkQTMovieGetType(m_qtMovie.get());
+
+ // Can't include WebKitSystemInterface from WebCore so we can't get the enum returned
+ // by wkQTMovieGetType, but at least verify that the value is in the valid range.
+ ASSERT(movieType >= MediaPlayer::Unknown && movieType <= MediaPlayer::LiveStream);
+
+ return movieType;
+}
+
+
+} // namespace WebCore
+
@implementation WebCoreMovieObserver
- (id)initWithCallback:(MediaPlayerPrivate*)callback
diff --git a/WebCore/platform/graphics/mac/WebLayer.h b/WebCore/platform/graphics/mac/WebLayer.h
index b8b46ed..af53ae6 100644
--- a/WebCore/platform/graphics/mac/WebLayer.h
+++ b/WebCore/platform/graphics/mac/WebLayer.h
@@ -42,6 +42,13 @@ namespace WebCore {
@end
+#if defined(BUILDING_ON_LEOPARD)
+@interface CALayer(WebLayerInternal)
+- (CGAffineTransform)contentsTransform;
+- (void)setContentsTransform:(CGAffineTransform)t;
+@end
+#endif
+
@interface WebLayer : CALayer
{
WebCore::GraphicsLayer* m_layerOwner;
diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm
index fad3916..2647466 100644
--- a/WebCore/platform/graphics/mac/WebLayer.mm
+++ b/WebCore/platform/graphics/mac/WebLayer.mm
@@ -40,10 +40,18 @@ using namespace WebCore;
+ (void)drawContents:(WebCore::GraphicsLayer*)layerContents ofLayer:(CALayer*)layer intoContext:(CGContextRef)context
{
- UNUSED_PARAM(layer);
+ if (!layerContents)
+ return;
+
CGContextSaveGState(context);
-
- if (layerContents && layerContents->client()) {
+
+ CGRect layerBounds = [layer bounds];
+ if (layerContents->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp) {
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM(context, 0, -layerBounds.size.height);
+ }
+
+ if (layerContents->client()) {
[NSGraphicsContext saveGraphicsState];
// Set up an NSGraphicsContext for the context, so that parts of AppKit that rely on
@@ -68,29 +76,24 @@ using namespace WebCore;
// FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color,
// so CA never makes backing store for it (which is what -setNeedsDisplay will do above).
CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f);
- CGRect aBounds = [layer bounds];
- CGContextFillRect(context, aBounds);
+ CGContextFillRect(context, layerBounds);
}
#endif
- CGContextRestoreGState(context);
-
#ifndef NDEBUG
- if (layerContents && layerContents->showRepaintCounter()) {
+ if (layerContents->showRepaintCounter()) {
bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
char text[16]; // that's a lot of repaints
snprintf(text, sizeof(text), "%d", layerContents->incrementRepaintCount());
- CGAffineTransform a = CGContextGetCTM(context);
-
CGContextSaveGState(context);
if (isTiledLayer)
CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 0.8f);
else
CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
- CGRect aBounds = [layer bounds];
+ CGRect aBounds = layerBounds;
aBounds.size.width = 10 + 12 * strlen(text);
aBounds.size.height = 25;
@@ -105,6 +108,8 @@ using namespace WebCore;
CGContextRestoreGState(context);
}
#endif
+
+ CGContextRestoreGState(context);
}
// Disable default animations
@@ -132,12 +137,19 @@ using namespace WebCore;
- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
{
if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) {
+#if defined(BUILDING_ON_LEOPARD)
+ dirtyRect = CGRectApplyAffineTransform(dirtyRect, [self contentsTransform]);
+#endif
[super setNeedsDisplayInRect:dirtyRect];
#ifndef NDEBUG
if (m_layerOwner->showRepaintCounter()) {
CGRect bounds = [self bounds];
- [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)];
+ CGRect indicatorRect = CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25);
+#if defined(BUILDING_ON_LEOPARD)
+ indicatorRect = CGRectApplyAffineTransform(indicatorRect, [self contentsTransform]);
+#endif
+ [super setNeedsDisplayInRect:indicatorRect];
}
#endif
}
diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm
index 1dd00ba..a1f5693 100644
--- a/WebCore/platform/graphics/mac/WebTiledLayer.mm
+++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm
@@ -74,12 +74,19 @@ using namespace WebCore;
- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
{
if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) {
+#if defined(BUILDING_ON_LEOPARD)
+ dirtyRect = CGRectApplyAffineTransform(dirtyRect, [self contentsTransform]);
+#endif
[super setNeedsDisplayInRect:dirtyRect];
#ifndef NDEBUG
if (m_layerOwner->showRepaintCounter()) {
CGRect bounds = [self bounds];
- [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)];
+ CGRect indicatorRect = CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25);
+#if defined(BUILDING_ON_LEOPARD)
+ indicatorRect = CGRectApplyAffineTransform(indicatorRect, [self contentsTransform]);
+#endif
+ [super setNeedsDisplayInRect:indicatorRect];
}
#endif
}
diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp
index 668912e..5d29389 100644
--- a/WebCore/platform/graphics/qt/FontCacheQt.cpp
+++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -1,6 +1,8 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -26,10 +28,13 @@
#include "FontDescription.h"
#include "FontPlatformData.h"
#include "Font.h"
+#include "PlatformString.h"
#include "StringHash.h"
+#include <utility>
+#include <wtf/ListHashSet.h>
#include <wtf/StdLibExtras.h>
-#include <QHash>
+using namespace WTF;
namespace WebCore {
@@ -47,36 +52,173 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne
{
}
-typedef QHash<FontDescription, FontPlatformData*> FontPlatformDataCache;
+// This type must be consistent with FontPlatformData's ctor - the one which
+// gets FontDescription as it's parameter.
+class FontPlatformDataCacheKey {
+public:
+ FontPlatformDataCacheKey(const FontDescription& description)
+ : m_familyName()
+ , m_bold(false)
+ , m_size(description.computedPixelSize())
+ , m_italic(description.italic())
+ , m_smallCaps(description.smallCaps())
+ , m_hash(0)
+ {
+ // FIXME: Map all FontWeight values to QFont weights in FontPlatformData's ctor and follow it here
+ if (FontPlatformData::toQFontWeight(description.weight()) > QFont::Normal)
+ m_bold = true;
-// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this.
-static FontPlatformDataCache* gFontPlatformDataCache;
+ const FontFamily* family = &description.family();
+ while (family) {
+ m_familyName.append(family->family());
+ family = family->next();
+ if (family)
+ m_familyName.append(',');
+ }
-uint qHash(const FontDescription& key)
-{
- uint value = CaseFoldingHash::hash(key.family().family());
- value ^= key.computedPixelSize();
- value ^= static_cast<int>(key.weight());
- return value;
-}
+ computeHash();
+ }
+
+ FontPlatformDataCacheKey(const FontPlatformData& fontData)
+ : m_familyName(static_cast<String>(fontData.family()))
+ , m_size(fontData.pixelSize())
+ , m_bold(fontData.bold())
+ , m_italic(fontData.italic())
+ , m_smallCaps(fontData.smallCaps())
+ , m_hash(0)
+ {
+ computeHash();
+ }
+
+ FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { }
+ bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); }
+
+ enum HashTableEmptyValueType { HashTableEmptyValue };
+
+ FontPlatformDataCacheKey(HashTableEmptyValueType)
+ : m_familyName()
+ , m_size(0)
+ , m_bold(false)
+ , m_italic(false)
+ , m_smallCaps(false)
+ , m_hash(0)
+ {
+ }
+
+ bool operator==(const FontPlatformDataCacheKey& other) const
+ {
+ if (m_hash != other.m_hash)
+ return false;
+
+ return equalIgnoringCase(m_familyName, other.m_familyName) && m_size == other.m_size &&
+ m_bold == other.m_bold && m_italic == other.m_italic && m_smallCaps == other.m_smallCaps;
+ }
+
+ unsigned hash() const
+ {
+ return m_hash;
+ }
+
+ void computeHash()
+ {
+ unsigned hashCodes[] = {
+ CaseFoldingHash::hash(m_familyName),
+ m_size | static_cast<unsigned>(m_bold << sizeof(unsigned) * 8 - 1)
+ | static_cast<unsigned>(m_italic) << sizeof(unsigned) *8 - 2
+ | static_cast<unsigned>(m_smallCaps) << sizeof(unsigned) * 8 - 3
+ };
+ m_hash = StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+ }
+
+private:
+ String m_familyName;
+ int m_size;
+ bool m_bold;
+ bool m_italic;
+ bool m_smallCaps;
+ unsigned m_hash;
+
+ static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; }
+};
+
+struct FontPlatformDataCacheKeyHash {
+ static unsigned hash(const FontPlatformDataCacheKey& key)
+ {
+ return key.hash();
+ }
+
+ static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> {
+ static const bool needsDestruction = true;
+ static const FontPlatformDataCacheKey& emptyValue()
+ {
+ DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (FontPlatformDataCacheKey::HashTableEmptyValue));
+ return key;
+ }
+ static void constructDeletedValue(FontPlatformDataCacheKey& slot)
+ {
+ new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FontPlatformDataCacheKey& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache;
+
+// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this.
+static FontPlatformDataCache* gFontPlatformDataCache = 0;
FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName)
{
if (!gFontPlatformDataCache)
gFontPlatformDataCache = new FontPlatformDataCache;
- FontPlatformData* fontData = gFontPlatformDataCache->value(description, 0);
- if (!fontData) {
- fontData = new FontPlatformData(description);
- gFontPlatformDataCache->insert(description, fontData);
+ FontPlatformDataCacheKey key(description);
+ FontPlatformData* platformData = gFontPlatformDataCache->get(key);
+ if (!platformData) {
+ platformData = new FontPlatformData(description);
+ gFontPlatformDataCache->add(key, platformData);
}
-
- return fontData;
+ return platformData;
}
-SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*)
+typedef HashMap<FontPlatformDataCacheKey, std::pair<SimpleFontData*, unsigned>, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontDataCache;
+
+static FontDataCache* gFontDataCache = 0;
+
+static const int cMaxInactiveFontData = 40;
+static const int cTargetInactiveFontData = 32;
+
+static ListHashSet<const SimpleFontData*>* gInactiveFontDataSet = 0;
+
+SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* fontPlatformData)
{
- return 0;
+ if (!gFontDataCache) {
+ gFontDataCache = new FontDataCache;
+ gInactiveFontDataSet = new ListHashSet<const SimpleFontData*>;
+ }
+
+ FontPlatformDataCacheKey key(*fontPlatformData);
+ FontDataCache::iterator it = gFontDataCache->find(key);
+ if (it == gFontDataCache->end()) {
+ SimpleFontData* fontData = new SimpleFontData(*fontPlatformData);
+ gFontDataCache->add(key, std::pair<SimpleFontData*, unsigned>(fontData, 1));
+ return fontData;
+ }
+ if (!it->second.second++) {
+ ASSERT(gInactiveFontDataSet->contains(it->second.first));
+ gInactiveFontDataSet->remove(it->second.first);
+ }
+ return it->second.first;
}
FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&)
@@ -84,8 +226,52 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&)
return 0;
}
-void FontCache::releaseFontData(const WebCore::SimpleFontData*)
+void FontCache::releaseFontData(const WebCore::SimpleFontData* fontData)
{
+ ASSERT(gFontDataCache);
+ ASSERT(!fontData->isCustomFont());
+
+ FontPlatformDataCacheKey key(fontData->platformData());
+ FontDataCache::iterator it = gFontDataCache->find(key);
+ ASSERT(it != gFontDataCache->end());
+ if (!--it->second.second) {
+ gInactiveFontDataSet->add(it->second.first);
+ if (gInactiveFontDataSet->size() > cMaxInactiveFontData)
+ purgeInactiveFontData(gInactiveFontDataSet->size() - cTargetInactiveFontData);
+ }
+}
+
+void FontCache::purgeInactiveFontData(int count)
+{
+ static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData.
+ if (isPurging)
+ return;
+
+ isPurging = true;
+
+ ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontDataSet->begin();
+ ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontDataSet->end();
+ for (int i = 0; i < count && it != end; ++i, ++it) {
+ FontPlatformDataCacheKey key = (*it)->platformData();
+ pair<SimpleFontData*, unsigned> fontDataPair = gFontDataCache->take(key);
+ ASSERT(fontDataPair.first != 0);
+ ASSERT(!fontDataPair.second);
+ delete fontDataPair.first;
+
+ FontPlatformData* platformData = gFontPlatformDataCache->take(key);
+ if (platformData)
+ delete platformData;
+ }
+
+ if (it == end) {
+ // Removed everything
+ gInactiveFontDataSet->clear();
+ } else {
+ for (int i = 0; i < count; ++i)
+ gInactiveFontDataSet->remove(gInactiveFontDataSet->begin());
+ }
+
+ isPurging = false;
}
void FontCache::addClient(FontSelector*)
@@ -98,10 +284,10 @@ void FontCache::removeClient(FontSelector*)
void FontCache::invalidate()
{
- if (!gFontPlatformDataCache)
+ if (!gFontPlatformDataCache || !gFontDataCache)
return;
- gFontPlatformDataCache->clear();
+ purgeInactiveFontData();
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp
index 50627b7..c29fd56 100644
--- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp
+++ b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp
@@ -25,6 +25,7 @@
#include "FontFallbackList.h"
#include "Font.h"
+#include "FontCache.h"
#include "SegmentedFontData.h"
#include <QDebug>
@@ -32,16 +33,23 @@
namespace WebCore {
FontFallbackList::FontFallbackList()
- : m_familyIndex(0)
+ : m_pageZero(0)
+ , m_cachedPrimarySimpleFontData(0)
+ , m_fontSelector(0)
+ , m_familyIndex(0)
, m_pitch(UnknownPitch)
, m_loadingCustomFonts(false)
- , m_fontSelector(0)
, m_generation(0)
{
}
void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector)
{
+ releaseFontData();
+ m_fontList.clear();
+ m_pageZero = 0;
+ m_pages.clear();
+ m_cachedPrimarySimpleFontData = 0;
m_familyIndex = 0;
m_pitch = UnknownPitch;
m_loadingCustomFonts = false;
@@ -51,14 +59,20 @@ void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSel
void FontFallbackList::releaseFontData()
{
- if (m_fontList.size())
- delete m_fontList[0].first;
- m_fontList.clear();
+ unsigned numFonts = m_fontList.size();
+ for (unsigned i = 0; i < numFonts; ++i) {
+ if (m_fontList[i].second)
+ delete m_fontList[i].first;
+ else {
+ ASSERT(!m_fontList[i].first->isSegmented());
+ fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first));
+ }
+ }
}
void FontFallbackList::determinePitch(const WebCore::Font* font) const
{
- const FontData* fontData = primaryFont(font);
+ const FontData* fontData = primaryFontData(font);
if (!fontData->isSegmented())
m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
else {
@@ -76,6 +90,14 @@ const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigne
if (index != 0)
return 0;
+ // Search for the WebCore font that is already in the list
+ for (int i = m_fontList.size() - 1; i >= 0; --i) {
+ pair<const FontData*, bool> item = m_fontList[i];
+ // item.second means that the item was created locally or not
+ if (!item.second)
+ return item.first;
+ }
+
// Use the FontSelector to get a WebCore font and then fallback to Qt
const FontDescription& description = _font->fontDescription();
const FontFamily* family = &description.family();
@@ -85,6 +107,10 @@ const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigne
if (data) {
if (data->isLoading())
m_loadingCustomFonts = true;
+ if (!data->isCustomFont()) {
+ // Custom fonts can be freed anytime so we must not hold them
+ m_fontList.append(pair<const FontData*, bool>(data, false));
+ }
return data;
}
}
@@ -94,14 +120,14 @@ const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigne
if (m_fontList.size())
return m_fontList[0].first;
- const FontData* result = new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing());
- m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont()));
+ const FontData* result = new SimpleFontData(FontPlatformData(description, _font->wordSpacing(), _font->letterSpacing()), true);
+ m_fontList.append(pair<const FontData*, bool>(result, true));
return result;
}
const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const
{
- return primaryFont(font);
+ return primaryFontData(font);
}
void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData& platformData)
diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h
index 5e97678..92219fd 100644
--- a/WebCore/platform/graphics/qt/FontPlatformData.h
+++ b/WebCore/platform/graphics/qt/FontPlatformData.h
@@ -1,6 +1,7 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -24,11 +25,12 @@
#define FontPlatformData_h
#include "FontDescription.h"
-
#include <QFont>
namespace WebCore {
+class String;
+
class FontPlatformData
{
public:
@@ -39,8 +41,38 @@ public:
FontPlatformData(const FontDescription&, int wordSpacing = 0, int letterSpacing = 0);
FontPlatformData(const QFont&, bool bold);
+ static inline QFont::Weight toQFontWeight(FontWeight fontWeight)
+ {
+ switch (fontWeight) {
+ case FontWeight100:
+ case FontWeight200:
+ return QFont::Light; // QFont::Light == Weight of 25
+ case FontWeight600:
+ return QFont::DemiBold; // QFont::DemiBold == Weight of 63
+ case FontWeight700:
+ case FontWeight800:
+ return QFont::Bold; // QFont::Bold == Weight of 75
+ case FontWeight900:
+ return QFont::Black; // QFont::Black == Weight of 87
+ case FontWeight300:
+ case FontWeight400:
+ case FontWeight500:
+ default:
+ return QFont::Normal; // QFont::Normal == Weight of 50
+ }
+ }
+
QFont font() const { return m_font; }
float size() const { return m_size; }
+ QString family() const { return m_font.family(); }
+ bool bold() const { return m_bold; }
+ bool italic() const { return m_font.italic(); }
+ bool smallCaps() const { return m_font.capitalization() == QFont::SmallCaps; }
+ int pixelSize() const { return m_font.pixelSize(); }
+
+#ifndef NDEBUG
+ String description() const;
+#endif
float m_size;
bool m_bold;
diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
index f0dd3ea..7709be6 100644
--- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
+++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -21,6 +22,8 @@
#include "config.h"
#include "FontPlatformData.h"
+#include "PlatformString.h"
+
namespace WebCore {
FontPlatformData::FontPlatformData(const FontDescription& description, int wordSpacing, int letterSpacing)
@@ -40,11 +43,9 @@ FontPlatformData::FontPlatformData(const FontDescription& description, int wordS
m_font.setFamily(familyName);
m_font.setPixelSize(qRound(description.computedSize()));
m_font.setItalic(description.italic());
- // FIXME: Map all FontWeight values to QFont weights.
- if (description.weight() >= FontWeight600)
- m_font.setWeight(QFont::Bold);
- else
- m_font.setWeight(QFont::Normal);
+
+ m_font.setWeight(toQFontWeight(description.weight()));
+ m_bold = m_font.bold();
bool smallCaps = description.smallCaps();
m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase);
@@ -77,4 +78,11 @@ FontPlatformData::FontPlatformData()
{
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
}
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index 5a4b7b2..e8eb923 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -47,8 +47,8 @@ namespace WebCore {
static const QString qstring(const TextRun& run)
{
- //We don't detach
- return QString::fromRawData((const QChar *)run.characters(), run.length());
+ // We don't detach
+ return QString::fromRawData(reinterpret_cast<const QChar*>(run.characters()), run.length());
}
static const QString fixSpacing(const QString &string)
@@ -57,11 +57,10 @@ static const QString fixSpacing(const QString &string)
QString possiblyDetached = string;
for (int i = 0; i < string.length(); ++i) {
const QChar c = string.at(i);
- if (c.unicode() != 0x20 && Font::treatAsSpace(c.unicode())) {
- possiblyDetached[i] = 0x20; //detach
- } else if (c.unicode() != 0x200c && Font::treatAsZeroWidthSpace(c.unicode())) {
- possiblyDetached[i] = 0x200c; //detach
- }
+ if (c.unicode() != 0x20 && Font::treatAsSpace(c.unicode()))
+ possiblyDetached[i] = 0x20; // detach
+ else if (c.unicode() != 0x200c && Font::treatAsZeroWidthSpace(c.unicode()))
+ possiblyDetached[i] = 0x200c; // detach
}
return possiblyDetached;
}
@@ -222,7 +221,10 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint&
QFont Font::font() const
{
- return primaryFont()->getQtFont();
+ QFont f = primaryFont()->getQtFont();
+ f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing);
+ f.setWordSpacing(m_wordSpacing);
+ return f;
}
}
diff --git a/WebCore/platform/graphics/qt/FontQt43.cpp b/WebCore/platform/graphics/qt/FontQt43.cpp
index 137b7c9..45bf05d 100644
--- a/WebCore/platform/graphics/qt/FontQt43.cpp
+++ b/WebCore/platform/graphics/qt/FontQt43.cpp
@@ -105,9 +105,9 @@ static int generateComponents(Vector<TextRunComponent, 1024>* components, const
offset += add + letterSpacing + components->last().width;
start = 1;
// qDebug() << "space at 0" << offset;
- } else if (smallCaps) {
+ } else if (smallCaps)
f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font());
- }
+
for (int i = 1; i < run.length(); ++i) {
uint ch = run[i];
if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate())
@@ -263,7 +263,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool
if (!l.isValid())
return offset;
- l.setLineWidth(INT_MAX/256);
+ l.setLineWidth(INT_MAX / 256);
layout.endLayout();
if (position - xs >= l.width())
@@ -272,9 +272,8 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool
if (cursor > 1)
--cursor;
return offset + cursor;
- } else {
+ } else
offset += components.at(i).string.length() - 1;
- }
}
} else {
for (int i = 0; i < components.size(); ++i) {
@@ -287,7 +286,7 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool
if (!l.isValid())
return offset;
- l.setLineWidth(INT_MAX/256);
+ l.setLineWidth(INT_MAX / 256);
layout.endLayout();
if (position - xs >= l.width())
@@ -296,9 +295,8 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool
if (cursor > 1)
--cursor;
return offset + cursor;
- } else {
+ } else
offset += components.at(i).string.length() - 1;
- }
}
}
return run.length();
@@ -321,7 +319,7 @@ static float cursorToX(const Vector<TextRunComponent, 1024>& components, int wid
if (!l.isValid())
return 0;
- l.setLineWidth(INT_MAX/256);
+ l.setLineWidth(INT_MAX / 256);
layout.endLayout();
return xs + l.cursorToX(cursor - start + 1);
diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp
index 1e71f58..9b9acc2 100644
--- a/WebCore/platform/graphics/qt/GradientQt.cpp
+++ b/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -67,7 +67,7 @@ QGradient* Gradient::platformGradient()
++stopIterator;
}
- switch(m_spreadMethod) {
+ switch (m_spreadMethod) {
case SpreadMethodPad:
m_gradient->setSpread(QGradient::PadSpread);
break;
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index ed7ac47..e259a4e 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -95,7 +95,8 @@ static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op
case CompositeXOR:
return QPainter::CompositionMode_Xor;
case CompositePlusDarker:
- return QPainter::CompositionMode_SourceOver;
+ // there is no exact match, but this is the closest
+ return QPainter::CompositionMode_Darken;
case CompositeHighlight:
return QPainter::CompositionMode_SourceOver;
case CompositePlusLighter:
@@ -155,7 +156,7 @@ static Qt::PenStyle toQPenStyle(StrokeStyle style)
static inline Qt::FillRule toQtFillRule(WindRule rule)
{
- switch(rule) {
+ switch (rule) {
case RULE_EVENODD:
return Qt::OddEvenFill;
case RULE_NONZERO:
@@ -165,8 +166,7 @@ static inline Qt::FillRule toQtFillRule(WindRule rule)
return Qt::OddEvenFill;
}
-struct TransparencyLayer
-{
+struct TransparencyLayer {
TransparencyLayer(const QPainter* p, const QRect &rect)
: pixmap(rect.width(), rect.height())
{
@@ -198,8 +198,7 @@ private:
TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
};
-class GraphicsContextPlatformPrivate
-{
+class GraphicsContextPlatformPrivate {
public:
GraphicsContextPlatformPrivate(QPainter* painter);
~GraphicsContextPlatformPrivate();
@@ -217,7 +216,7 @@ public:
bool antiAliasingForRectsAndLines;
- QStack<TransparencyLayer *> layers;
+ QStack<TransparencyLayer*> layers;
QPainter* redirect;
QBrush solidColor;
@@ -242,9 +241,8 @@ GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p)
antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
// FIXME: Maybe only enable in SVG mode?
painter->setRenderHint(QPainter::Antialiasing, true);
- } else {
+ } else
antiAliasingForRectsAndLines = false;
- }
}
GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
@@ -265,7 +263,7 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
GraphicsContext::~GraphicsContext()
{
- while(!m_data->layers.isEmpty())
+ while (!m_data->layers.isEmpty())
endTransparencyLayer();
destroyGraphicsContextPrivate(m_common);
@@ -280,7 +278,7 @@ PlatformGraphicsContext* GraphicsContext::platformContext() const
TransformationMatrix GraphicsContext::getCTM() const
{
QTransform matrix(platformContext()->combinedTransform());
- return TransformationMatrix(matrix.m11(), matrix.m12(), 0, matrix.m13(),
+ return TransformationMatrix(matrix.m11(), matrix.m12(), 0, matrix.m13(),
matrix.m21(), matrix.m22(), 0, matrix.m23(),
0, 0, 1, 0,
matrix.m31(), matrix.m32(), 0, matrix.m33());
@@ -763,7 +761,6 @@ void GraphicsContext::clipPath(WindRule clipRule)
* RenderTheme handles drawing focus on widgets which
* need it.
*/
-Color focusRingColor() { return Color(0, 0, 0); }
void GraphicsContext::drawFocusRing(const Color& color)
{
if (paintingDisabled())
@@ -1127,8 +1124,9 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform)
m_data->p()->setWorldTransform(transform, true);
- // Transformations to the context shouldn't transform the currentPath.
- // We have to undo every change made to the context from the currentPath to avoid wrong drawings.
+ // Transformations to the context shouldn't transform the currentPath.
+ // We have to undo every change made to the context from the currentPath
+ // to avoid wrong drawings.
if (!m_data->currentPath.isEmpty() && transform.isInvertible()) {
QTransform matrix = transform.inverse();
m_data->currentPath = m_data->currentPath * matrix;
@@ -1211,7 +1209,7 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
bitmapInfo.bmiHeader.biClrImportant = 0;
void* pixels = 0;
- HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
if (!bitmap)
return 0;
@@ -1229,7 +1227,7 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
memset(bmpInfo.bmBits, 0, bufferSize);
}
-#if !PLATFORM(WIN_CE)
+#if !PLATFORM(WINCE)
// Make sure we can do world transforms.
SetGraphicsMode(bitmapDC, GM_ADVANCED);
diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp
index c9f3ced..34c3c47 100644
--- a/WebCore/platform/graphics/qt/IconQt.cpp
+++ b/WebCore/platform/graphics/qt/IconQt.cpp
@@ -39,7 +39,7 @@ Icon::Icon()
Icon::~Icon()
{
}
-
+
PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
{
RefPtr<Icon> i = adoptRef(new Icon);
@@ -57,9 +57,8 @@ void Icon::paint(GraphicsContext* ctx, const IntRect& rect)
{
QPixmap px = m_icon.pixmap(rect.size());
QPainter *p = static_cast<QPainter*>(ctx->platformContext());
- if (p && !px.isNull()) {
+ if (p && !px.isNull())
p->drawPixmap(rect.x(), rect.y(), px);
- }
}
}
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
index 506a8ea..22a5a43 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -40,6 +40,7 @@
#include <QImageWriter>
#include <QPainter>
#include <QPixmap>
+#include <math.h>
namespace WebCore {
@@ -67,7 +68,7 @@ ImageBufferData::ImageBufferData(const IntSize& size)
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
}
-ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
@@ -98,6 +99,32 @@ Image* ImageBuffer::image() const
return m_image.get();
}
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ bool isPainting = m_data.m_painter->isActive();
+ if (isPainting)
+ m_data.m_painter->end();
+
+ QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ ASSERT(!image.isNull());
+
+ for (int y = 0; y < m_size.height(); ++y) {
+ for (int x = 0; x < m_size.width(); x++) {
+ QRgb value = image.pixel(x, y);
+ value = qRgba(lookUpTable[qRed(value)],
+ lookUpTable[qGreen(value)],
+ lookUpTable[qBlue(value)],
+ lookUpTable[qAlpha(value)]);
+ image.setPixel(x, y, value);
+ }
+ }
+
+ m_data.m_pixmap = QPixmap::fromImage(image);
+
+ if (isPainting)
+ m_data.m_painter->begin(&m_data.m_pixmap);
+}
+
PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
{
PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index cd32428..7bbdcc0 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -118,7 +118,7 @@ ImageDecoderQt::ReadContext::ReadResult
// Attempt to construct an empty image of the matching size and format
// for efficient reading
QImage newImage = m_dataFormat != QImage::Format_Invalid ?
- QImage(m_size,m_dataFormat) : QImage();
+ QImage(m_size, m_dataFormat) : QImage();
m_target.push_back(ImageData(newImage));
}
@@ -137,8 +137,8 @@ ImageDecoderQt::ReadContext::ReadResult
const bool supportsAnimation = m_reader.supportsAnimation();
if (debugImageDecoderQt)
- qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size << " format " << m_dataFormat
- << " supportsAnimation=" << supportsAnimation ;
+ qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size
+ << " format " << m_dataFormat << " supportsAnimation=" << supportsAnimation;
// No point in readinfg further
if (!supportsAnimation)
return ReadComplete;
@@ -158,7 +158,7 @@ ImageDecoderQt::ReadContext::IncrementalReadResult
// set state to reflect complete header, etc.
// For now, we read the whole image.
- const qint64 startPos = m_buffer.pos ();
+ const qint64 startPos = m_buffer.pos();
// Oops, failed. Rewind.
if (!m_reader.read(&imageData.m_image)) {
m_buffer.seek(startPos);
@@ -217,9 +217,7 @@ void ImageDecoderQt::reset()
m_failed = false;
m_imageList.clear();
m_pixmapCache.clear();
- m_sizeAvailable = false;
m_loopCount = cAnimationNone;
- m_size = IntSize(-1, -1);
}
void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived)
@@ -238,7 +236,7 @@ void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived)
if (debugImageDecoderQt)
qDebug() << " read returns " << readResult;
- switch ( readResult) {
+ switch (readResult) {
case ReadContext::ReadFailed:
m_failed = true;
break;
@@ -247,8 +245,8 @@ void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived)
case ReadContext::ReadComplete:
// Did we read anything - try to set the size.
if (hasFirstImageHeader()) {
- m_sizeAvailable = true;
- m_size = m_imageList[0].m_image.size();
+ QSize imgSize = m_imageList[0].m_image.size();
+ setSize(imgSize.width(), imgSize.height());
if (readContext.reader()->supportsAnimation()) {
if (readContext.reader()->loopCount() != -1)
@@ -262,14 +260,14 @@ void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived)
}
-bool ImageDecoderQt::isSizeAvailable() const
+bool ImageDecoderQt::isSizeAvailable()
{
if (debugImageDecoderQt)
- qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << m_sizeAvailable;
- return m_sizeAvailable;
+ qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << ImageDecoder::isSizeAvailable();
+ return ImageDecoder::isSizeAvailable();
}
-int ImageDecoderQt::frameCount() const
+size_t ImageDecoderQt::frameCount() const
{
if (debugImageDecoderQt)
qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size();
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h
index b8c3edd..fc52479 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.h
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -45,8 +45,8 @@ public:
typedef Vector<char> IncomingData;
virtual void setData(const IncomingData& data, bool allDataReceived);
- virtual bool isSizeAvailable() const;
- virtual int frameCount() const;
+ virtual bool isSizeAvailable();
+ virtual size_t frameCount() const;
virtual int repetitionCount() const;
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp
index a2e96f3..5d40e26 100644
--- a/WebCore/platform/graphics/qt/ImageQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -83,7 +83,6 @@ bool FrameData::clear(bool clearMetadata)
}
-
// ================================================
// Image Class
// ================================================
@@ -93,7 +92,6 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name)
return StillImage::create(loadResourcePixmap(name));
}
-
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
@@ -103,9 +101,8 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const
QPixmap pixmap = *framePixmap;
QRect tr = QRectF(tileRect).toRect();
- if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) {
+ if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height())
pixmap = pixmap.copy(tr);
- }
QBrush b(pixmap);
b.setTransform(patternTransform);
@@ -129,7 +126,7 @@ void BitmapImage::initPlatformData()
void BitmapImage::invalidatePlatformData()
{
}
-
+
// Drawing Routines
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
const FloatRect& src, CompositeOperator op)
@@ -139,7 +136,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
QPixmap* image = nativeImageForCurrentFrame();
if (!image)
return;
-
+
if (mayFillWithSolidColor()) {
fillWithSolidColor(ctxt, dst, solidColor(), op);
return;
@@ -158,7 +155,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
painter->setCompositionMode(QPainter::CompositionMode_Source);
// Test using example site at
- // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
painter->drawPixmap(dst, *image, src);
ctxt->restore();
diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
index 621728e..8ae449c 100644
--- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
@@ -91,9 +91,12 @@ IntSize ImageSource::size() const
return m_decoder->size();
}
-IntSize ImageSource::frameSizeAtIndex(size_t) const
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
{
- return size();
+ if (!m_decoder)
+ return IntSize();
+
+ return m_decoder->frameSizeAtIndex(index);
}
int ImageSource::repetitionCount()
@@ -124,7 +127,7 @@ float ImageSource::frameDurationAtIndex(size_t index)
{
if (!m_decoder)
return 0;
-
+
// Many annoying ads specify a 0 duration to make an image flash as quickly
// as possible. We follow WinIE's behavior and use a duration of 100 ms
// for any frames that specify a duration of <= 50 ms. See
@@ -138,17 +141,17 @@ bool ImageSource::frameHasAlphaAtIndex(size_t index)
{
if (!m_decoder || !m_decoder->supportsAlpha())
return false;
-
- const QPixmap* source = m_decoder->imageAtIndex( index);
+
+ const QPixmap* source = m_decoder->imageAtIndex(index);
if (!source)
return false;
-
+
return source->hasAlphaChannel();
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
{
- return (m_decoder && m_decoder->imageAtIndex(index) != 0);
+ return (m_decoder && m_decoder->imageAtIndex(index));
}
void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
index c80d73b..76b1494 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -36,11 +36,14 @@
#include <QMetaEnum>
#include <QUrl>
#include <QEvent>
-#include <phonon>
+
+#include <Phonon/AudioOutput>
+#include <Phonon/MediaObject>
+#include <Phonon/VideoWidget>
using namespace Phonon;
-#define LOG_MEDIAOBJECT() (LOG(Media,"%s", debugMediaObject(this, *m_mediaObject).constData()))
+#define LOG_MEDIAOBJECT() (LOG(Media, "%s", debugMediaObject(this, *m_mediaObject).constData()))
static QByteArray debugMediaObject(WebCore::MediaPlayerPrivate* mediaPlayer, const MediaObject& mediaObject)
{
@@ -94,9 +97,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
// Make sure we get updates for each frame
m_videoWidget->installEventFilter(this);
- foreach(QWidget* widget, qFindChildren<QWidget*>(m_videoWidget)) {
+ foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget))
widget->installEventFilter(this);
- }
connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
this, SLOT(stateChanged(Phonon::State, Phonon::State)));
@@ -111,8 +113,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
}
-MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
-{
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
return new MediaPlayerPrivate(player);
}
@@ -263,7 +265,7 @@ float MediaPlayerPrivate::maxTimeSeekable() const
}
unsigned MediaPlayerPrivate::bytesLoaded() const
-{
+{
notImplemented();
return 0;
}
@@ -343,9 +345,8 @@ void MediaPlayerPrivate::updateStates()
m_networkState = MediaPlayer::NetworkError;
m_readyState = MediaPlayer::HaveNothing;
cancelLoad();
- } else {
+ } else
m_mediaObject->pause();
- }
}
if (seeking())
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index 7569031..e5cecc8 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -92,7 +92,7 @@ bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point)
// FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer
// on each call.
- OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false);
+ OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1));
GraphicsContext* gc = scratchImage->context();
QPainterPathStroker stroke;
applier->strokeStyle(gc);
@@ -124,7 +124,7 @@ FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
{
// FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer
// on each call.
- OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false);
+ OwnPtr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1));
GraphicsContext* gc = scratchImage->context();
QPainterPathStroker stroke;
if (applier) {
@@ -170,8 +170,8 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
return;
}
- FloatPoint p1p0((p0.x() - p1.x()),(p0.y() - p1.y()));
- FloatPoint p1p2((p2.x() - p1.x()),(p2.y() - p1.y()));
+ FloatPoint p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
+ FloatPoint p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
@@ -216,7 +216,7 @@ void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
float factor_p1p2 = tangent / p1p2_length;
FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
- FloatPoint orth_p1p2((t_p1p2.x() - p.x()),(t_p1p2.y() - p.y()));
+ FloatPoint orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
float ea = acos(orth_p1p2.x() / orth_p1p2_length);
if (orth_p1p2.y() < 0)
@@ -298,7 +298,14 @@ void Path::clear()
bool Path::isEmpty() const
{
- return m_path->isEmpty();
+ // Don't use QPainterPath::isEmpty(), as that also returns true if there's only
+ // one initial MoveTo element in the path.
+ return !m_path->elementCount();
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
}
String Path::debugString() const
diff --git a/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
index 15f0cc5..37b86f3 100644
--- a/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
+++ b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
@@ -32,7 +32,7 @@
namespace WebCore {
TransformationMatrix::operator QTransform() const
-{
+{
return QTransform(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44());
}
diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp
index ac7366c..3bdddb2 100644
--- a/WebCore/platform/graphics/skia/GradientSkia.cpp
+++ b/WebCore/platform/graphics/skia/GradientSkia.cpp
@@ -158,15 +158,21 @@ SkShader* Gradient::platformGradient()
// circle" (m_p1/m_r1).
// See http://webkit.org/blog/175/introducing-css-gradients/ for a
// description of the expected behavior.
+
+ // The radius we give to Skia must be positive (and non-zero). If
+ // we're given a zero radius, just ask for a very small radius so
+ // Skia will still return an object.
+ SkScalar radius = m_r1 > 0 ? WebCoreFloatToSkScalar(m_r1) : SK_ScalarMin;
m_gradient = SkGradientShader::CreateRadial(m_p1,
- WebCoreFloatToSkScalar(m_r1), colors, pos,
- static_cast<int>(countUsed), tile);
+ radius, colors, pos, static_cast<int>(countUsed), tile);
} else {
SkPoint pts[2] = { m_p0, m_p1 };
m_gradient = SkGradientShader::CreateLinear(pts, colors, pos,
static_cast<int>(countUsed), tile);
}
+ ASSERT(m_gradient);
+
SkMatrix matrix = m_gradientSpaceTransformation;
m_gradient->setLocalMatrix(matrix);
@@ -179,4 +185,10 @@ void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
context->fillRect(rect);
}
+void Gradient::setPlatformGradientSpaceTransform(const TransformationMatrix& matrix)
+{
+ if (m_gradient)
+ m_gradient->setLocalMatrix(m_gradientSpaceTransformation);
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h b/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h
index 29738f4..5e12ad6 100644
--- a/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h
+++ b/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h
@@ -38,7 +38,7 @@ class PlatformContextSkia;
namespace WebCore {
// This class just holds onto a PlatformContextSkia for GraphicsContext.
-class GraphicsContextPlatformPrivate : Noncopyable {
+class GraphicsContextPlatformPrivate : public Noncopyable {
public:
GraphicsContextPlatformPrivate(PlatformContextSkia* platformContext)
: m_context(platformContext) { }
diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
index 33ca23a..bbb42c9 100644
--- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -331,7 +331,7 @@ void GraphicsContext::clearRect(const FloatRect& rect)
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
- paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
platformContext()->canvas()->drawRect(r, paint);
}
@@ -503,7 +503,7 @@ void GraphicsContext::drawFocusRing(const Color& color)
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(focusRingColor().rgb());
+ paint.setColor(color.rgb());
paint.setStrokeWidth(focusRingOutset * 2);
paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref();
focusRingRegion.getBoundaryPath(&path);
@@ -530,16 +530,48 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
// probably worth the speed up of no square root, which also won't be exact.
SkPoint disp = pts[1] - pts[0];
int length = SkScalarRound(disp.fX + disp.fY);
- int width = roundf(
- platformContext()->setupPaintForStroking(&paint, 0, length));
+ platformContext()->setupPaintForStroking(&paint, 0, length);
+ int width = roundf(strokeThickness());
+ bool isVerticalLine = pts[0].fX == pts[1].fX;
+
+ if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+
+ SkRect r1, r2;
+ r1.set(pts[0].fX, pts[0].fY, pts[0].fX + width, pts[0].fY + width);
+ r2.set(pts[1].fX, pts[1].fY, pts[1].fX + width, pts[1].fY + width);
+
+ if (isVerticalLine) {
+ r1.offset(-width / 2, 0);
+ r2.offset(-width / 2, -width);
+ } else {
+ r1.offset(0, -width / 2);
+ r2.offset(-width, -width / 2);
+ }
+ SkPaint fillPaint;
+ fillPaint.setColor(paint.getColor());
+ platformContext()->canvas()->drawRect(r1, fillPaint);
+ platformContext()->canvas()->drawRect(r2, fillPaint);
+
+ // Since we've already rendered the endcaps, adjust the endpoints to
+ // exclude them from the line itself.
+ if (isVerticalLine) {
+ pts[0].fY += width;
+ pts[1].fY -= width;
+ } else {
+ pts[0].fX += width;
+ pts[1].fX -= width;
+ }
+ }
// "Borrowed" this comment and idea from GraphicsContextCG.cpp
+ //
// For odd widths, we add in 0.5 to the appropriate x/y so that the float
// arithmetic works out. For example, with a border width of 3, KHTML will
// pass us (y1+y2)/2, e.g., (50+53)/2 = 103/2 = 51 when we want 51.5. It is
// always true that an even width gave us a perfect position, but an odd
// width gave us a position that is off by exactly 0.5.
- bool isVerticalLine = pts[0].fX == pts[1].fX;
if (width & 1) { // Odd.
if (isVerticalLine) {
@@ -687,13 +719,6 @@ void GraphicsContext::fillPath()
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
- if (colorSpace == PatternColorSpace) {
- SkShader* pat = state.fillPattern->createPlatformPattern(getCTM());
- paint.setShader(pat);
- pat->unref();
- } else if (colorSpace == GradientColorSpace)
- paint.setShader(state.fillGradient->platformGradient());
-
platformContext()->canvas()->drawPath(path, paint);
}
@@ -713,14 +738,6 @@ void GraphicsContext::fillRect(const FloatRect& rect)
SkPaint paint;
platformContext()->setupPaintForFilling(&paint);
-
- if (colorSpace == PatternColorSpace) {
- SkShader* pat = state.fillPattern->createPlatformPattern(getCTM());
- paint.setShader(pat);
- pat->unref();
- } else if (colorSpace == GradientColorSpace)
- paint.setShader(state.fillGradient->platformGradient());
-
platformContext()->canvas()->drawRect(r, paint);
}
@@ -858,7 +875,7 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op)
{
if (paintingDisabled())
return;
- platformContext()->setPorterDuffMode(WebCoreCompositeToSkiaComposite(op));
+ platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
}
void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
@@ -947,6 +964,24 @@ void GraphicsContext::setPlatformFillColor(const Color& color)
platformContext()->setFillColor(color.rgb());
}
+void GraphicsContext::setPlatformFillGradient(Gradient* gradient)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setFillShader(gradient->platformGradient());
+}
+
+void GraphicsContext::setPlatformFillPattern(Pattern* pattern)
+{
+ if (paintingDisabled())
+ return;
+
+ SkShader* pat = pattern->createPlatformPattern(getCTM());
+ platformContext()->setFillShader(pat);
+ pat->safeUnref();
+}
+
void GraphicsContext::setPlatformShadow(const IntSize& size,
int blurInt,
const Color& color)
@@ -1015,6 +1050,24 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness)
platformContext()->setStrokeThickness(thickness);
}
+void GraphicsContext::setPlatformStrokeGradient(Gradient* gradient)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeShader(gradient->platformGradient());
+}
+
+void GraphicsContext::setPlatformStrokePattern(Pattern* pattern)
+{
+ if (paintingDisabled())
+ return;
+
+ SkShader* pat = pattern->createPlatformPattern(getCTM());
+ platformContext()->setStrokeShader(pat);
+ pat->safeUnref();
+}
+
void GraphicsContext::setPlatformTextDrawingMode(int mode)
{
if (paintingDisabled())
@@ -1077,13 +1130,6 @@ void GraphicsContext::strokePath()
SkPaint paint;
platformContext()->setupPaintForStroking(&paint, 0, 0);
- if (colorSpace == PatternColorSpace) {
- SkShader* pat = state.strokePattern->createPlatformPattern(getCTM());
- paint.setShader(pat);
- pat->unref();
- } else if (colorSpace == GradientColorSpace)
- paint.setShader(state.strokeGradient->platformGradient());
-
platformContext()->canvas()->drawPath(path, paint);
}
@@ -1102,13 +1148,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
platformContext()->setupPaintForStroking(&paint, 0, 0);
paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth));
- if (colorSpace == PatternColorSpace) {
- SkShader* pat = state.strokePattern->createPlatformPattern(getCTM());
- paint.setShader(pat);
- pat->unref();
- } else if (colorSpace == GradientColorSpace)
- paint.setShader(state.strokeGradient->platformGradient());
-
platformContext()->canvas()->drawRect(rect, paint);
}
diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
index 600882d..7935ff1 100644
--- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2008, Google Inc. All rights reserved.
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -53,7 +54,7 @@ ImageBufferData::ImageBufferData(const IntSize& size)
{
}
-ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
: m_data(size)
, m_size(size)
{
@@ -71,7 +72,7 @@ ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
// Make the background transparent. It would be nice if this wasn't
// required, but the canvas is currently filled with the magic transparency
// color. Can we have another way to manage this?
- m_data.m_canvas.drawARGB(0, 0, 0, 0, SkPorterDuff::kClear_Mode);
+ m_data.m_canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
success = true;
}
@@ -100,6 +101,23 @@ Image* ImageBuffer::image() const
return m_image.get();
}
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ const SkBitmap& bitmap = *context()->platformContext()->bitmap();
+ ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ SkAutoLockPixels bitmapLock(bitmap);
+ for (int y = 0; y < m_size.height(); ++y) {
+ uint32_t* srcRow = bitmap.getAddr32(0, y);
+ for (int x = 0; x < m_size.width(); ++x) {
+ SkColor color = SkPMColorToColor(srcRow[x]);
+ srcRow[x] = SkPreMultiplyARGB(lookUpTable[SkColorGetA(color)],
+ lookUpTable[SkColorGetR(color)],
+ lookUpTable[SkColorGetG(color)],
+ lookUpTable[SkColorGetB(color)]);
+ }
+ }
+}
+
PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
{
ASSERT(context());
diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp
index cb089bb..45c3dcd 100644
--- a/WebCore/platform/graphics/skia/ImageSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageSkia.cpp
@@ -220,10 +220,10 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm
}
}
-static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkPorterDuff::Mode& compOp)
+static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp)
{
SkPaint paint;
- paint.setPorterDuffXfermode(compOp);
+ paint.setXfermodeMode(compOp);
paint.setFilterBitmap(true);
int alpha = roundf(platformContext->getAlpha() * 256);
if (alpha > 255)
@@ -379,7 +379,7 @@ void Image::drawPattern(GraphicsContext* context,
SkPaint paint;
paint.setShader(shader)->unref();
- paint.setPorterDuffXfermode(WebCoreCompositeToSkiaComposite(compositeOp));
+ paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
context->platformContext()->paintSkPaint(destRect, paint);
diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
index b5f7e1d..1647b86 100644
--- a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
+++ b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
@@ -30,21 +30,21 @@
#include "config.h"
-#include "ImageSourceSkia.h"
+#include "ImageSource.h"
#include "SharedBuffer.h"
#include "GIFImageDecoder.h"
+#include "ICOImageDecoder.h"
#include "JPEGImageDecoder.h"
#include "PNGImageDecoder.h"
#include "BMPImageDecoder.h"
#include "XBMImageDecoder.h"
-#include "ICOImageDecoder.h"
#include "SkBitmap.h"
namespace WebCore {
-ImageDecoder* createDecoder(const Vector<char>& data, const IntSize& preferredIconSize)
+ImageDecoder* createDecoder(const Vector<char>& data)
{
// We need at least 4 bytes to figure out what kind of image we're dealing with.
int length = data.size();
@@ -79,7 +79,7 @@ ImageDecoder* createDecoder(const Vector<char>& data, const IntSize& preferredIc
// CURs begin with 2-byte 0 followed by 2-byte 2.
if (!memcmp(contents, "\000\000\001\000", 4) ||
!memcmp(contents, "\000\000\002\000", 4))
- return new ICOImageDecoder(preferredIconSize);
+ return new ICOImageDecoder();
// XBMs require 8 bytes of info.
if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
@@ -124,7 +124,7 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
// If insufficient bytes are available to determine the image type, no decoder plugin will be
// made.
if (!m_decoder)
- m_decoder = createDecoder(data->buffer(), IntSize());
+ m_decoder = createDecoder(data->buffer());
// CreateDecoder will return NULL if the decoder could not be created. Plus,
// we should not send more data to a decoder which has already decided it
@@ -150,10 +150,12 @@ IntSize ImageSource::size() const
return m_decoder->size();
}
-IntSize ImageSource::frameSizeAtIndex(size_t) const
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
{
- // TODO(brettw) do we need anything here?
- return size();
+ if (!m_decoder)
+ return IntSize();
+
+ return m_decoder->frameSizeAtIndex(index);
}
int ImageSource::repetitionCount()
@@ -185,9 +187,8 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
return 0;
// Copy the bitmap. The pixel data is refcounted internally by SkBitmap, so
- // this doesn't cost much. This pointer will be owned by the BitmapImage
- // and freed in FrameData::clear().
- return new NativeImageSkia(buffer->bitmap());
+ // this doesn't cost much.
+ return buffer->asNewNativeImage();
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
@@ -229,16 +230,6 @@ bool ImageSource::frameHasAlphaAtIndex(size_t index)
return buffer->hasAlpha();
}
-void ImageSourceSkia::setData(SharedBuffer* data,
- bool allDataReceived,
- const IntSize& preferredIconSize)
-{
- if (!m_decoder)
- m_decoder = createDecoder(data->buffer(), preferredIconSize);
-
- ImageSource::setData(data, allDataReceived);
-}
-
String ImageSource::filenameExtension() const
{
return m_decoder ? m_decoder->filenameExtension() : String();
diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp
index 9d9df52..5ac14b9 100644
--- a/WebCore/platform/graphics/skia/PathSkia.cpp
+++ b/WebCore/platform/graphics/skia/PathSkia.cpp
@@ -68,6 +68,11 @@ bool Path::isEmpty() const
return m_path->isEmpty();
}
+bool Path::hasCurrentPoint() const
+{
+ return m_path->getPoints(NULL, 0) != 0;
+}
+
bool Path::contains(const FloatPoint& point, WindRule rule) const
{
return SkPathContainsPoint(m_path, point,
@@ -81,15 +86,7 @@ void Path::translate(const FloatSize& size)
FloatRect Path::boundingRect() const
{
- // FIXME: This #ifdef can go away once we're firmly using the new Skia.
- // During the transition, this makes the code compatible with both versions.
-#ifdef SK_USE_OLD_255_TO_256
return m_path->getBounds();
-#else
- SkRect rect;
- m_path->computeBounds(&rect, SkPath::kExact_BoundsType);
- return rect;
-#endif
}
void Path::moveTo(const FloatPoint& point)
@@ -281,15 +278,7 @@ static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context)
context->platformContext()->setupPaintForStroking(&paint, 0, 0);
SkPath boundingPath;
paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath);
- // FIXME: This #ifdef can go away once we're firmly using the new Skia.
- // During the transition, this makes the code compatible with both versions.
-#ifdef SK_USE_OLD_255_TO_256
return boundingPath.getBounds();
-#else
- SkRect r;
- boundingPath.computeBounds(&r, SkPath::kExact_BoundsType);
- return r;
-#endif
}
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
diff --git a/WebCore/platform/graphics/skia/PatternSkia.cpp b/WebCore/platform/graphics/skia/PatternSkia.cpp
index be8eb8a..11b5cf1 100644
--- a/WebCore/platform/graphics/skia/PatternSkia.cpp
+++ b/WebCore/platform/graphics/skia/PatternSkia.cpp
@@ -33,8 +33,10 @@
#include "NativeImageSkia.h"
#include "TransformationMatrix.h"
-#include "SkShader.h"
#include "SkCanvas.h"
+#include "SkColor.h"
+#include "SkColorShader.h"
+#include "SkShader.h"
namespace WebCore {
@@ -49,6 +51,10 @@ PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& pa
// LayoutTests/svg/W3C-SVG-1.1/pservers-grad-06-b.svg
SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame();
+ // If we don't have a bitmap, return a transparent shader.
+ if (!bm)
+ return new SkColorShader(SkColorSetARGB(0, 0, 0, 0));
+
if (m_repeatX && m_repeatY)
return SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index 74b2bfe..e0a292c 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -57,18 +57,18 @@ struct PlatformContextSkia::State {
// Common shader state.
float m_alpha;
- SkPorterDuff::Mode m_porterDuffMode;
- SkShader* m_gradient;
- SkShader* m_pattern;
+ SkXfermode::Mode m_xferMode;
bool m_useAntialiasing;
SkDrawLooper* m_looper;
// Fill.
SkColor m_fillColor;
+ SkShader* m_fillShader;
// Stroke.
WebCore::StrokeStyle m_strokeStyle;
SkColor m_strokeColor;
+ SkShader* m_strokeShader;
float m_strokeThickness;
int m_dashRatio; // Ratio of the length of a dash to its width.
float m_miterLimit;
@@ -98,15 +98,15 @@ private:
// Note: Keep theses default values in sync with GraphicsContextState.
PlatformContextSkia::State::State()
: m_alpha(1)
- , m_porterDuffMode(SkPorterDuff::kSrcOver_Mode)
- , m_gradient(0)
- , m_pattern(0)
+ , m_xferMode(SkXfermode::kSrcOver_Mode)
, m_useAntialiasing(true)
, m_looper(0)
, m_fillColor(0xFF000000)
+ , m_fillShader(0)
, m_strokeStyle(WebCore::SolidStroke)
, m_strokeColor(WebCore::Color::black)
, m_strokeThickness(0)
+ , m_strokeShader(0)
, m_dashRatio(3)
, m_miterLimit(4)
, m_lineCap(SkPaint::kDefault_Cap)
@@ -118,15 +118,15 @@ PlatformContextSkia::State::State()
PlatformContextSkia::State::State(const State& other)
: m_alpha(other.m_alpha)
- , m_porterDuffMode(other.m_porterDuffMode)
- , m_gradient(other.m_gradient)
- , m_pattern(other.m_pattern)
+ , m_xferMode(other.m_xferMode)
, m_useAntialiasing(other.m_useAntialiasing)
, m_looper(other.m_looper)
, m_fillColor(other.m_fillColor)
+ , m_fillShader(other.m_fillShader)
, m_strokeStyle(other.m_strokeStyle)
, m_strokeColor(other.m_strokeColor)
, m_strokeThickness(other.m_strokeThickness)
+ , m_strokeShader(other.m_strokeShader)
, m_dashRatio(other.m_dashRatio)
, m_miterLimit(other.m_miterLimit)
, m_lineCap(other.m_lineCap)
@@ -141,16 +141,16 @@ PlatformContextSkia::State::State(const State& other)
// Up the ref count of these. saveRef does nothing if 'this' is NULL.
m_looper->safeRef();
m_dash->safeRef();
- m_gradient->safeRef();
- m_pattern->safeRef();
+ m_fillShader->safeRef();
+ m_strokeShader->safeRef();
}
PlatformContextSkia::State::~State()
{
m_looper->safeUnref();
m_dash->safeUnref();
- m_gradient->safeUnref();
- m_pattern->safeUnref();
+ m_fillShader->safeUnref();
+ m_strokeShader->safeUnref();
}
SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
@@ -170,7 +170,6 @@ SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
// Danger: canvas can be NULL.
PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
: m_canvas(canvas)
- , m_stateStack(sizeof(State))
#if PLATFORM(WIN_OS)
, m_drawingToImageBuffer(false)
#endif
@@ -274,8 +273,11 @@ void PlatformContextSkia::drawRect(SkRect rect)
(m_state->m_strokeColor & 0xFF000000)) {
// We do a fill of four rects to simulate the stroke of a border.
SkColor oldFillColor = m_state->m_fillColor;
- if (oldFillColor != m_state->m_strokeColor)
- setFillColor(m_state->m_strokeColor);
+
+ // setFillColor() will set the shader to NULL, so save a ref to it now.
+ SkShader* oldFillShader = m_state->m_fillShader;
+ oldFillShader->safeRef();
+ setFillColor(m_state->m_strokeColor);
setupPaintForFilling(&paint);
SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 };
canvas()->drawRect(topBorder, paint);
@@ -285,8 +287,9 @@ void PlatformContextSkia::drawRect(SkRect rect)
canvas()->drawRect(leftBorder, paint);
SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 };
canvas()->drawRect(rightBorder, paint);
- if (oldFillColor != m_state->m_strokeColor)
- setFillColor(oldFillColor);
+ setFillColor(oldFillColor);
+ setFillShader(oldFillShader);
+ oldFillShader->safeUnref();
}
}
@@ -300,19 +303,15 @@ void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
#endif
paint->setAntiAlias(m_state->m_useAntialiasing);
- paint->setPorterDuffXfermode(m_state->m_porterDuffMode);
+ paint->setXfermodeMode(m_state->m_xferMode);
paint->setLooper(m_state->m_looper);
-
- if (m_state->m_gradient)
- paint->setShader(m_state->m_gradient);
- else if (m_state->m_pattern)
- paint->setShader(m_state->m_pattern);
}
void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
{
setupPaintCommon(paint);
paint->setColor(m_state->applyAlpha(m_state->m_fillColor));
+ paint->setShader(m_state->m_fillShader);
}
float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
@@ -321,6 +320,7 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
float width = m_state->m_strokeThickness;
paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
+ paint->setShader(m_state->m_strokeShader);
paint->setStyle(SkPaint::kStroke_Style);
paint->setStrokeWidth(SkFloatToScalar(width));
paint->setStrokeCap(m_state->m_lineCap);
@@ -338,20 +338,27 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
width = m_state->m_dashRatio * width;
// Fall through.
case WebCore::DottedStroke:
- SkScalar dashLength;
- if (length) {
- // Determine about how many dashes or dots we should have.
- float roundedWidth = roundf(width);
- int numDashes = roundedWidth ? (length / roundedWidth) : length;
- if (!(numDashes & 1))
- numDashes++; // Make it odd so we end on a dash/dot.
- // Use the number of dashes to determine the length of a
- // dash/dot, which will be approximately width
- dashLength = SkScalarDiv(SkIntToScalar(length), SkIntToScalar(numDashes));
- } else
- dashLength = SkFloatToScalar(width);
- SkScalar intervals[2] = { dashLength, dashLength };
- paint->setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref();
+ // Truncate the width, since we don't want fuzzy dots or dashes.
+ int dashLength = static_cast<int>(width);
+ // Subtract off the endcaps, since they're rendered separately.
+ int distance = length - 2 * static_cast<int>(m_state->m_strokeThickness);
+ int phase = 1;
+ if (dashLength > 1) {
+ // Determine how many dashes or dots we should have.
+ int numDashes = distance / dashLength;
+ int remainder = distance % dashLength;
+ // Adjust the phase to center the dashes within the line.
+ if (numDashes % 2 == 0) {
+ // Even: shift right half a dash, minus half the remainder
+ phase = (dashLength - remainder) / 2;
+ } else {
+ // Odd: shift right a full dash, minus half the remainder
+ phase = dashLength - remainder / 2;
+ }
+ }
+ SkScalar dashLengthSk = SkIntToScalar(dashLength);
+ SkScalar intervals[2] = { dashLengthSk, dashLengthSk };
+ paint->setPathEffect(new SkDashPathEffect(intervals, 2, SkIntToScalar(phase)))->unref();
}
}
@@ -383,14 +390,15 @@ void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
m_state->m_lineJoin = lj;
}
-void PlatformContextSkia::setPorterDuffMode(SkPorterDuff::Mode pdm)
+void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm)
{
- m_state->m_porterDuffMode = pdm;
+ m_state->m_xferMode = pdm;
}
void PlatformContextSkia::setFillColor(SkColor color)
{
m_state->m_fillColor = color;
+ setFillShader(NULL);
}
SkDrawLooper* PlatformContextSkia::getDrawLooper() const
@@ -411,6 +419,7 @@ void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle)
void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
{
m_state->m_strokeColor = strokeColor;
+ setStrokeShader(NULL);
}
float PlatformContextSkia::getStrokeThickness() const
@@ -423,6 +432,15 @@ void PlatformContextSkia::setStrokeThickness(float thickness)
m_state->m_strokeThickness = thickness;
}
+void PlatformContextSkia::setStrokeShader(SkShader* strokeShader)
+{
+ if (strokeShader != m_state->m_strokeShader) {
+ m_state->m_strokeShader->safeUnref();
+ m_state->m_strokeShader = strokeShader;
+ m_state->m_strokeShader->safeRef();
+ }
+}
+
int PlatformContextSkia::getTextDrawingMode() const
{
return m_state->m_textDrawingMode;
@@ -471,7 +489,8 @@ SkPath PlatformContextSkia::currentPathInLocalCoordinates() const
SkPath localPath = m_path;
const SkMatrix& matrix = m_canvas->getTotalMatrix();
SkMatrix inverseMatrix;
- matrix.invert(&inverseMatrix);
+ if (!matrix.invert(&inverseMatrix))
+ return SkPath();
localPath.transform(inverseMatrix);
return localPath;
}
@@ -481,19 +500,12 @@ void PlatformContextSkia::setFillRule(SkPath::FillType fr)
m_path.setFillType(fr);
}
-void PlatformContextSkia::setGradient(SkShader* gradient)
-{
- if (gradient != m_state->m_gradient) {
- m_state->m_gradient->safeUnref();
- m_state->m_gradient = gradient;
- }
-}
-
-void PlatformContextSkia::setPattern(SkShader* pattern)
+void PlatformContextSkia::setFillShader(SkShader* fillShader)
{
- if (pattern != m_state->m_pattern) {
- m_state->m_pattern->safeUnref();
- m_state->m_pattern = pattern;
+ if (fillShader != m_state->m_fillShader) {
+ m_state->m_fillShader->safeUnref();
+ m_state->m_fillShader = fillShader;
+ m_state->m_fillShader->safeRef();
}
}
@@ -527,7 +539,7 @@ void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, con
// NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
// only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
SkPaint paint;
- paint.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode);
+ paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
}
#endif
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h
index 25495aa..0c87fc2 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.h
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -60,7 +60,7 @@
// responsible for managing the painting state which is store in separate
// SkPaint objects. This class provides the adaptor that allows the painting
// state to be pushed and popped along with the bitmap.
-class PlatformContextSkia : Noncopyable {
+class PlatformContextSkia : public Noncopyable {
public:
// For printing, there shouldn't be any canvas. canvas can be NULL. If you
// supply a NULL canvas, you can also call setCanvas later.
@@ -115,15 +115,15 @@ public:
void setLineCap(SkPaint::Cap);
void setLineJoin(SkPaint::Join);
void setFillRule(SkPath::FillType);
- void setPorterDuffMode(SkPorterDuff::Mode);
+ void setXfermodeMode(SkXfermode::Mode);
void setFillColor(SkColor);
+ void setFillShader(SkShader*);
void setStrokeStyle(WebCore::StrokeStyle);
void setStrokeColor(SkColor);
void setStrokeThickness(float thickness);
+ void setStrokeShader(SkShader*);
void setTextDrawingMode(int mode);
void setUseAntialiasing(bool enable);
- void setGradient(SkShader*);
- void setPattern(SkShader*);
void setDashPathEffect(SkDashPathEffect*);
SkDrawLooper* getDrawLooper() const;
diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
index 7f12508..f1c5cdc 100644
--- a/WebCore/platform/graphics/skia/SkiaFontWin.cpp
+++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
@@ -267,21 +267,11 @@ static bool skiaDrawText(HFONT hfont,
SkCanvas* canvas,
const SkPoint& point,
SkPaint* paint,
- const TransformationMatrix& transformationMatrix,
- Gradient* gradient,
- Pattern* pattern,
const WORD* glyphs,
const int* advances,
const GOFFSET* offsets,
int numGlyphs)
{
- SkShader* shader = NULL;
- if (gradient)
- shader = gradient->platformGradient();
- else if (pattern)
- shader = pattern->createPlatformPattern(transformationMatrix);
-
- paint->setShader(shader);
float x = point.fX, y = point.fY;
for (int i = 0; i < numGlyphs; i++) {
@@ -326,14 +316,7 @@ bool paintSkiaText(GraphicsContext* context,
bool didFill = false;
if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {
- Gradient* fillGradient = 0;
- Pattern* fillPattern = 0;
- if (context->fillColorSpace() == GradientColorSpace)
- fillGradient = context->fillGradient();
- else if (context->fillColorSpace() == PatternColorSpace)
- fillPattern = context->fillPattern();
if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
- context->getCTM(), fillGradient, fillPattern,
&glyphs[0], &advances[0], &offsets[0], numGlyphs))
return false;
didFill = true;
@@ -360,14 +343,7 @@ bool paintSkiaText(GraphicsContext* context,
paint.setLooper(0)->safeUnref();
}
- Gradient* strokeGradient = 0;
- Pattern* strokePattern = 0;
- if (context->strokeColorSpace() == GradientColorSpace)
- strokeGradient = context->strokeGradient();
- else if (context->strokeColorSpace() == PatternColorSpace)
- strokePattern = context->strokePattern();
if (!skiaDrawText(hfont, dc, platformContext->canvas(), *origin, &paint,
- context->getCTM(), strokeGradient, strokePattern,
&glyphs[0], &advances[0], &offsets[0], numGlyphs))
return false;
}
diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp
index a7a266d..dbbbdbf 100644
--- a/WebCore/platform/graphics/skia/SkiaUtils.cpp
+++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp
@@ -42,6 +42,7 @@
namespace WebCore {
+#ifdef MANUAL_MERGE_REQUIRED
static const struct CompositOpToSkiaMode {
uint8_t mCompositOp;
uint8_t mMode;
@@ -77,36 +78,39 @@ SkXfermode::Mode WebCoreCompositeToSkiaMode(CompositeOperator op)
}
static const struct CompositOpToPorterDuffMode {
+#else // MANUAL_MERGE_REQUIRED
+static const struct CompositOpToXfermodeMode {
+#endif // MANUAL_MERGE_REQUIRED
uint8_t mCompositOp;
- uint8_t mPorterDuffMode;
-} gMapCompositOpsToPorterDuffModes[] = {
- { CompositeClear, SkPorterDuff::kClear_Mode },
- { CompositeCopy, SkPorterDuff::kSrc_Mode },
- { CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
- { CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
- { CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
- { CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode },
- { CompositeDestinationOver, SkPorterDuff::kDstOver_Mode },
- { CompositeDestinationIn, SkPorterDuff::kDstIn_Mode },
- { CompositeDestinationOut, SkPorterDuff::kDstOut_Mode },
- { CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode },
- { CompositeXOR, SkPorterDuff::kXor_Mode },
- { CompositePlusDarker, SkPorterDuff::kDarken_Mode },
- { CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO
- { CompositePlusLighter, SkPorterDuff::kAdd_Mode }
+ uint8_t m_xfermodeMode;
+} gMapCompositOpsToXfermodeModes[] = {
+ { CompositeClear, SkXfermode::kClear_Mode },
+ { CompositeCopy, SkXfermode::kSrc_Mode },
+ { CompositeSourceOver, SkXfermode::kSrcOver_Mode },
+ { CompositeSourceIn, SkXfermode::kSrcIn_Mode },
+ { CompositeSourceOut, SkXfermode::kSrcOut_Mode },
+ { CompositeSourceAtop, SkXfermode::kSrcATop_Mode },
+ { CompositeDestinationOver, SkXfermode::kDstOver_Mode },
+ { CompositeDestinationIn, SkXfermode::kDstIn_Mode },
+ { CompositeDestinationOut, SkXfermode::kDstOut_Mode },
+ { CompositeDestinationAtop, SkXfermode::kDstATop_Mode },
+ { CompositeXOR, SkXfermode::kXor_Mode },
+ { CompositePlusDarker, SkXfermode::kDarken_Mode },
+ { CompositeHighlight, SkXfermode::kSrcOver_Mode }, // TODO
+ { CompositePlusLighter, SkXfermode::kPlus_Mode }
};
-SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op)
+SkXfermode::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op)
{
- const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes;
+ const CompositOpToXfermodeMode* table = gMapCompositOpsToXfermodeModes;
- for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) {
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToXfermodeModes); i++) {
if (table[i].mCompositOp == op)
- return (SkPorterDuff::Mode)table[i].mPorterDuffMode;
+ return (SkXfermode::Mode)table[i].m_xfermodeMode;
}
SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositeOperator %d\n", op));
- return SkPorterDuff::kSrcOver_Mode; // fall-back
+ return SkXfermode::kSrcOver_Mode; // fall-back
}
Color SkPMColorToWebCoreColor(SkPMColor pm)
@@ -168,8 +172,12 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::
SkPath scaledPath;
int scale = 1;
+#ifdef MANUAL_MERGE_REQUIRED
SkRect bounds;
bounds = originalPath->getBounds();
+#else // MANUAL_MERGE_REQUIRED
+ SkRect bounds = originalPath->getBounds();
+#endif // MANUAL_MERGE_REQUIRED
// We can immediately return false if the point is outside the bounding rect
if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y())))
@@ -208,7 +216,7 @@ GraphicsContext* scratchContext()
{
static ImageBuffer* scratch = 0;
if (!scratch)
- scratch = ImageBuffer::create(IntSize(1, 1), false).release();
+ scratch = ImageBuffer::create(IntSize(1, 1)).release();
// We don't bother checking for failure creating the ImageBuffer, since our
// ImageBuffer initializer won't fail.
return scratch->context();
diff --git a/WebCore/platform/graphics/skia/SkiaUtils.h b/WebCore/platform/graphics/skia/SkiaUtils.h
index aa4cd4d..a210cd3 100644
--- a/WebCore/platform/graphics/skia/SkiaUtils.h
+++ b/WebCore/platform/graphics/skia/SkiaUtils.h
@@ -36,16 +36,24 @@
#include <wtf/MathExtras.h>
#include "GraphicsContext.h"
#include "SkPath.h"
+#ifdef MANUAL_MERGE_REQUIRED
#include "SkPorterDuff.h"
#include "SkXfermode.h"
+#else // MANUAL_MERGE_REQUIRED
+#include "SkXfermode.h"
+#endif // MANUAL_MERGE_REQUIRED
class SkCanvas;
class SkRegion;
namespace WebCore {
+#ifdef MANUAL_MERGE_REQUIRED
SkXfermode::Mode WebCoreCompositeToSkiaMode(CompositeOperator);
SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator);
+#else // MANUAL_MERGE_REQUIRED
+SkXfermode::Mode WebCoreCompositeToSkiaComposite(CompositeOperator);
+#endif // MANUAL_MERGE_REQUIRED
// move this guy into SkColor.h
SkColor SkPMColorToColor(SkPMColor);
diff --git a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
index ab3413b..230be3c 100644
--- a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp
@@ -47,7 +47,7 @@ PassRefPtr<TransformOperation> Matrix3DTransformOperation::blend(const Transform
apply(toT, size);
if (blendToIdentity)
- swap(fromT, toT);
+ std::swap(fromT, toT);
toT.blend(fromT, progress);
return Matrix3DTransformOperation::create(toT);
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
index 4934fa6..0eaccea 100644
--- a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
@@ -43,7 +43,7 @@ PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOp
}
if (blendToIdentity)
- swap(fromT, toT);
+ std::swap(fromT, toT);
toT.blend(fromT, progress);
return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f());
diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h
index 11605e8..dd56408 100644
--- a/WebCore/platform/graphics/transforms/TransformOperations.h
+++ b/WebCore/platform/graphics/transforms/TransformOperations.h
@@ -60,6 +60,9 @@ public:
Vector<RefPtr<TransformOperation> >& operations() { return m_operations; }
const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; }
+ size_t size() const { return m_operations.size(); }
+ const TransformOperation* at(size_t index) const { return index < m_operations.size() ? m_operations.at(index).get() : 0; }
+
private:
Vector<RefPtr<TransformOperation> > m_operations;
};
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
index a358aaf..13ef281 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -865,6 +866,16 @@ TransformationMatrix& TransformationMatrix::applyPerspective(double p)
return *this;
}
+TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to)
+{
+ ASSERT(!from.isEmpty());
+ return TransformationMatrix(to.width() / from.width(),
+ 0, 0,
+ to.height() / from.height(),
+ to.x() - from.x(),
+ to.y() - from.y());
+}
+
//
// *this = mat * *this
//
diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h
index 7b93e04..a7fbb3d 100644
--- a/WebCore/platform/graphics/transforms/TransformationMatrix.h
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -225,6 +225,9 @@ public:
TransformationMatrix& applyPerspective(double p);
bool hasPerspective() const { return m_matrix[2][3] != 0.0f; }
+ // returns a transformation that maps a rect to a rect
+ static TransformationMatrix rectToRect(const FloatRect&, const FloatRect&);
+
bool isInvertible() const;
// This method returns the identity matrix if it is not invertible.
@@ -284,7 +287,7 @@ public:
}
// result = *this * t (i.e., a multRight)
- TransformationMatrix operator*(const TransformationMatrix& t)
+ TransformationMatrix operator*(const TransformationMatrix& t) const
{
TransformationMatrix result = t;
result.multLeft(*this);
@@ -303,6 +306,10 @@ public:
operator wxGraphicsMatrix() const;
#endif
+#if PLATFORM(WIN)
+ operator XFORM() const;
+#endif
+
private:
// multiply passed 2D point by matrix (assume z=0)
void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
diff --git a/WebCore/platform/graphics/win/ColorSafari.cpp b/WebCore/platform/graphics/win/ColorSafari.cpp
deleted file mode 100644
index 25b6b89..0000000
--- a/WebCore/platform/graphics/win/ColorSafari.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Color.h"
-
-#include <CoreGraphics/CGColor.h>
-#include <SafariTheme/SafariTheme.h>
-#include <wtf/Assertions.h>
-#include <wtf/RetainPtr.h>
-
-using namespace SafariTheme;
-
-namespace WebCore {
-
-typedef CGColorRef (APIENTRY*stCopyThemeColorPtr)(unsigned, SafariTheme::ThemeControlState);
-static const unsigned stFocusRingColorID = 4;
-
-static const unsigned aquaFocusRingColor = 0xFF7DADD9;
-
-static RGBA32 makeRGBAFromCGColor(CGColorRef c)
-{
- const CGFloat* components = CGColorGetComponents(c);
- return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]);
-}
-
-Color focusRingColor()
-{
- static Color focusRingColor;
- focusRingColor.isValid();
-
- if (!focusRingColor.isValid()) {
- if (HMODULE module = LoadLibrary(SAFARITHEMEDLL))
- if (stCopyThemeColorPtr stCopyThemeColor = (stCopyThemeColorPtr)GetProcAddress(module, "STCopyThemeColor")) {
- RetainPtr<CGColorRef> c(AdoptCF, stCopyThemeColor(stFocusRingColorID, SafariTheme::ActiveState));
- focusRingColor = makeRGBAFromCGColor(c.get());
- }
- if (!focusRingColor.isValid())
- focusRingColor = aquaFocusRingColor;
- }
-
- return focusRingColor;
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h
index 09a8b55..0660d90 100644
--- a/WebCore/platform/graphics/win/FontPlatformData.h
+++ b/WebCore/platform/graphics/win/FontPlatformData.h
@@ -39,6 +39,7 @@ typedef struct CGFont* CGFontRef;
namespace WebCore {
class FontDescription;
+class String;
class FontPlatformData {
public:
@@ -64,6 +65,9 @@ public:
FontPlatformData(HFONT, CGFontRef, float size, bool bold, bool oblique, bool useGDI);
#elif PLATFORM(CAIRO)
FontPlatformData(cairo_font_face_t*, float size, bool bold, bool oblique);
+ FontPlatformData(const FontPlatformData&);
+
+ FontPlatformData& operator=(const FontPlatformData&);
#endif
~FontPlatformData();
@@ -104,6 +108,10 @@ public:
m_useGDI == other.m_useGDI;
}
+#ifndef NDEBUG
+ String description() const;
+#endif
+
private:
class RefCountedHFONT : public RefCounted<RefCountedHFONT> {
public:
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
index 59f7e5c..a92e367 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -137,4 +137,8 @@ FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool
{
}
+FontPlatformData::~FontPlatformData()
+{
+}
+
}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
index 438d0a9..b56a71c 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
@@ -41,6 +41,7 @@ namespace WebCore {
void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
{
m_fontFace = cairo_win32_font_face_create_for_hfont(font);
+
cairo_matrix_t sizeMatrix, ctm;
cairo_matrix_init_identity(&ctm);
cairo_matrix_init_scale(&sizeMatrix, size, size);
@@ -79,6 +80,22 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool
cairo_font_options_destroy(options);
}
+FontPlatformData::FontPlatformData(const FontPlatformData& source)
+ : m_font(source.m_font)
+ , m_size(source.m_size)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+ , m_syntheticBold(source.m_syntheticBold)
+ , m_syntheticOblique(source.m_syntheticOblique)
+ , m_useGDI(source.m_useGDI)
+{
+ if (source.m_fontFace)
+ m_fontFace = cairo_font_face_reference(source.m_fontFace);
+
+ if (source.m_scaledFont)
+ m_scaledFont = cairo_scaled_font_reference(source.m_scaledFont);
+}
+
void FontPlatformData::setFont(cairo_t* cr) const
{
ASSERT(m_scaledFont);
@@ -86,4 +103,37 @@ void FontPlatformData::setFont(cairo_t* cr) const
cairo_set_scaled_font(cr, m_scaledFont);
}
+FontPlatformData::~FontPlatformData()
+{
+ cairo_scaled_font_destroy(m_scaledFont);
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ // Check for self-assignment.
+ if (this == &other)
+ return *this;
+
+ m_font = other.m_font;
+ m_size = other.m_size;
+ m_syntheticBold = other.m_syntheticBold;
+ m_syntheticOblique = other.m_syntheticOblique;
+ m_useGDI = other.m_useGDI;
+
+ if (other.m_fontFace)
+ cairo_font_face_reference(other.m_fontFace);
+ if (m_fontFace)
+ cairo_font_face_destroy(m_fontFace);
+ m_fontFace = other.m_fontFace;
+
+ if (other.m_scaledFont)
+ cairo_scaled_font_reference(other.m_scaledFont);
+ if (m_scaledFont)
+ cairo_scaled_font_destroy(m_scaledFont);
+ m_scaledFont = other.m_scaledFont;
+
+ return *this;
+}
+
}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
index 4b4df5a..cc02c4c 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -85,8 +85,11 @@ FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
{
}
-FontPlatformData::~FontPlatformData()
+#ifndef NDEBUG
+String FontPlatformData::description() const
{
+ return String();
}
+#endif
}
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index 917631b..9eaf54b 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -77,64 +77,6 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API
// suitable for all clients?
-HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
-{
- // FIXME: Should a bitmap be created also when a shadow is set?
- if (mayCreateBitmap && inTransparencyLayer()) {
- if (dstRect.isEmpty())
- return 0;
-
- // Create a bitmap DC in which to draw.
- BITMAPINFO bitmapInfo;
- bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bitmapInfo.bmiHeader.biWidth = dstRect.width();
- bitmapInfo.bmiHeader.biHeight = dstRect.height();
- bitmapInfo.bmiHeader.biPlanes = 1;
- bitmapInfo.bmiHeader.biBitCount = 32;
- bitmapInfo.bmiHeader.biCompression = BI_RGB;
- bitmapInfo.bmiHeader.biSizeImage = 0;
- bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
- bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
- bitmapInfo.bmiHeader.biClrUsed = 0;
- bitmapInfo.bmiHeader.biClrImportant = 0;
-
- void* pixels = 0;
- HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
- if (!bitmap)
- return 0;
-
- HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc);
- ::SelectObject(bitmapDC, bitmap);
-
- // Fill our buffer with clear if we're going to alpha blend.
- if (supportAlphaBlend) {
- BITMAP bmpInfo;
- GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
- int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
- memset(bmpInfo.bmBits, 0, bufferSize);
- }
-
- // Make sure we can do world transforms.
- SetGraphicsMode(bitmapDC, GM_ADVANCED);
-
- // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
- XFORM xform;
- xform.eM11 = 1.0f;
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = 1.0f;
- xform.eDx = -dstRect.x();
- xform.eDy = -dstRect.y();
- ::SetWorldTransform(bitmapDC, &xform);
-
- return bitmapDC;
- }
-
- CGContextFlush(platformContext());
- m_data->save();
- return m_data->m_hdc;
-}
-
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
if (mayCreateBitmap && hdc && inTransparencyLayer()) {
@@ -170,52 +112,6 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
m_data->restore();
}
-GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
- : m_hdc(0)
- , m_size(size)
-{
- BITMAPINFO bitmapInfo;
- bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bitmapInfo.bmiHeader.biWidth = m_size.width();
- bitmapInfo.bmiHeader.biHeight = m_size.height();
- bitmapInfo.bmiHeader.biPlanes = 1;
- bitmapInfo.bmiHeader.biBitCount = 32;
- bitmapInfo.bmiHeader.biCompression = BI_RGB;
- bitmapInfo.bmiHeader.biSizeImage = 0;
- bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
- bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
- bitmapInfo.bmiHeader.biClrUsed = 0;
- bitmapInfo.bmiHeader.biClrImportant = 0;
-
- m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&m_bitmapBuffer), 0, 0);
- if (!m_bitmap)
- return;
-
- m_hdc = CreateCompatibleDC(hdc);
- SelectObject(m_hdc, m_bitmap);
-
- BITMAP bmpInfo;
- GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo);
- m_bytesPerRow = bmpInfo.bmWidthBytes;
- m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
-
- SetGraphicsMode(m_hdc, GM_ADVANCED);
-}
-
-GraphicsContext::WindowsBitmap::~WindowsBitmap()
-{
- if (!m_bitmap)
- return;
-
- DeleteDC(m_hdc);
- DeleteObject(m_bitmap);
-}
-
-GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize size)
-{
- return new WindowsBitmap(m_data->m_hdc, size);
-}
-
void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
{
RetainPtr<CGColorSpaceRef> deviceRGB(AdoptCF, CGColorSpaceCreateDeviceRGB());
@@ -228,23 +124,6 @@ void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& po
CGContextDrawImage(m_data->m_cgContext, CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get());
}
-void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform)
-{
- if (!m_hdc)
- return;
-
- CGAffineTransform mat = transform;
- XFORM xform;
- xform.eM11 = mat.a;
- xform.eM12 = mat.b;
- xform.eM21 = mat.c;
- xform.eM22 = mat.d;
- xform.eDx = mat.tx;
- xform.eDy = mat.ty;
-
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
-}
-
void GraphicsContext::drawFocusRing(const Color& color)
{
if (paintingDisabled())
@@ -362,4 +241,9 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point,
CGContextRestoreGState(context);
}
+void GraphicsContextPlatformPrivate::flush()
+{
+ CGContextFlush(m_cgContext);
+}
+
}
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index ca3cb5d..2489e02 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -59,32 +59,6 @@ static cairo_t* createCairoContextWithHDC(HDC hdc, bool hasAlpha)
return context;
}
-static BITMAPINFO bitmapInfoForSize(const IntSize& size)
-{
- BITMAPINFO bitmapInfo;
- bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bitmapInfo.bmiHeader.biWidth = size.width();
- bitmapInfo.bmiHeader.biHeight = size.height();
- bitmapInfo.bmiHeader.biPlanes = 1;
- bitmapInfo.bmiHeader.biBitCount = 32;
- bitmapInfo.bmiHeader.biCompression = BI_RGB;
- bitmapInfo.bmiHeader.biSizeImage = 0;
- bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
- bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
- bitmapInfo.bmiHeader.biClrUsed = 0;
- bitmapInfo.bmiHeader.biClrImportant = 0;
-
- return bitmapInfo;
-}
-
-static void fillWithClearColor(HBITMAP bitmap)
-{
- BITMAP bmpInfo;
- GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
- int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
- memset(bmpInfo.bmBits, 0, bufferSize);
-}
-
GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
: m_common(createGraphicsContextPrivate())
, m_data(new GraphicsContextPlatformPrivate)
@@ -105,53 +79,6 @@ GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
}
}
-HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
-{
- // FIXME: Should a bitmap be created also when a shadow is set?
- if (mayCreateBitmap && inTransparencyLayer()) {
- if (dstRect.isEmpty())
- return 0;
-
- // Create a bitmap DC in which to draw.
- BITMAPINFO bitmapInfo = bitmapInfoForSize(dstRect.size());
-
- void* pixels = 0;
- HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
- if (!bitmap)
- return 0;
-
- HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc);
- ::SelectObject(bitmapDC, bitmap);
-
- // Fill our buffer with clear if we're going to alpha blend.
- if (supportAlphaBlend)
- fillWithClearColor(bitmap);
-
- // Make sure we can do world transforms.
- SetGraphicsMode(bitmapDC, GM_ADVANCED);
-
- // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
- XFORM xform;
- xform.eM11 = 1.0f;
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = 1.0f;
- xform.eDx = -dstRect.x();
- xform.eDy = -dstRect.y();
- ::SetWorldTransform(bitmapDC, &xform);
-
- return bitmapDC;
- }
-
- cairo_surface_t* surface = cairo_win32_surface_create(m_data->m_hdc);
- cairo_surface_flush(surface);
- cairo_surface_destroy(surface);
-
- m_data->save();
-
- return m_data->m_hdc;
-}
-
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
if (!mayCreateBitmap || !hdc || !inTransparencyLayer()) {
@@ -194,27 +121,22 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
::DeleteObject(bitmap);
}
-void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform)
-{
- const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
-
- XFORM xform;
- xform.eM11 = matrix->xx;
- xform.eM12 = matrix->xy;
- xform.eM21 = matrix->yx;
- xform.eM22 = matrix->yy;
- xform.eDx = matrix->x0;
- xform.eDy = matrix->y0;
-
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
-}
-
void GraphicsContextPlatformPrivate::syncContext(PlatformGraphicsContext* cr)
{
+ if (!cr)
+ return;
+
cairo_surface_t* surface = cairo_get_target(cr);
m_hdc = cairo_win32_surface_get_dc(surface);
SetGraphicsMode(m_hdc, GM_ADVANCED); // We need this call for themes to honor world transforms.
}
+void GraphicsContextPlatformPrivate::flush()
+{
+ cairo_surface_t* surface = cairo_win32_surface_create(m_hdc);
+ cairo_surface_flush(surface);
+ cairo_surface_destroy(surface);
+}
+
}
diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
index e4c5b04..54b0cb2 100644
--- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -32,6 +32,7 @@
#include "GraphicsContextPlatformPrivateCairo.h"
#endif
+#include "BitmapInfo.h"
#include "TransformationMatrix.h"
#include "NotImplemented.h"
#include "Path.h"
@@ -43,6 +44,14 @@ namespace WebCore {
class SVGResourceImage;
+static void fillWithClearColor(HBITMAP bitmap)
+{
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+}
+
bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
void GraphicsContext::setShouldIncludeChildWindows(bool include)
@@ -55,6 +64,79 @@ bool GraphicsContext::shouldIncludeChildWindows() const
return m_data->m_shouldIncludeChildWindows;
}
+GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
+ : m_hdc(0)
+ , m_size(size)
+{
+ BitmapInfo bitmapInfo = BitmapInfo::create(m_size);
+
+ m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&m_bitmapBuffer), 0, 0);
+ if (!m_bitmap)
+ return;
+
+ m_hdc = CreateCompatibleDC(hdc);
+ SelectObject(m_hdc, m_bitmap);
+
+ BITMAP bmpInfo;
+ GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo);
+ m_bytesPerRow = bmpInfo.bmWidthBytes;
+ m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ SetGraphicsMode(m_hdc, GM_ADVANCED);
+}
+
+GraphicsContext::WindowsBitmap::~WindowsBitmap()
+{
+ if (!m_bitmap)
+ return;
+
+ DeleteDC(m_hdc);
+ DeleteObject(m_bitmap);
+}
+
+GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize size)
+{
+ return new WindowsBitmap(m_data->m_hdc, size);
+}
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // FIXME: Should a bitmap be created also when a shadow is set?
+ if (mayCreateBitmap && inTransparencyLayer()) {
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BitmapInfo bitmapInfo = BitmapInfo::create(dstRect.size());
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc);
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend)
+ fillWithClearColor(bitmap);
+
+ // Make sure we can do world transforms.
+ SetGraphicsMode(bitmapDC, GM_ADVANCED);
+
+ // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
+ XFORM xform = TransformationMatrix().translate(-dstRect.x(), -dstRect.y());
+
+ ::SetWorldTransform(bitmapDC, &xform);
+
+ return bitmapDC;
+ }
+
+ m_data->flush();
+ m_data->save();
+ return m_data->m_hdc;
+}
+
void GraphicsContextPlatformPrivate::save()
{
if (!m_hdc)
@@ -85,13 +167,8 @@ void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
{
if (!m_hdc)
return;
- XFORM xform;
- xform.eM11 = size.width();
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = size.height();
- xform.eDx = 0.0f;
- xform.eDy = 0.0f;
+
+ XFORM xform = TransformationMatrix().scaleNonUniform(size.width(), size.height());
ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
}
@@ -99,16 +176,7 @@ static const double deg2rad = 0.017453292519943295769; // pi/180
void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
{
- float radiansAngle = degreesAngle * deg2rad;
- float cosAngle = cosf(radiansAngle);
- float sinAngle = sinf(radiansAngle);
- XFORM xform;
- xform.eM11 = cosAngle;
- xform.eM12 = -sinAngle;
- xform.eM21 = sinAngle;
- xform.eM22 = cosAngle;
- xform.eDx = 0.0f;
- xform.eDy = 0.0f;
+ XFORM xform = TransformationMatrix().rotate(degreesAngle);
ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
}
@@ -116,13 +184,17 @@ void GraphicsContextPlatformPrivate::translate(float x , float y)
{
if (!m_hdc)
return;
- XFORM xform;
- xform.eM11 = 1.0f;
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = 1.0f;
- xform.eDx = x;
- xform.eDy = y;
+
+ XFORM xform = TransformationMatrix().translate(x, y);
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform)
+{
+ if (!m_hdc)
+ return;
+
+ XFORM xform = transform;
ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
}
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
index c02b56e..61f1fd3 100644
--- a/WebCore/platform/graphics/win/IconWin.cpp
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+* 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
@@ -26,6 +27,11 @@
#include <tchar.h>
#include <windows.h>
+#if PLATFORM(WINCE)
+// SHGFI_SHELLICONSIZE is not available on WINCE
+#define SHGFI_SHELLICONSIZE 0
+#endif
+
namespace WebCore {
static const int shell32MultipleFileIconIndex = 54;
@@ -55,6 +61,9 @@ PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&)
{
+#if PLATFORM(WINCE)
+ return 0;
+#else
TCHAR buffer[MAX_PATH];
UINT length = ::GetSystemDirectory(buffer, ARRAYSIZE(buffer));
if (!length)
@@ -67,6 +76,7 @@ PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&)
if (!::ExtractIconEx(buffer, shell32MultipleFileIconIndex, 0, &hIcon, 1))
return 0;
return adoptRef(new Icon(hIcon));
+#endif
}
void Icon::paint(GraphicsContext* context, const IntRect& r)
@@ -74,11 +84,15 @@ void Icon::paint(GraphicsContext* context, const IntRect& r)
if (context->paintingDisabled())
return;
+#if PLATFORM(WINCE)
+ context->drawIcon(m_hIcon, r, DI_NORMAL);
+#else
HDC hdc = context->getWindowsContext(r);
DrawIconEx(hdc, r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL);
context->releaseWindowsContext(hdc, r);
+#endif
}
}
diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp
index 752729c..8a8e943 100644
--- a/WebCore/platform/graphics/win/ImageCGWin.cpp
+++ b/WebCore/platform/graphics/win/ImageCGWin.cpp
@@ -65,8 +65,8 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp)
{
- int frames = frameCount();
- for (int i = 0; i < frames; ++i) {
+ size_t frames = frameCount();
+ for (size_t i = 0; i < frames; ++i) {
CGImageRef image = frameAtIndex(i);
if (CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) {
size_t currentFrame = m_currentFrame;
diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp
index 06428b8..591375f 100644
--- a/WebCore/platform/graphics/win/ImageCairoWin.cpp
+++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp
@@ -73,8 +73,8 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp)
{
- int frames = frameCount();
- for (int i = 0; i < frames; ++i) {
+ size_t frames = frameCount();
+ for (size_t i = 0; i < frames; ++i) {
cairo_surface_t* image = frameAtIndex(i);
if (cairo_image_surface_get_height(image) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast<size_t>(srcSize.width())) {
size_t currentFrame = m_currentFrame;
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index 35ea786..eb7334e 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -106,7 +106,7 @@ void MediaPlayerPrivate::load(const String& url)
cancelSeek();
m_qtMovie.set(new QTMovieWin(this));
- m_qtMovie->load(url.characters(), url.length());
+ m_qtMovie->load(url.characters(), url.length(), m_player->preservesPitch());
m_qtMovie->setVolume(m_player->volume());
m_qtMovie->setVisible(m_player->visible());
}
@@ -252,8 +252,14 @@ void MediaPlayerPrivate::setRate(float rate)
{
if (!m_qtMovie)
return;
- if (!paused())
- m_qtMovie->setRate(rate);
+ m_qtMovie->setRate(rate);
+}
+
+void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setPreservesPitch(preservesPitch);
}
int MediaPlayerPrivate::dataRate() const
@@ -421,9 +427,33 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
{
if (p->paintingDisabled() || !m_qtMovie || m_hasUnsupportedTracks)
return;
+
+ bool usingTempBitmap = false;
+ OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
HDC hdc = p->getWindowsContext(r);
+ if (!hdc) {
+ // The graphics context doesn't have an associated HDC so create a temporary
+ // bitmap where QTMovieWin can draw the frame and we can copy it.
+ usingTempBitmap = true;
+ bitmap.set(p->createWindowsBitmap(r.size()));
+ hdc = bitmap->hdc();
+
+ // FIXME: is this necessary??
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -r.x();
+ xform.eDy = -r.y();
+ SetWorldTransform(hdc, &xform);
+ }
+
m_qtMovie->paint(hdc, r.x(), r.y());
- p->releaseWindowsContext(hdc, r);
+ if (usingTempBitmap)
+ p->drawWindowsBitmap(bitmap.get(), r.topLeft());
+ else
+ p->releaseWindowsContext(hdc, r);
#if DRAW_FRAME_RATE
if (m_frameCountWhilePlaying > 10) {
@@ -486,7 +516,7 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, c
{
// only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
// extended MIME type
- return mimeTypeCache().contains(type) ? (!codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
+ return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
}
void MediaPlayerPrivate::movieEnded(QTMovieWin* movie)
@@ -535,6 +565,13 @@ void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie)
m_player->repaint();
}
+bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
+{
+ // We tell quicktime to disallow resources that come from different origins
+ // so we all media is single origin.
+ return true;
+}
+
}
#endif
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index 3207867..f584148 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -69,6 +69,7 @@ public:
void setRate(float);
void setVolume(float);
+ void setPreservesPitch(bool);
int dataRate() const;
@@ -89,6 +90,7 @@ public:
void paint(GraphicsContext*, const IntRect&);
+ bool hasSingleSecurityOrigin() const;
private:
MediaPlayerPrivate(MediaPlayer*);
diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp
index 1d10006..aaa61f1 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -76,7 +76,7 @@ static void updateTaskTimer(int maxInterval = 1000)
setSharedTimerFireDelay(static_cast<float>(intervalInMS) / 1000);
}
-class QTMovieWinPrivate : Noncopyable {
+class QTMovieWinPrivate : public Noncopyable {
public:
QTMovieWinPrivate();
~QTMovieWinPrivate();
@@ -115,6 +115,9 @@ public:
long m_loadError;
float m_widthScaleFactor;
float m_heightScaleFactor;
+ CFURLRef m_currentURL;
+ float m_timeToRestore;
+ float m_rateToRestore;
#if !ASSERT_DISABLED
bool m_scaleCached;
#endif
@@ -141,6 +144,9 @@ QTMovieWinPrivate::QTMovieWinPrivate()
, m_loadError(0)
, m_widthScaleFactor(1)
, m_heightScaleFactor(1)
+ , m_currentURL(0)
+ , m_timeToRestore(-1.0f)
+ , m_rateToRestore(-1.0f)
#if !ASSERT_DISABLED
, m_scaleCached(false)
#endif
@@ -156,6 +162,8 @@ QTMovieWinPrivate::~QTMovieWinPrivate()
DisposeMovieController(m_movieController);
if (m_movie)
DisposeMovie(m_movie);
+ if (m_currentURL)
+ CFRelease(m_currentURL);
}
static void taskTimerFired()
@@ -230,16 +238,26 @@ void QTMovieWinPrivate::task()
// we only need to erase the movie gworld when the load state changes to loaded while it
// is visible as the gworld is destroyed/created when visibility changes
+ bool shouldRestorePlaybackState = false;
if (loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded) {
if (m_visible)
clearGWorld();
cacheMovieScale();
+ shouldRestorePlaybackState = true;
}
m_loadState = loadState;
if (!m_movieController && m_loadState >= QTMovieLoadStateLoaded)
createMovieController();
m_client->movieLoadStateChanged(m_movieWin);
+
+ if (shouldRestorePlaybackState && m_timeToRestore != -1.0f) {
+ m_movieWin->setCurrentTime(m_timeToRestore);
+ m_timeToRestore = -1.0f;
+ m_movieWin->setRate(m_rateToRestore);
+ m_rateToRestore = -1.0f;
+ }
+
if (m_movieWin->m_disabled) {
endTask();
return;
@@ -425,6 +443,8 @@ QTMovieWin::~QTMovieWin()
void QTMovieWin::play()
{
+ m_private->m_timeToRestore = -1.0f;
+
if (m_private->m_movieController)
MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)GetMoviePreferredRate(m_private->m_movie));
else
@@ -434,6 +454,8 @@ void QTMovieWin::play()
void QTMovieWin::pause()
{
+ m_private->m_timeToRestore = -1.0f;
+
if (m_private->m_movieController)
MCDoAction(m_private->m_movieController, mcActionPlay, 0);
else
@@ -451,7 +473,9 @@ float QTMovieWin::rate() const
void QTMovieWin::setRate(float rate)
{
if (!m_private->m_movie)
- return;
+ return;
+ m_private->m_timeToRestore = -1.0f;
+
if (m_private->m_movieController)
MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)FloatToFixed(rate));
else
@@ -481,6 +505,9 @@ void QTMovieWin::setCurrentTime(float time) const
{
if (!m_private->m_movie)
return;
+
+ m_private->m_timeToRestore = -1.0f;
+
m_private->m_seeking = true;
TimeScale scale = GetMovieTimeScale(m_private->m_movie);
if (m_private->m_movieController){
@@ -498,6 +525,25 @@ void QTMovieWin::setVolume(float volume)
SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256));
}
+void QTMovieWin::setPreservesPitch(bool preservesPitch)
+{
+ if (!m_private->m_movie || !m_private->m_currentURL)
+ return;
+
+ OSErr error;
+ bool prop = false;
+
+ error = QTGetMovieProperty(m_private->m_movie, kQTPropertyClass_Audio, kQTAudioPropertyID_RateChangesPreservePitch,
+ sizeof(kQTAudioPropertyID_RateChangesPreservePitch), static_cast<QTPropertyValuePtr>(&prop), 0);
+
+ if (error || prop == preservesPitch)
+ return;
+
+ m_private->m_timeToRestore = currentTime();
+ m_private->m_rateToRestore = rate();
+ load(m_private->m_currentURL, preservesPitch);
+}
+
unsigned QTMovieWin::dataSize() const
{
if (!m_private->m_movie)
@@ -561,8 +607,22 @@ void QTMovieWin::paint(HDC hdc, int x, int y)
0, 0, m_private->m_width, m_private->m_height, blendFunction);
}
-void QTMovieWin::load(const UChar* url, int len)
+void QTMovieWin::load(const UChar* url, int len, bool preservesPitch)
{
+ CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
+ CFURLRef cfURL = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0);
+
+ load(cfURL, preservesPitch);
+
+ CFRelease(cfURL);
+ CFRelease(urlStringRef);
+}
+
+void QTMovieWin::load(CFURLRef url, bool preservesPitch)
+{
+ if (!url)
+ return;
+
if (m_private->m_movie) {
m_private->endTask();
if (m_private->m_gWorld)
@@ -572,6 +632,7 @@ void QTMovieWin::load(const UChar* url, int len)
m_private->m_movieController = 0;
DisposeMovie(m_private->m_movie);
m_private->m_movie = 0;
+ m_private->m_loadState = 0;
}
// Define a property array for NewMovieFromProperties. 8 should be enough for our needs.
@@ -579,23 +640,33 @@ void QTMovieWin::load(const UChar* url, int len)
ItemCount moviePropCount = 0;
bool boolTrue = true;
-
- // Create a URL data reference of type CFURL
- CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
// Disable streaming support for now.
- if (CFStringHasPrefix(urlStringRef, CFSTR("rtsp:"))) {
+ CFStringRef scheme = CFURLCopyScheme(url);
+ bool isRTSP = CFStringHasPrefix(scheme, CFSTR("rtsp:"));
+ CFRelease(scheme);
+
+ if (isRTSP) {
m_private->m_loadError = noMovieFound;
goto end;
}
- CFURLRef urlRef = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0);
+ if (m_private->m_currentURL) {
+ if (m_private->m_currentURL != url) {
+ CFRelease(m_private->m_currentURL);
+ m_private->m_currentURL = url;
+ CFRetain(url);
+ }
+ } else {
+ m_private->m_currentURL = url;
+ CFRetain(url);
+ }
// Add the movie data location to the property array
movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation;
movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL;
- movieProps[moviePropCount].propValueSize = sizeof(urlRef);
- movieProps[moviePropCount].propValueAddress = &urlRef;
+ movieProps[moviePropCount].propValueSize = sizeof(m_private->m_currentURL);
+ movieProps[moviePropCount].propValueAddress = &(m_private->m_currentURL);
movieProps[moviePropCount].propStatus = 0;
moviePropCount++;
@@ -639,12 +710,18 @@ void QTMovieWin::load(const UChar* url, int len)
movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
movieProps[moviePropCount].propValueAddress = &boolTrue;
movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_Audio;
+ movieProps[moviePropCount].propID = kQTAudioPropertyID_RateChangesPreservePitch;
+ movieProps[moviePropCount].propValueSize = sizeof(preservesPitch);
+ movieProps[moviePropCount].propValueAddress = &preservesPitch;
+ movieProps[moviePropCount].propStatus = 0;
moviePropCount++;
ASSERT(moviePropCount <= sizeof(movieProps)/sizeof(movieProps[0]));
m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie);
- CFRelease(urlRef);
end:
m_private->startTask();
// get the load fail callback quickly
@@ -660,8 +737,6 @@ end:
QTSetMovieProperty(m_private->m_movie, kQTPropertyClass_Visual, kQTVisualPropertyID_ApertureMode, sizeof(mode), &mode);
m_private->registerDrawingCallback();
}
-
- CFRelease(urlStringRef);
}
void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& totalTrackCount)
diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h
index 70cbef5..f46efd3 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.h
+++ b/WebCore/platform/graphics/win/QTMovieWin.h
@@ -53,6 +53,8 @@ enum {
QTMovieLoadStateComplete = 100000L
};
+typedef const struct __CFURL * CFURLRef;
+
class QTMOVIEWIN_API QTMovieWin {
public:
static bool initializeQuickTime();
@@ -60,7 +62,7 @@ public:
QTMovieWin(QTMovieWinClient*);
~QTMovieWin();
- void load(const UChar* url, int len);
+ void load(const UChar* url, int len, bool preservesPitch);
long loadState() const;
float maxTimeLoaded() const;
@@ -75,6 +77,7 @@ public:
void setCurrentTime(float) const;
void setVolume(float);
+ void setPreservesPitch(bool);
unsigned dataSize() const;
@@ -93,6 +96,8 @@ public:
static void getSupportedType(unsigned index, const UChar*& str, unsigned& len);
private:
+ void load(CFURLRef, bool preservesPitch);
+
QTMovieWinPrivate* m_private;
bool m_disabled;
friend class QTMovieWinPrivate;
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
index aaa089a..6b3a96e 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -126,11 +126,6 @@ void SimpleFontData::platformCharWidthInit()
}
}
-void SimpleFontData::platformDestroy()
-{
- platformCommonDestroy();
-}
-
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
if (m_platformData.useGDI())
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
index 2e51621..0343007 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -47,7 +47,6 @@ void SimpleFontData::platformInit()
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_isSystemFont = false;
- m_syntheticBoldOffset = 0;
m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f;
@@ -97,16 +96,6 @@ void SimpleFontData::platformCharWidthInit()
// charwidths are set in platformInit.
}
-void SimpleFontData::platformDestroy()
-{
- cairo_font_face_destroy(m_platformData.fontFace());
- cairo_scaled_font_destroy(m_platformData.scaledFont());
-
- DeleteObject(m_platformData.hfont());
-
- platformCommonDestroy();
-}
-
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
if (m_platformData.useGDI())
diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
index 9835e9f..5a3244c 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -37,10 +37,13 @@
#include <wtf/MathExtras.h>
#include <unicode/uchar.h>
#include <unicode/unorm.h>
-#include <ApplicationServices/ApplicationServices.h>
#include <mlang.h>
#include <tchar.h>
+
+#if PLATFORM(CG)
+#include <ApplicationServices/ApplicationServices.h>
#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
namespace WebCore {
@@ -89,7 +92,7 @@ void SimpleFontData::initGDIFont()
return;
}
-void SimpleFontData::platformCommonDestroy()
+void SimpleFontData::platformDestroy()
{
// We don't hash this on Win32, so it's effectively owned by us.
delete m_smallCapsFontData;
diff --git a/WebCore/platform/graphics/chromium/ColorChromium.cpp b/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
index 647169c..38dbfbf 100644
--- a/WebCore/platform/graphics/chromium/ColorChromium.cpp
+++ b/WebCore/platform/graphics/win/TransformationMatrixWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,19 +24,21 @@
*/
#include "config.h"
-#include "Color.h"
+#include "TransformationMatrix.h"
namespace WebCore {
-#if !PLATFORM(DARWIN)
-// On OS X, there's code to monitor changes in the focus color system setting.
-// On Windows/Linux there is no equivalent system setting and therefore a static
-// color is all we need.
-Color focusRingColor()
+TransformationMatrix::operator XFORM() const
{
- static Color focusRingColor(229, 151, 0, 255);
- return focusRingColor;
+ XFORM xform;
+ xform.eM11 = a();
+ xform.eM12 = b();
+ xform.eM21 = c();
+ xform.eM22 = d();
+ xform.eDx = e();
+ xform.eDy = f();
+
+ return xform;
}
-#endif
-} // namespace WebCore
+}
diff --git a/WebCore/platform/graphics/wince/FontCacheWince.cpp b/WebCore/platform/graphics/wince/FontCacheWince.cpp
new file mode 100644
index 0000000..f67f1b4
--- /dev/null
+++ b/WebCore/platform/graphics/wince/FontCacheWince.cpp
@@ -0,0 +1,352 @@
+/*
+* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+* Copyright (C) 2007-2009 Torch Mobile, Inc.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "Font.h"
+#include "FontData.h"
+#include "SimpleFontData.h"
+#include "UnicodeRange.h"
+#include "wtf/OwnPtr.h"
+
+#include <windows.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+static IMultiLanguage *multiLanguage = 0;
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static IMLangFontLink2* langFontLink = 0;
+#else
+static IMLangFontLink* langFontLink = 0;
+#endif
+
+IMultiLanguage* getMultiLanguageInterface()
+{
+ if (!multiLanguage)
+ CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&multiLanguage);
+
+ return multiLanguage;
+}
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+IMLangFontLink2* FontCache::getFontLinkInterface()
+#else
+IMLangFontLink* FontCache::getFontLinkInterface()
+#endif
+{
+ if (!langFontLink) {
+ if (IMultiLanguage* mli = getMultiLanguageInterface())
+ mli->QueryInterface(&langFontLink);
+ }
+
+ return langFontLink;
+}
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static bool currentFontContainsCharacter(IMLangFontLink2* langFontLink, HDC hdc, UChar character)
+{
+ UINT unicodeRanges;
+ if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, 0))
+ return false;
+
+ static Vector<UNICODERANGE, 64> glyphsetBuffer;
+ glyphsetBuffer.resize(unicodeRanges);
+
+ if (S_OK != langFontLink->GetFontUnicodeRanges(hdc, &unicodeRanges, glyphsetBuffer.data()))
+ return false;
+
+ // FIXME: Change this to a binary search. (Yong Li: That's easy. But, is it guaranteed that the ranges are sorted?)
+ for (Vector<UNICODERANGE, 64>::const_iterator i = glyphsetBuffer.begin(); i != glyphsetBuffer.end(); ++i) {
+ if (i->wcTo >= character)
+ return i->wcFrom <= character;
+ }
+
+ return false;
+}
+#else
+static bool currentFontContainsCharacter(IMLangFontLink* langFontLink, HDC hdc, HFONT hfont, UChar character, const wchar_t* faceName)
+{
+ DWORD fontCodePages = 0, charCodePages = 0;
+ HRESULT result = langFontLink->GetFontCodePages(hdc, hfont, &fontCodePages);
+ if (result != S_OK)
+ return false;
+ result = langFontLink->GetCharCodePages(character, &charCodePages);
+ if (result != S_OK)
+ return false;
+
+ fontCodePages |= FontPlatformData::getKnownFontCodePages(faceName);
+ if (fontCodePages & charCodePages)
+ return true;
+
+ return false;
+}
+#endif
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
+{
+ HFONT mlangFont;
+ if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &mlangFont)))
+ return mlangFont;
+
+ return 0;
+}
+#else
+static HFONT createMLangFont(IMLangFontLink* langFontLink, HDC hdc, const FontPlatformData& refFont, DWORD codePageMask)
+{
+ HFONT mlangFont;
+ LRESULT result = langFontLink->MapFont(hdc, codePageMask, refFont.hfont(), &mlangFont);
+
+ return result == S_OK ? mlangFont : 0;
+}
+#endif
+
+static const Vector<DWORD, 4>& getCJKCodePageMasks()
+{
+ // The default order in which we look for a font for a CJK character. If the user's default code page is
+ // one of these, we will use it first.
+ static const UINT CJKCodePages[] = {
+ 932, /* Japanese */
+ 936, /* Simplified Chinese */
+ 950, /* Traditional Chinese */
+ 949 /* Korean */
+ };
+
+ static Vector<DWORD, 4> codePageMasks;
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
+#else
+ IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface();
+#endif
+ if (!langFontLink)
+ return codePageMasks;
+
+ UINT defaultCodePage;
+ DWORD defaultCodePageMask = 0;
+ if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
+ langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
+
+ if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
+ codePageMasks.append(defaultCodePageMask);
+ for (unsigned i = 0; i < 4; ++i) {
+ if (defaultCodePage != CJKCodePages[i]) {
+ DWORD codePageMask;
+ langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
+ codePageMasks.append(codePageMask);
+ }
+ }
+ }
+ return codePageMasks;
+}
+
+
+struct TraitsInFamilyProcData {
+ TraitsInFamilyProcData(const AtomicString& familyName)
+ : m_familyName(familyName)
+ {
+ }
+
+ const AtomicString& m_familyName;
+ HashSet<unsigned> m_traitsMasks;
+};
+
+static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
+
+ unsigned traitsMask = 0;
+ traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
+ traitsMask |= FontVariantNormalMask;
+ LONG weight = FontPlatformData::adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+
+void FontCache::platformInit()
+{
+}
+
+void FontCache::comInitialize()
+{
+}
+
+void FontCache::comUninitialize()
+{
+ if (langFontLink) {
+ langFontLink->Release();
+ langFontLink = 0;
+ }
+ if (multiLanguage) {
+ multiLanguage->Release();
+ multiLanguage = 0;
+ }
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ String familyName;
+ WCHAR name[LF_FACESIZE];
+
+ UChar character = characters[0];
+ const FontPlatformData& origFont = font.primaryFont()->fontDataForCharacter(character)->platformData();
+ unsigned unicodeRange = findCharUnicodeRange(character);
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
+#else
+ if (IMLangFontLink* langFontLink = getFontLinkInterface()) {
+#endif
+ HGDIOBJ oldFont = GetCurrentObject(g_screenDC, OBJ_FONT);
+ HFONT hfont = 0;
+ DWORD codePages = 0;
+ UINT codePage = 0;
+ // Try MLang font linking first.
+ langFontLink->GetCharCodePages(character, &codePages);
+ if (codePages && unicodeRange == cRangeSetCJK) {
+ // The CJK character may belong to multiple code pages. We want to
+ // do font linking against a single one of them, preferring the default
+ // code page for the user's locale.
+ const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
+ unsigned numCodePages = CJKCodePageMasks.size();
+ for (unsigned i = 0; i < numCodePages; ++i) {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ hfont = createMLangFont(langFontLink, g_screenDC, CJKCodePageMasks[i]);
+#else
+ hfont = createMLangFont(langFontLink, g_screenDC, origFont, CJKCodePageMasks[i]);
+#endif
+ if (!hfont)
+ continue;
+
+ SelectObject(g_screenDC, hfont);
+ GetTextFace(g_screenDC, LF_FACESIZE, name);
+
+ if (hfont && !(codePages & CJKCodePageMasks[i])) {
+ // We asked about a code page that is not one of the code pages
+ // returned by MLang, so the font might not contain the character.
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (!currentFontContainsCharacter(langFontLink, g_screenDC, character)) {
+#else
+ if (!currentFontContainsCharacter(langFontLink, g_screenDC, hfont, character, name)) {
+#endif
+ SelectObject(g_screenDC, oldFont);
+ langFontLink->ReleaseFont(hfont);
+ hfont = 0;
+ continue;
+ }
+ }
+ break;
+ }
+ } else {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ hfont = createMLangFont(langFontLink, g_screenDC, codePages, character);
+#else
+ hfont = createMLangFont(langFontLink, g_screenDC, origFont, codePages);
+#endif
+ SelectObject(g_screenDC, hfont);
+ GetTextFace(g_screenDC, LF_FACESIZE, name);
+ }
+ SelectObject(g_screenDC, oldFont);
+
+ if (hfont) {
+ familyName = name;
+ langFontLink->ReleaseFont(hfont);
+ } else
+ FontPlatformData::mapKnownFont(codePages, familyName);
+ }
+
+ if (familyName.isEmpty())
+ familyName = FontPlatformData::defaultFontFamily();
+
+ if (!familyName.isEmpty()) {
+ // FIXME: temporary workaround for Thai font problem
+ FontDescription fontDescription(font.fontDescription());
+ if (unicodeRange == cRangeThai && fontDescription.weight() > FontWeightNormal)
+ fontDescription.setWeight(FontWeightNormal);
+
+ FontPlatformData* result = getCachedFontPlatformData(fontDescription, familyName);
+ if (result && result->hash() != origFont.hash()) {
+ if (SimpleFontData* fontData = getCachedFontData(result))
+ return fontData;
+ }
+ }
+
+ return 0;
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDesc)
+{
+ // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick
+ // the default that the user would get without changing any prefs.
+ return getCachedFontPlatformData(fontDesc, FontPlatformData::defaultFontFamily());
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ FontPlatformData* result = new FontPlatformData(fontDescription, family);
+ return result;
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = std::min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ TraitsInFamilyProcData procData(familyName);
+ EnumFontFamiliesEx(g_screenDC, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+}
+
+}
+
diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..7c6853c
--- /dev/null
+++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "Base64.h"
+#include "CachedFont.h"
+#include "FontPlatformData.h"
+#include <wtf/RandomNumber.h>
+
+namespace WebCore {
+
+static CustomFontCache* g_customFontCache = 0;
+
+bool renameFont(SharedBuffer* fontData, const String& fontName);
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ if (g_customFontCache && !m_name.isEmpty())
+ g_customFontCache->unregisterFont(m_name);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode renderingMode)
+{
+ FontDescription fontDesc;
+ fontDesc.setComputedSize(size);
+ fontDesc.setSpecifiedSize(size);
+ fontDesc.setItalic(italic);
+ fontDesc.setWeight(bold ? FontWeightBold : FontWeightNormal);
+ return FontPlatformData(fontDesc, m_name, false);
+}
+
+// Creates a unique and unpredictable font name, in order to avoid collisions and to
+// not allow access from CSS.
+static String createUniqueFontName()
+{
+ Vector<char> fontUuid(sizeof(GUID));
+
+ unsigned int* ptr = reinterpret_cast<unsigned int*>(fontUuid.data());
+ for (int i = 0; i < sizeof(GUID) / sizeof(int) ; ++i)
+ *(ptr + i) = static_cast<unsigned int>(WTF::randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0));
+
+ Vector<char> fontNameVector;
+ base64Encode(fontUuid, fontNameVector);
+ ASSERT(fontNameVector.size() < LF_FACESIZE);
+ String fontName(fontNameVector.data(), fontNameVector.size());
+ return fontName.replace('/', '_');
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(CachedFont* cachedFont)
+{
+ if (g_customFontCache && cachedFont->CachedResource::data()) {
+ String fontName = createUniqueFontName();
+ if (renameFont(cachedFont->CachedResource::data(), fontName) && g_customFontCache->registerFont(fontName, cachedFont))
+ return new FontCustomPlatformData(fontName);
+ }
+ return 0;
+}
+
+}
diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/WebCore/platform/graphics/wince/FontCustomPlatformData.h
new file mode 100644
index 0000000..b1f64a0
--- /dev/null
+++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+ class FontPlatformData;
+ class CachedFont;
+
+ class CustomFontCache {
+ public:
+ virtual bool registerFont(const String& fontName, CachedFont*) = 0;
+ virtual void unregisterFont(const String& fontName) = 0;
+ };
+
+ struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(const String& name)
+ : m_name(name)
+ {
+ }
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
+ String m_name;
+ };
+
+ FontCustomPlatformData* createFontCustomPlatformData(CachedFont*);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/wince/FontPlatformData.cpp b/WebCore/platform/graphics/wince/FontPlatformData.cpp
new file mode 100644
index 0000000..f0db2ff
--- /dev/null
+++ b/WebCore/platform/graphics/wince/FontPlatformData.cpp
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FontData.h"
+#include "PlatformString.h"
+#include "SimpleFontData.h"
+#include "UnicodeRange.h"
+#include "wtf/OwnPtr.h"
+
+#include <windows.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+static wchar_t songTiStr[] = { 0x5b8b, 0x4f53, 0 };
+static wchar_t heiTiStr[] = { 0x9ed1, 0x4f53, 0 };
+
+class FontFamilyCodePageInfo {
+public:
+ FontFamilyCodePageInfo()
+ : m_codePage(0), m_codePages(0)
+ {
+ }
+ FontFamilyCodePageInfo(const wchar_t* family, UINT codePage)
+ : m_family(family), m_codePage(codePage), m_codePages(0)
+ {
+ }
+ DWORD codePages() const
+ {
+ if (!m_codePages) {
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface())
+ langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
+#else
+ if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface())
+ langFontLink->CodePageToCodePages(m_codePage, &m_codePages);
+#endif
+ }
+ return m_codePages;
+ }
+
+ String m_family;
+ UINT m_codePage;
+private:
+ mutable DWORD m_codePages;
+};
+
+class FontFamilyChecker {
+public:
+ FontFamilyChecker(const wchar_t* family)
+ : m_exists(false)
+ {
+ EnumFontFamilies(g_screenDC, family, enumFontFamProc, (LPARAM)this);
+ }
+ bool isSupported() const { return m_exists; }
+private:
+ bool m_exists;
+ static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
+};
+
+class ValidFontFamilyFinder {
+public:
+ ValidFontFamilyFinder()
+ {
+ EnumFontFamilies(g_screenDC, 0, enumFontFamProc, (LPARAM)this);
+ }
+ const String& family() const { return m_family; }
+private:
+ String m_family;
+ static int CALLBACK enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam);
+};
+
+class FixedSizeFontData: public RefCounted<FixedSizeFontData> {
+public:
+ LOGFONT m_font;
+ OwnPtr<HFONT> m_hfont;
+ TEXTMETRIC m_metrics;
+ DWORD m_codePages;
+ unsigned m_weight;
+ bool m_italic;
+
+ static PassRefPtr<FixedSizeFontData> create(const AtomicString& family, unsigned weight, bool italic);
+private:
+ FixedSizeFontData()
+ : m_codePages(0)
+ , m_weight(0)
+ , m_italic(false)
+ {
+ memset(&m_font, 0, sizeof(m_font));
+ memset(&m_metrics, 0, sizeof(m_metrics));
+ }
+};
+
+struct FixedSizeFontDataKey {
+ FixedSizeFontDataKey(const AtomicString& family = AtomicString(), unsigned weight = 0, bool italic = false)
+ : m_family(family)
+ , m_weight(weight)
+ , m_italic(italic)
+ {
+ }
+
+ FixedSizeFontDataKey(WTF::HashTableDeletedValueType) : m_weight(-2) { }
+ bool isHashTableDeletedValue() const { return m_weight == -2; }
+
+ bool operator==(const FixedSizeFontDataKey& other) const
+ {
+ return equalIgnoringCase(m_family, other.m_family)
+ && m_weight == other.m_weight
+ && m_italic == other.m_italic;
+ }
+
+ AtomicString m_family;
+ unsigned m_weight;
+ bool m_italic;
+};
+
+struct FixedSizeFontDataKeyHash {
+ static unsigned hash(const FixedSizeFontDataKey& font)
+ {
+ unsigned hashCodes[] = {
+ CaseFoldingHash::hash(font.m_family),
+ font.m_weight,
+ // static_cast<unsigned>(font.m_italic);
+ };
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+ }
+
+ static bool equal(const FixedSizeFontDataKey& a, const FixedSizeFontDataKey& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FixedSizeFontDataKeyTraits : WTF::GenericHashTraits<FixedSizeFontDataKey> {
+ static const bool emptyValueIsZero = true;
+ static const FixedSizeFontDataKey& emptyValue()
+ {
+ DEFINE_STATIC_LOCAL(FixedSizeFontDataKey, key, (nullAtom));
+ return key;
+ }
+ static void constructDeletedValue(FixedSizeFontDataKey& slot)
+ {
+ new (&slot) FixedSizeFontDataKey(WTF::HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FixedSizeFontDataKey& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+int CALLBACK FontFamilyChecker::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
+{
+ ((FontFamilyChecker*)lParam)->m_exists = true;
+ return 0;
+}
+
+int CALLBACK ValidFontFamilyFinder::enumFontFamProc(const LOGFONT FAR* lpelf, const TEXTMETRIC FAR* lpntm, DWORD FontType, LPARAM lParam)
+{
+ if (lpelf->lfCharSet != SYMBOL_CHARSET) {
+ ((ValidFontFamilyFinder*)lParam)->m_family = String(lpelf->lfFaceName);
+ return 0;
+ }
+ return 1;
+}
+
+typedef Vector<FontFamilyCodePageInfo> KnownFonts;
+static KnownFonts& knownFonts()
+{
+ static KnownFonts fonts;
+ static bool firstTime = true;
+ if (firstTime) {
+ firstTime = false;
+ if (FontPlatformData::isSongTiSupported())
+ fonts.append(FontFamilyCodePageInfo(songTiStr, 936));
+ }
+ return fonts;
+}
+
+static String getDefaultFontFamily()
+{
+ if (FontFamilyChecker(L"Tahoma").isSupported())
+ return String(L"Tahoma");
+
+ bool good = false;
+ String family;
+ HKEY key;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\GDI\\SysFnt", 0, 0, &key) == ERROR_SUCCESS) {
+ DWORD maxlen, type;
+ if (RegQueryValueEx(key, L"Nm", 0, &type, 0, &maxlen) == ERROR_SUCCESS && type == REG_SZ) {
+ ++maxlen;
+ if (wchar_t* buffer = new wchar_t[maxlen]) {
+ if (RegQueryValueEx(key, L"Nm", 0, &type, (LPBYTE)buffer, &maxlen) == ERROR_SUCCESS) {
+ family = String(buffer, maxlen);
+ good = true;
+ }
+ delete[] buffer;
+ }
+ }
+ RegCloseKey(key);
+ }
+ if (good)
+ return family;
+
+ return ValidFontFamilyFinder().family();
+}
+
+typedef HashMap<FixedSizeFontDataKey, RefPtr<FixedSizeFontData>, FixedSizeFontDataKeyHash, FixedSizeFontDataKeyTraits> FixedSizeFontCache;
+FixedSizeFontCache g_fixedSizeFontCache;
+
+PassRefPtr<FixedSizeFontData> FixedSizeFontData::create(const AtomicString& family, unsigned weight, bool italic)
+{
+ FixedSizeFontData* fontData = new FixedSizeFontData();
+
+ fontData->m_weight = weight;
+ fontData->m_italic = italic;
+
+ LOGFONT& winFont = fontData->m_font;
+ // The size here looks unusual. The negative number is intentional.
+ winFont.lfHeight = -72;
+ winFont.lfWidth = 0;
+ winFont.lfEscapement = 0;
+ winFont.lfOrientation = 0;
+ winFont.lfUnderline = false;
+ winFont.lfStrikeOut = false;
+ winFont.lfCharSet = DEFAULT_CHARSET;
+ winFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ winFont.lfQuality = CLEARTYPE_QUALITY; //DEFAULT_QUALITY;
+ winFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ winFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ winFont.lfItalic = italic;
+ winFont.lfWeight = FontPlatformData::adjustedGDIFontWeight(weight, family);
+
+ int len = std::min(family.length(), (unsigned int)LF_FACESIZE - 1);
+ wmemcpy(winFont.lfFaceName, family.characters(), len);
+ winFont.lfFaceName[len] = L'\0';
+
+ fontData->m_hfont.set(CreateFontIndirect(&winFont));
+
+ HGDIOBJ oldFont = SelectObject(g_screenDC, fontData->m_hfont.get());
+
+ GetTextMetrics(g_screenDC, &fontData->m_metrics);
+
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) {
+#else
+ if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) {
+#endif
+ langFontLink->GetFontCodePages(g_screenDC, fontData->m_hfont.get(), &fontData->m_codePages);
+ fontData->m_codePages |= FontPlatformData::getKnownFontCodePages(winFont.lfFaceName);
+ }
+
+ SelectObject(g_screenDC, oldFont);
+
+ return adoptRef(fontData);
+}
+
+static PassRefPtr<FixedSizeFontData> createFixedSizeFontData(const AtomicString& family, unsigned weight, bool italic)
+{
+ FixedSizeFontDataKey key(family, weight, italic);
+ pair<FixedSizeFontCache::iterator, bool> result = g_fixedSizeFontCache.add(key, RefPtr<FixedSizeFontData>());
+ if (result.second)
+ result.first->second = FixedSizeFontData::create(family, weight, italic);
+
+ return result.first->second;
+}
+
+static LONG toGDIFontWeight(FontWeight fontWeight)
+{
+ static LONG gdiFontWeights[] = {
+ FW_THIN, // FontWeight100
+ FW_EXTRALIGHT, // FontWeight200
+ FW_LIGHT, // FontWeight300
+ FW_NORMAL, // FontWeight400
+ FW_MEDIUM, // FontWeight500
+ FW_SEMIBOLD, // FontWeight600
+ FW_BOLD, // FontWeight700
+ FW_EXTRABOLD, // FontWeight800
+ FW_HEAVY // FontWeight900
+ };
+ return gdiFontWeights[fontWeight];
+}
+
+class FontPlatformPrivateData {
+public:
+ int m_reference;
+ RefPtr<FixedSizeFontData> m_rootFontData;
+ AtomicString m_family;
+ FontDescription m_fontDescription;
+ OwnPtr<HFONT> m_hfontScaled;
+ int m_size;
+ long m_fontScaledWidth;
+ long m_fontScaledHeight;
+ bool m_disabled;
+ FontPlatformPrivateData(int size, unsigned weight)
+ : m_reference(1)
+ , m_family(FontPlatformData::defaultFontFamily())
+ , m_size(size)
+ , m_fontScaledWidth(0)
+ , m_fontScaledHeight(0)
+ , m_disabled(false)
+ {
+ m_rootFontData = createFixedSizeFontData(m_family, weight, false);
+ }
+ FontPlatformPrivateData(const FontDescription& fontDescription, const AtomicString& family)
+ : m_reference(1)
+ , m_size(fontDescription.computedPixelSize())
+ , m_fontDescription(fontDescription)
+ , m_family(family)
+ , m_fontScaledWidth(0)
+ , m_fontScaledHeight(0)
+ , m_disabled(!fontDescription.specifiedSize())
+ {
+ m_rootFontData = FixedSizeFontData::create(family, toGDIFontWeight(fontDescription.weight()), fontDescription.italic());
+ }
+};
+
+FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& desiredFamily, bool useDefaultFontIfNotPresent)
+{
+ String family(desiredFamily);
+ if (!equalIgnoringCase(family, defaultFontFamily()) && !FontFamilyChecker(family.charactersWithNullTermination()).isSupported()) {
+ if (equalIgnoringCase(family, String(heiTiStr)) && isSongTiSupported())
+ family = String(songTiStr);
+ else if (useDefaultFontIfNotPresent)
+ family = defaultFontFamily();
+ }
+
+ m_private = new FontPlatformPrivateData(fontDescription, family);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+{
+ if (!size)
+ m_private = 0;
+ else
+ m_private = new FontPlatformPrivateData((int)(size + 0.5), bold ? FW_BOLD : FW_NORMAL);
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ if (isValid() && !--m_private->m_reference) {
+ if (m_private->m_rootFontData->refCount() == 2) {
+ FixedSizeFontDataKey key(m_private->m_family, m_private->m_rootFontData->m_weight, m_private->m_rootFontData->m_italic);
+ g_fixedSizeFontCache.remove(key);
+ }
+ delete m_private;
+ }
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& o)
+{
+ if (isValid() && !--m_private->m_reference)
+ delete m_private;
+
+ if (m_private = o.m_private)
+ ++m_private->m_reference;
+
+ return *this;
+}
+
+HFONT FontPlatformData::hfont() const
+{
+ if (!isValid())
+ return 0;
+
+ if (m_private->m_disabled)
+ return 0;
+
+ if (!m_private->m_rootFontData->m_hfont)
+ m_private->m_rootFontData->m_hfont.set(CreateFontIndirect(&m_private->m_rootFontData->m_font));
+
+ return m_private->m_rootFontData->m_hfont.get();
+}
+
+HFONT FontPlatformData::getScaledFontHandle(int height, int width) const
+{
+ if (!isValid() || m_private->m_disabled)
+ return 0;
+
+ if (!m_private->m_hfontScaled || m_private->m_fontScaledHeight != height || m_private->m_fontScaledWidth != width) {
+ m_private->m_fontScaledHeight = height;
+ m_private->m_fontScaledWidth = width;
+ LOGFONT font = m_private->m_rootFontData->m_font;
+ font.lfHeight = -height;
+ font.lfWidth = width;
+ m_private->m_hfontScaled.set(CreateFontIndirect(&font));
+ }
+
+ return m_private->m_hfontScaled.get();
+}
+
+bool FontPlatformData::discardFontHandle()
+{
+ if (!isValid())
+ return false;
+
+ if (m_private->m_rootFontData->m_hfont) {
+ m_private->m_rootFontData->m_hfont.set(0);
+ return true;
+ }
+
+ if (m_private->m_hfontScaled) {
+ m_private->m_hfontScaled.set(0);
+ return true;
+ }
+ return false;
+}
+
+const TEXTMETRIC& FontPlatformData::metrics() const
+{
+ return m_private->m_rootFontData->m_metrics;
+}
+
+bool FontPlatformData::isSystemFont() const
+{
+ return false;
+}
+
+int FontPlatformData::size() const
+{
+ return m_private->m_size;
+}
+
+const FontDescription& FontPlatformData::fontDescription() const
+{
+ return m_private->m_fontDescription;
+}
+
+const AtomicString& FontPlatformData::family() const
+{
+ return m_private->m_family;
+}
+
+const LOGFONT& FontPlatformData::logFont() const
+{
+ return m_private->m_rootFontData->m_font;
+}
+
+int FontPlatformData::averageCharWidth() const
+{
+ return (m_private->m_rootFontData->m_metrics.tmAveCharWidth * size() + 36) / 72;
+}
+
+bool FontPlatformData::isDisabled() const
+{
+ return !isValid() || m_private->m_disabled;
+}
+
+DWORD FontPlatformData::codePages() const
+{
+ return m_private->m_rootFontData->m_codePages;
+}
+
+bool FontPlatformData::isSongTiSupported()
+{
+ static bool exists = FontFamilyChecker(songTiStr).isSupported();
+ return exists;
+}
+
+bool FontPlatformData::mapKnownFont(DWORD codePages, String& family)
+{
+ KnownFonts& fonts = knownFonts();
+ for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
+ if (i->codePages() & codePages) {
+ family = i->m_family;
+ return true;
+ }
+ }
+ return false;
+}
+
+DWORD FontPlatformData::getKnownFontCodePages(const wchar_t* family)
+{
+ KnownFonts& fonts = knownFonts();
+ for (KnownFonts::iterator i = fonts.begin(); i != fonts.end(); ++i) {
+ if (equalIgnoringCase(i->m_family, String(family)))
+ return i->codePages();
+ }
+ return 0;
+}
+
+const String& FontPlatformData::defaultFontFamily()
+{
+ static String family(getDefaultFontFamily());
+ return family;
+}
+
+LONG FontPlatformData::adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
+{
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr)) {
+ if (gdiFontWeight == FW_NORMAL)
+ return FW_MEDIUM;
+ if (gdiFontWeight == FW_BOLD)
+ return FW_SEMIBOLD;
+ }
+ return gdiFontWeight;
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/WebCore/platform/graphics/wince/FontPlatformData.h b/WebCore/platform/graphics/wince/FontPlatformData.h
new file mode 100644
index 0000000..77803d3
--- /dev/null
+++ b/WebCore/platform/graphics/wince/FontPlatformData.h
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 2007-2008 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformDataWince_H
+#define FontPlatformDataWince_H
+
+#include "FontDescription.h"
+#include "StringImpl.h"
+#include <wtf/Noncopyable.h>
+
+typedef struct tagTEXTMETRICW TEXTMETRIC;
+typedef struct tagLOGFONTW LOGFONT;
+
+namespace WebCore {
+
+ class FontPlatformPrivateData;
+ class String;
+
+ class FontPlatformData {
+
+ public:
+
+ FontPlatformData(): m_private(0) {}
+ FontPlatformData(float size, bool bold, bool oblique);
+
+ // Used for deleted values in the font cache's hash tables.
+ FontPlatformData(WTF::HashTableDeletedValueType) : m_private((FontPlatformPrivateData*)1) {}
+ bool isHashTableDeletedValue() const { return (unsigned)m_private == 1; }
+
+ FontPlatformData(const FontDescription& fontDescription, const AtomicString& family, bool useDefaultFontIfNotPresent = true);
+
+ ~FontPlatformData();
+
+ FontPlatformData(const FontPlatformData& o) : m_private(0) { operator=(o); }
+ FontPlatformData& operator=(const FontPlatformData& o);
+
+ int isValid() const { return reinterpret_cast<unsigned>(m_private) & ~1; }
+ HFONT hfont() const;
+ const TEXTMETRIC& metrics() const;
+ bool isSystemFont() const;
+ int size() const;
+ unsigned hash() const { return (unsigned)m_private; }
+ const FontDescription& fontDescription() const;
+ const AtomicString& family() const;
+ bool operator==(const FontPlatformData& other) const { return m_private == other.m_private; }
+ HFONT getScaledFontHandle(int height, int width) const;
+ const LOGFONT& logFont() const;
+ int averageCharWidth() const;
+ bool isDisabled() const;
+ bool discardFontHandle();
+ DWORD codePages() const;
+
+ static bool isSongTiSupported();
+ static bool mapKnownFont(DWORD codePages, String& family);
+ static DWORD getKnownFontCodePages(const wchar_t* family);
+ static const String& defaultFontFamily();
+ static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family);
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+
+ private:
+ FontPlatformPrivateData* m_private;
+ };
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/wince/FontWince.cpp b/WebCore/platform/graphics/wince/FontWince.cpp
new file mode 100644
index 0000000..d00336b
--- /dev/null
+++ b/WebCore/platform/graphics/wince/FontWince.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FloatRect.h"
+#include "FontCache.h"
+#include "FontData.h"
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "TransformationMatrix.h"
+#include "WidthIterator.h"
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/unicode/Unicode.h>
+
+#include <windows.h>
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+HDC g_screenDC = GetDC(0);
+
+class ScreenDcReleaser {
+public:
+ ~ScreenDcReleaser()
+ {
+ ReleaseDC(0, g_screenDC);
+ }
+};
+
+ScreenDcReleaser releaseScreenDc;
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ graphicsContext->drawText(fontData, glyphBuffer, from, numGlyphs, point);
+}
+
+class TextRunComponent {
+public:
+ TextRunComponent() : m_textRun(0, 0) {}
+ TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int offset);
+ TextRunComponent(int spaces, const Font &font, int offset);
+ ~TextRunComponent() { m_textRun; }
+
+ bool isSpace() const { return m_spaces; }
+ int textLength() const { return m_spaces ? m_spaces : m_textRun.length(); }
+
+ TextRun m_textRun;
+ float m_width;
+ int m_offset;
+ int m_spaces;
+};
+
+TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o)
+ : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0
+ , parentTextRun.rtl()
+ , parentTextRun.directionalOverride()
+ , parentTextRun.applyRunRounding()
+ , parentTextRun.applyWordRounding())
+ , m_offset(o)
+ , m_spaces(0)
+{
+ WidthIterator it(&font, m_textRun);
+ it.advance(m_textRun.length(), 0);
+ m_width = it.m_runWidthSoFar;
+}
+
+TextRunComponent::TextRunComponent(int s, const Font &font, int o)
+ : m_textRun(0, 0)
+ , m_offset(o)
+ , m_spaces(s)
+{
+ m_width = s * font.primaryFont()->widthForGlyph(' ');
+}
+
+typedef Vector<TextRunComponent, 128> TextRunComponents;
+
+static int generateComponents(TextRunComponents* components, const Font &font, const TextRun &run)
+{
+ int letterSpacing = font.letterSpacing();
+ int wordSpacing = font.wordSpacing();
+ int padding = run.padding();
+ int numSpaces = 0;
+ if (padding) {
+ for (int i = 0; i < run.length(); i++)
+ if (Font::treatAsSpace(run[i]))
+ ++numSpaces;
+ }
+
+ int offset = 0;
+ if (letterSpacing) {
+ // need to draw every letter on it's own
+ int start = 0;
+ if (Font::treatAsSpace(run[0])) {
+ int add = 0;
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += add + letterSpacing + components->last().m_width;
+ start = 1;
+ }
+ for (int i = 1; i < run.length(); ++i) {
+ uint ch = run[i];
+ if (isHighSurrogate(ch) && isLowSurrogate(run[i-1]))
+ ch = surrogateToUcs4(ch, run[i-1]);
+ if (isLowSurrogate(ch) || category(ch) == Mark_NonSpacing)
+ continue;
+ if (Font::treatAsSpace(run[i])) {
+ int add = 0;
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run, font, offset));
+ offset += components->last().m_width + letterSpacing;
+ }
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += wordSpacing + add + components->last().m_width + letterSpacing;
+ start = i + 1;
+ continue;
+ }
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run,
+ font, offset));
+ offset += components->last().m_width + letterSpacing;
+ }
+ start = i;
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ offset += letterSpacing;
+ } else {
+ int start = 0;
+ for (int i = 0; i < run.length(); ++i) {
+ if (Font::treatAsSpace(run[i])) {
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ int add = 0;
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, font, offset));
+ offset += add + components->last().m_width;
+ if (i)
+ offset += wordSpacing;
+ start = i + 1;
+ }
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run,
+ font, offset));
+ offset += components->last().m_width;
+ }
+ }
+ return offset;
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
+ int from, int to) const
+{
+ if (to < 0)
+ to = run.length();
+ if (from < 0)
+ from = 0;
+
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+
+ int curPos = 0;
+ for (int i = 0; i < (int)components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int len = comp.textLength();
+ int curEnd = curPos + len;
+ if (curPos < to && from < curEnd && !comp.isSpace()) {
+ FloatPoint pt = point;
+ if (run.rtl())
+ pt.setX(point.x() + w - comp.m_offset - comp.m_width);
+ else
+ pt.setX(point.x() + comp.m_offset);
+ drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos);
+ }
+ curPos += len;
+ if (from < curPos)
+ from = curPos;
+ }
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const
+{
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+ return w;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const
+{
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+
+ if (position >= w)
+ return run.length();
+
+ int offset = 0;
+ if (run.rtl()) {
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int xe = w - comp.m_offset;
+ int xs = xe - comp.m_width;
+ if (position >= xs)
+ return offset + (comp.isSpace()
+ ? static_cast<int>((position - xe) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
+ : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
+
+ offset += comp.textLength();
+ }
+ } else {
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ int xs = comp.m_offset;
+ int xe = xs + comp.m_width;
+ if (position <= xe) {
+ if (position - xs >= xe)
+ return offset + comp.textLength();
+ return offset + (comp.isSpace()
+ ? static_cast<int>((position - xs) * comp.m_spaces / std::max(1.f, comp.m_width) + 0.5)
+ : offsetForPositionForSimpleText(comp.m_textRun, position - xs, includePartialGlyphs));
+ }
+ offset += comp.textLength();
+ }
+ }
+ return run.length();
+}
+
+
+static float cursorToX(const Font* font, const TextRunComponents& components, int width, bool rtl, int cursor)
+{
+ int start = 0;
+ for (size_t i = 0; i < components.size(); ++i) {
+ const TextRunComponent& comp = components.at(i);
+ if (start + comp.textLength() <= cursor) {
+ start += comp.textLength();
+ continue;
+ }
+ int xs = comp.m_offset;
+ if (rtl)
+ xs = width - xs - comp.m_width;
+
+ int pos = cursor - start;
+ if (comp.isSpace()) {
+ if (rtl)
+ pos = comp.textLength() - pos;
+ return xs + pos * comp.m_width / comp.m_spaces;
+ }
+ WidthIterator it(font, comp.m_textRun);
+ it.advance(pos);
+ return xs + it.m_runWidthSoFar;
+ }
+ return width;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt,
+ int h, int from, int to) const
+{
+ TextRunComponents components;
+ int w = generateComponents(&components, *this, run);
+
+ if (!from && to == run.length())
+ return FloatRect(pt.x(), pt.y(), w, h);
+
+ float x1 = cursorToX(this, components, w, run.rtl(), from);
+ float x2 = cursorToX(this, components, w, run.rtl(), to);
+ if (x2 < x1)
+ std::swap(x1, x2);
+
+ return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
+}
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+}
diff --git a/WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp b/WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp
new file mode 100644
index 0000000..27c4e15
--- /dev/null
+++ b/WebCore/platform/graphics/wince/GlyphPageTreeNodeWince.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FontData.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+DWORD getKnownFontCodePages(const wchar_t* family);
+
+typedef unsigned (*funcGetCharCodePages)(unsigned short c, unsigned& lastPos);
+funcGetCharCodePages getCharCodePages = 0;
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ if (length != bufferLength)
+ return false;
+
+ if (fontData->platformData().hfont()) {
+ DWORD fontCodePages = fontData->platformData().codePages();
+ if (fontCodePages) {
+ if (getCharCodePages) {
+ unsigned lastPos = 0;
+ for (unsigned i = 0; i < bufferLength; ++i) {
+ DWORD actualCodePages = getCharCodePages(buffer[i], lastPos);
+ if (!actualCodePages || (actualCodePages & fontCodePages))
+ setGlyphDataForIndex(offset + i, buffer[i], fontData);
+ else
+ setGlyphDataForIndex(offset + i, buffer[i], 0);
+ }
+ return true;
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ } else if (IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface()) {
+#else
+ } else if (IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface()) {
+#endif
+ for (unsigned i = 0; i < bufferLength; ++i) {
+ DWORD actualCodePages;
+ langFontLink->GetCharCodePages(buffer[i], &actualCodePages);
+ if (!actualCodePages || (actualCodePages & fontCodePages))
+ setGlyphDataForIndex(offset + i, buffer[i], fontData);
+ else
+ setGlyphDataForIndex(offset + i, buffer[i], 0);
+ }
+ return true;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < length; ++i)
+ setGlyphDataForIndex(offset + i, buffer[i], fontData);
+
+ return true;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
new file mode 100644
index 0000000..c114c0e
--- /dev/null
+++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
@@ -0,0 +1,1930 @@
+/*
+ * Copyright (C) 2007-2009 Torch Mobile Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "CharacterNames.h"
+#include "GlyphBuffer.h"
+#include "Gradient.h"
+#include "GraphicsContextPrivate.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "PlatformPathWince.h"
+#include "SharedBitmap.h"
+#include "SimpleFontData.h"
+#include "TransformationMatrix.h"
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops);
+typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops);
+FuncGradientFillRectLinear g_linearGradientFiller = 0;
+FuncGradientFillRectRadial g_radialGradientFiller = 0;
+
+static inline bool isZero(double d)
+{
+ return d > 0 ? d <= 1.E-10 : d >= -1.E-10;
+}
+
+// stableRound rounds -0.5 to 0, where lround rounds -0.5 to -1.
+static inline int stableRound(double d)
+{
+ if (d > 0)
+ return static_cast<int>(d + 0.5);
+
+ int i = static_cast<int>(d);
+ return i - d > 0.5 ? i - 1 : i;
+}
+
+// Unlike enclosingIntRect(), this function does strict rounding.
+static inline IntRect roundRect(const FloatRect& r)
+{
+ return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.right()) - stableRound(r.x()), stableRound(r.bottom()) - stableRound(r.y()));
+}
+
+// Rotation transformation
+class RotationTransform {
+public:
+ RotationTransform()
+ : m_cosA(1.)
+ , m_sinA(0.)
+ , m_preShiftX(0)
+ , m_preShiftY(0)
+ , m_postShiftX(0)
+ , m_postShiftY(0)
+ {
+ }
+ RotationTransform operator-() const
+ {
+ RotationTransform rtn;
+ rtn.m_cosA = m_cosA;
+ rtn.m_sinA = -m_sinA;
+ rtn.m_preShiftX = m_postShiftX;
+ rtn.m_preShiftY = m_postShiftY;
+ rtn.m_postShiftX = m_preShiftX;
+ rtn.m_postShiftY = m_preShiftY;
+ return rtn;
+ }
+ void map(double x1, double y1, double* x2, double* y2) const
+ {
+ x1 += m_preShiftX;
+ y1 += m_preShiftY;
+ *x2 = x1 * m_cosA + y1 * m_sinA + m_postShiftX;
+ *y2 = y1 * m_cosA - x1 * m_sinA + m_postShiftY;
+ }
+ void map(int x1, int y1, int* x2, int* y2) const
+ {
+ x1 += m_preShiftX;
+ y1 += m_preShiftY;
+ *x2 = stableRound(x1 * m_cosA + y1 * m_sinA) + m_postShiftX;
+ *y2 = stableRound(y1 * m_cosA - x1 * m_sinA) + m_postShiftY;
+ }
+
+ double m_cosA;
+ double m_sinA;
+ int m_preShiftX;
+ int m_preShiftY;
+ int m_postShiftX;
+ int m_postShiftY;
+};
+
+template<class T> static inline IntPoint mapPoint(const IntPoint& p, const T& t)
+{
+ int x, y;
+ t.map(p.x(), p.y(), &x, &y);
+ return IntPoint(x, y);
+}
+
+template<class T> static inline FloatPoint mapPoint(const FloatPoint& p, const T& t)
+{
+ double x, y;
+ t.map(p.x(), p.y(), &x, &y);
+ return FloatPoint(static_cast<float>(x), static_cast<float>(y));
+}
+
+template<class Transform, class Rect, class Value> static inline Rect mapRect(const Rect& rect, const Transform& transform)
+{
+ Value x[4], y[4];
+ Value l, t, r, b;
+ r = rect.right() - 1;
+ b = rect.bottom() - 1;
+ transform.map(rect.x(), rect.y(), x, y);
+ transform.map(rect.x(), b, x + 1, y + 1);
+ transform.map(r, b, x + 2, y + 2);
+ transform.map(r, rect.y(), x + 3, y + 3);
+ l = r = x[3];
+ t = b = y[3];
+ for (int i = 0; i < 3; ++i) {
+ if (x[i] < l)
+ l = x[i];
+ else if (x[i] > r)
+ r = x[i];
+
+ if (y[i] < t)
+ t = y[i];
+ else if (y[i] > b)
+ b = y[i];
+ }
+
+ return IntRect(l, t, r - l + 1, b - t + 1);
+}
+
+template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform)
+{
+ return mapRect<T, IntRect, int>(rect, transform);
+}
+
+template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform)
+{
+ return mapRect<T, FloatRect, double>(rect, transform);
+}
+
+class GraphicsContextPlatformPrivateData {
+public:
+ GraphicsContextPlatformPrivateData()
+ : m_transform()
+ , m_opacity(1.0)
+ {
+ }
+
+ TransformationMatrix m_transform;
+ float m_opacity;
+ Vector<Path> m_paths;
+};
+
+enum AlphaPaintType {
+ AlphaPaintNone,
+ AlphaPaintImage,
+ AlphaPaintOther,
+};
+
+class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData {
+public:
+ GraphicsContextPlatformPrivate(HDC dc)
+ : m_dc(dc)
+ {
+ }
+ ~GraphicsContextPlatformPrivate()
+ {
+ while (!m_backupData.isEmpty())
+ restore();
+ }
+
+ IntPoint origin() const
+ {
+ return IntPoint(stableRound(-m_transform.e()), stableRound(-m_transform.f()));
+ }
+
+ void translate(float x, float y)
+ {
+ m_transform.translate(x, y);
+ }
+
+ void scale(const FloatSize& size)
+ {
+ m_transform.scaleNonUniform(size.width(), size.height());
+ }
+
+ void rotate(float radians)
+ {
+ m_transform.rotate(rad2deg(radians));
+ }
+
+ void concatCTM(const TransformationMatrix& transform)
+ {
+ m_transform = transform * m_transform;
+ }
+
+ IntRect mapRect(const IntRect& rect) const
+ {
+ return m_transform.mapRect(rect);
+ }
+
+ FloatRect mapRect(const FloatRect& rect) const
+ {
+ return m_transform.mapRect(rect);
+ }
+
+ IntPoint mapPoint(const IntPoint& point) const
+ {
+ return m_transform.mapPoint(point);
+ }
+
+ FloatPoint mapPoint(const FloatPoint& point) const
+ {
+ return m_transform.mapPoint(point);
+ }
+
+ FloatSize mapSize(const FloatSize& size) const
+ {
+ double w, h;
+ m_transform.map(size.width(), size.height(), w, h);
+ return FloatSize(static_cast<float>(w), static_cast<float>(h));
+ }
+
+ void save()
+ {
+ if (m_dc)
+ SaveDC(m_dc);
+
+ m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this));
+ }
+
+ void restore()
+ {
+ if (m_backupData.isEmpty())
+ return;
+
+ if (m_dc)
+ RestoreDC(m_dc, -1);
+
+ GraphicsContextPlatformPrivateData::operator=(m_backupData.last());
+ m_backupData.removeLast();
+ }
+
+ bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); }
+
+ PassRefPtr<SharedBitmap> getTransparentLayerBitmap(IntRect& origRect, AlphaPaintType alphaPaint, RECT& bmpRect, bool checkClipBox, bool force) const
+ {
+ if (m_opacity <= 0)
+ return 0;
+
+ if (force || m_opacity < 1.) {
+ if (checkClipBox) {
+ RECT clipBox;
+ int clipType = GetClipBox(m_dc, &clipBox);
+ if (clipType == SIMPLEREGION || clipType == COMPLEXREGION)
+ origRect.intersect(clipBox);
+ if (origRect.isEmpty())
+ return 0;
+ }
+
+ RefPtr<SharedBitmap> bmp = SharedBitmap::createInstance(alphaPaint == AlphaPaintNone, origRect.width(), origRect.height(), false);
+ SetRect(&bmpRect, 0, 0, origRect.width(), origRect.height());
+ if (bmp) {
+ switch (alphaPaint) {
+ case AlphaPaintNone:
+ case AlphaPaintImage:
+ {
+ SharedBitmap::DCHolder dc(bmp.get());
+ if (dc.get()) {
+ BitBlt(dc.get(), 0, 0, origRect.width(), origRect.height(), m_dc, origRect.x(), origRect.y(), SRCCOPY);
+ if (bmp->is32bit() && (!m_bitmap || m_bitmap->is16bit())) {
+ // Set alpha channel
+ unsigned* pixels = (unsigned*)bmp->bytes();
+ const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
+ while (pixels < pixelsEnd) {
+ *pixels |= 0xFF000000;
+ ++pixels;
+ }
+ }
+ return bmp;
+ }
+ }
+ break;
+ //case AlphaPaintOther:
+ default:
+ memset(bmp->bytes(), 0xFF, bmp->bitmapInfo().numPixels() * 4);
+ return bmp;
+ break;
+ }
+ }
+ }
+
+ bmpRect = origRect;
+ return 0;
+ }
+
+ void paintBackTransparentLayerBitmap(HDC hdc, SharedBitmap* bmp, const IntRect& origRect, AlphaPaintType alphaPaint, const RECT& bmpRect)
+ {
+ if (hdc == m_dc)
+ return;
+
+#if !defined(NO_ALPHABLEND)
+ if (alphaPaint == AlphaPaintOther) {
+ ASSERT(bmp && bmp->bytes() && bmp->is32bit());
+ unsigned* pixels = (unsigned*)bmp->bytes();
+ const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
+ while (pixels < pixelsEnd) {
+ *pixels ^= 0xFF000000;
+ ++pixels;
+ }
+ }
+ if (m_opacity < 1. || alphaPaint == AlphaPaintOther) {
+ const BLENDFUNCTION blend = { AC_SRC_OVER, 0
+ , m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255)
+ , alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA };
+ AlphaBlend(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend);
+ } else
+#endif
+ StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY);
+ }
+
+ HDC m_dc;
+ RefPtr<SharedBitmap> m_bitmap;
+ Vector<GraphicsContextPlatformPrivateData> m_backupData;
+};
+
+static HPEN createPen(const Color& col, double fWidth, StrokeStyle style)
+{
+ int width = stableRound(fWidth);
+ if (width < 1)
+ width = 1;
+
+ int penStyle = PS_NULL;
+ switch (style) {
+ case SolidStroke:
+ penStyle = PS_SOLID;
+ break;
+ case DottedStroke: // not supported on Windows CE
+ case DashedStroke:
+ penStyle = PS_DASH;
+ width = 1;
+ break;
+ default:
+ break;
+ }
+
+ return CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue()));
+}
+
+static inline HGDIOBJ createBrush(const Color& col)
+{
+ return CreateSolidBrush(RGB(col.red(), col.green(), col.blue()));
+}
+
+template <typename PixelType, bool Is16bit> static void _rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
+{
+ int destW = destBmp->width();
+ int destH = destBmp->height();
+ int sourceW = sourceBmp->width();
+ int sourceH = sourceBmp->height();
+ PixelType* dest = (PixelType*)destBmp->bytes();
+ const PixelType* source = (const PixelType*)sourceBmp->bytes();
+ int padding;
+ int paddedSourceW;
+ if (Is16bit) {
+ padding = destW & 1;
+ paddedSourceW = sourceW + (sourceW & 1);
+ } else {
+ padding = 0;
+ paddedSourceW = sourceW;
+ }
+ if (isZero(transform.m_sinA)) {
+ int cosA = transform.m_cosA > 0 ? 1 : -1;
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ int x1 = x + transform.m_preShiftX;
+ int y1 = y + transform.m_preShiftY;
+ int srcX = x1 * cosA + transform.m_postShiftX;
+ int srcY = y1 * cosA - transform.m_postShiftY;
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX] | 0xFF000000;
+ else
+ *dest++ |= 0xFF;
+ }
+ dest += padding;
+ }
+ } else if (isZero(transform.m_cosA)) {
+ int sinA = transform.m_sinA > 0 ? 1 : -1;
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ int x1 = x + transform.m_preShiftX;
+ int y1 = y + transform.m_preShiftY;
+ int srcX = y1 * sinA + transform.m_postShiftX;
+ int srcY = -x1 * sinA + transform.m_postShiftY;
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX];
+ }
+ dest += padding;
+ }
+ } else {
+ for (int y = 0; y < destH; ++y) {
+ for (int x = 0; x < destW; ++x) {
+ // FIXME: for best quality, we should get weighted sum of four neighbours,
+ // but that will be too expensive
+ int srcX, srcY;
+ transform.map(x, y, &srcX, &srcY);
+ if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
+ *dest++ = source[srcY * paddedSourceW + srcX];
+ }
+ dest += padding;
+ }
+ }
+}
+
+static void rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
+{
+ ASSERT(destBmp->is16bit() == sourceBmp->is16bit());
+ if (destBmp->is16bit())
+ _rotateBitmap<unsigned short, true>(destBmp, sourceBmp, transform);
+ else
+ _rotateBitmap<unsigned, false>(destBmp, sourceBmp, transform);
+}
+
+class TransparentLayerDC : Noncopyable {
+public:
+ TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform = 0, int alpha = 255, bool paintImage = false);
+ ~TransparentLayerDC();
+
+ HDC hdc() const { return m_memDc; }
+ const RECT& rect() const { return m_bmpRect; }
+ IntSize toShift() const { return IntSize(m_bmpRect.left - m_origRect.x(), m_bmpRect.top - m_origRect.y()); }
+ void fillAlphaChannel();
+
+private:
+ GraphicsContextPlatformPrivate* m_data;
+ IntRect m_origRect;
+ IntRect m_rotatedOrigRect;
+ HDC m_memDc;
+ RefPtr<SharedBitmap> m_bitmap;
+ RefPtr<SharedBitmap> m_rotatedBitmap;
+ RECT m_bmpRect;
+ unsigned m_key1;
+ unsigned m_key2;
+ RotationTransform m_rotation;
+ float m_oldOpacity;
+ AlphaPaintType m_alphaPaintType;
+};
+
+TransparentLayerDC::TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform, int alpha, bool paintImage)
+: m_data(data)
+, m_origRect(origRect)
+, m_oldOpacity(data->m_opacity)
+// m_key1 and m_key2 are not initalized here. They are used only in the case that
+// SharedBitmap::getDC() is called, I.E., when m_bitmap is not null.
+{
+ m_data->m_opacity *= alpha / 255.;
+ bool mustCreateLayer;
+ if (!m_data->hasAlpha()) {
+ mustCreateLayer = false;
+ m_alphaPaintType = AlphaPaintNone;
+ } else {
+ mustCreateLayer = true;
+ m_alphaPaintType = paintImage ? AlphaPaintImage : AlphaPaintOther;
+ }
+ if (rectBeforeTransform && !isZero(m_data->m_transform.b())) {
+ m_rotatedOrigRect = origRect;
+ m_rotatedBitmap = m_data->getTransparentLayerBitmap(m_rotatedOrigRect, m_alphaPaintType, m_bmpRect, false, true);
+ if (m_rotatedBitmap) {
+ double a = m_data->m_transform.a();
+ double b = m_data->m_transform.b();
+ double c = _hypot(a, b);
+ m_rotation.m_cosA = a / c;
+ m_rotation.m_sinA = b / c;
+
+ int centerX = origRect.x() + origRect.width() / 2;
+ int centerY = origRect.y() + origRect.height() / 2;
+ m_rotation.m_preShiftX = -centerX;
+ m_rotation.m_preShiftY = -centerY;
+ m_rotation.m_postShiftX = centerX;
+ m_rotation.m_postShiftY = centerY;
+
+ m_origRect = mapRect(m_rotatedOrigRect, m_rotation);
+
+ m_rotation.m_preShiftX += m_rotatedOrigRect.x();
+ m_rotation.m_preShiftY += m_rotatedOrigRect.y();
+ m_rotation.m_postShiftX -= m_origRect.x();
+ m_rotation.m_postShiftY -= m_origRect.y();
+
+ FloatPoint topLeft = m_data->m_transform.mapPoint(FloatPoint(rectBeforeTransform->topLeft()));
+ FloatPoint topRight(rectBeforeTransform->right() - 1, rectBeforeTransform->y());
+ topRight = m_data->m_transform.mapPoint(topRight);
+ FloatPoint bottomLeft(rectBeforeTransform->x(), rectBeforeTransform->bottom() - 1);
+ bottomLeft = m_data->m_transform.mapPoint(bottomLeft);
+ FloatSize sideTop = topRight - topLeft;
+ FloatSize sideLeft = bottomLeft - topLeft;
+ float width = _hypot(sideTop.width() + 1, sideTop.height() + 1);
+ float height = _hypot(sideLeft.width() + 1, sideLeft.height() + 1);
+
+ origRect.inflateX(stableRound((width - origRect.width()) * 0.5));
+ origRect.inflateY(stableRound((height - origRect.height()) * 0.5));
+
+ m_bitmap = SharedBitmap::createInstance(m_rotatedBitmap->is16bit(), m_origRect.width(), m_origRect.height(), true);
+ if (m_bitmap)
+ rotateBitmap(m_bitmap.get(), m_rotatedBitmap.get(), -m_rotation);
+ else
+ m_rotatedBitmap = 0;
+ }
+ } else
+ m_bitmap = m_data->getTransparentLayerBitmap(m_origRect, m_alphaPaintType, m_bmpRect, true, mustCreateLayer);
+ if (m_bitmap)
+ m_memDc = m_bitmap->getDC(&m_key1, &m_key2);
+ else
+ m_memDc = m_data->m_dc;
+}
+
+TransparentLayerDC::~TransparentLayerDC()
+{
+ if (m_rotatedBitmap) {
+ m_bitmap->releaseDC(m_memDc, m_key1, m_key2);
+ m_key1 = m_key2 = 0;
+ rotateBitmap(m_rotatedBitmap.get(), m_bitmap.get(), m_rotation);
+ m_memDc = m_rotatedBitmap->getDC(&m_key1, &m_key2);
+ m_data->paintBackTransparentLayerBitmap(m_memDc, m_rotatedBitmap.get(), m_rotatedOrigRect, m_alphaPaintType, m_bmpRect);
+ m_rotatedBitmap->releaseDC(m_memDc, m_key1, m_key2);
+ } else if (m_bitmap) {
+ m_data->paintBackTransparentLayerBitmap(m_memDc, m_bitmap.get(), m_origRect, m_alphaPaintType, m_bmpRect);
+ m_bitmap->releaseDC(m_memDc, m_key1, m_key2);
+ }
+ m_data->m_opacity = m_oldOpacity;
+}
+
+void TransparentLayerDC::fillAlphaChannel()
+{
+ if (!m_bitmap || !m_bitmap->is32bit())
+ return;
+
+ unsigned* pixels = (unsigned*)m_bitmap->bytes();
+ const unsigned* const pixelsEnd = pixels + m_bitmap->bitmapInfo().numPixels();
+ while (pixels < pixelsEnd) {
+ *pixels |= 0xFF000000;
+ ++pixels;
+ }
+}
+
+class ScopeDCProvider : Noncopyable {
+public:
+ explicit ScopeDCProvider(GraphicsContextPlatformPrivate* data)
+ : m_data(data)
+ {
+ if (m_data->m_bitmap)
+ m_data->m_dc = m_data->m_bitmap->getDC(&m_key1, &m_key2);
+ }
+ ~ScopeDCProvider()
+ {
+ if (m_data->m_bitmap) {
+ m_data->m_bitmap->releaseDC(m_data->m_dc, m_key1, m_key2);
+ m_data->m_dc = 0;
+ }
+ }
+private:
+ GraphicsContextPlatformPrivate* m_data;
+ unsigned m_key1;
+ unsigned m_key2;
+};
+
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext* dc)
+: m_common(createGraphicsContextPrivate())
+, m_data(new GraphicsContextPlatformPrivate(dc))
+{
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ destroyGraphicsContextPrivate(m_common);
+ delete m_data;
+}
+
+void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp)
+{
+ ASSERT(!m_data->m_dc);
+ m_data->m_bitmap = bmp;
+}
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ notImplemented();
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ notImplemented();
+ ASSERT_NOT_REACHED();
+}
+
+void GraphicsContext::savePlatformState()
+{
+ m_data->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ m_data->restore();
+}
+
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (!m_data->m_opacity || paintingDisabled() || rect.isEmpty())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ HGDIOBJ brush = 0;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush);
+ } else
+ SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ HGDIOBJ pen = 0;
+ HGDIOBJ oldPen;
+ if (strokeStyle() != NoStroke) {
+ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ oldPen = SelectObject(dc, pen);
+ } else
+ SelectObject(dc, GetStockObject(NULL_PEN));
+
+ if (!brush && !pen)
+ return;
+
+ if (trRect.width() <= 0)
+ trRect.setWidth(1);
+ if (trRect.height() <= 0)
+ trRect.setHeight(1);
+
+ Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+
+ if (pen) {
+ SelectObject(dc, oldPen);
+ DeleteObject(pen);
+ }
+
+ if (brush) {
+ SelectObject(dc, oldBrush);
+ DeleteObject(brush);
+ }
+}
+
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || !strokeColor().alpha())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntPoint trPoint1 = m_data->mapPoint(point1);
+ IntPoint trPoint2 = m_data->mapPoint(point2);
+
+ IntRect lineRect(trPoint1, trPoint2 - trPoint1);
+ lineRect.setHeight(lineRect.height() + strokeThickness());
+ TransparentLayerDC transparentDC(m_data, lineRect, 0, strokeColor().alpha());
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trPoint1 += transparentDC.toShift();
+ trPoint2 += transparentDC.toShift();
+
+ HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(dc, pen);
+
+ MoveToEx(dc, trPoint1.x(), trPoint1.y(), 0);
+ LineTo(dc, trPoint2.x(), trPoint2.y());
+
+ SelectObject(dc, oldPen);
+ DeleteObject(pen);
+}
+
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (!m_data->m_opacity || paintingDisabled() || (!fillColor().alpha() && strokeStyle() == NoStroke))
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ HGDIOBJ brush = 0;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush);
+ } else
+ SelectObject(dc, GetStockObject(NULL_BRUSH));
+ HGDIOBJ pen = 0;
+ HGDIOBJ oldPen;
+ if (strokeStyle() != NoStroke) {
+ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ oldPen = SelectObject(dc, pen);
+ } else
+ SelectObject(dc, GetStockObject(NULL_PEN));
+
+ Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+
+ if (pen) {
+ SelectObject(dc, oldPen);
+ DeleteObject(pen);
+ }
+
+ if (brush) {
+ SelectObject(dc, oldBrush);
+ DeleteObject(brush);
+ }
+}
+
+static inline bool equalAngle(double a, double b)
+{
+ return fabs(a - b) < 1E-5;
+}
+
+void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y)
+{
+ while (angle < 0)
+ angle += 2 * piDouble;
+ while (angle >= 2 * piDouble)
+ angle -= 2 * piDouble;
+
+ if (equalAngle(angle, 0) || equalAngle(angle, 2 * piDouble)) {
+ x = a;
+ y = 0;
+ } else if (equalAngle(angle, piDouble)) {
+ x = -a;
+ y = 0;
+ } else if (equalAngle(angle, .5 * piDouble)) {
+ x = 0;
+ y = b;
+ } else if (equalAngle(angle, 1.5 * piDouble)) {
+ x = 0;
+ y = -b;
+ } else {
+ double k = tan(angle);
+ double sqA = a * a;
+ double sqB = b * b;
+ double tmp = 1. / (1. / sqA + (k * k) / sqB);
+ tmp = tmp <= 0 ? 0 : sqrt(tmp);
+ if (angle > .5 * piDouble && angle < 1.5 * piDouble)
+ tmp = -tmp;
+ x = tmp;
+
+ k = tan(.5 * piDouble - angle);
+ tmp = 1. / ((k * k) / sqA + 1 / sqB);
+ tmp = tmp <= 0 ? 0 : sqrt(tmp);
+ if (angle > piDouble)
+ tmp = -tmp;
+ y = tmp;
+ }
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || rect.isEmpty())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(dc, pen);
+
+ double a = trRect.width() * 0.5;
+ double b = trRect.height() * 0.5;
+ int centerX = stableRound(trRect.x() + a);
+ int centerY = stableRound(trRect.y() + b);
+ float fstartX, fstartY, fendX, fendY;
+ int startX, startY, endX, endY;
+ getEllipsePointByAngle(deg2rad((double)startAngle), a, b, fstartX, fstartY);
+ getEllipsePointByAngle(deg2rad((double)startAngle + angleSpan), a, b, fendX, fendY);
+ startX = stableRound(fstartX);
+ startY = stableRound(fstartY);
+ endX = stableRound(fendX);
+ endY = stableRound(fendY);
+
+ startX += centerX;
+ startY = centerY - startY;
+ endX += centerX;
+ endY = centerY - endY;
+ RECT clipRect;
+ if (startX < endX) {
+ clipRect.left = startX;
+ clipRect.right = endX;
+ } else {
+ clipRect.left = endX;
+ clipRect.right = startX;
+ }
+ if (startY < endY) {
+ clipRect.top = startY;
+ clipRect.bottom = endY;
+ } else {
+ clipRect.top = endY;
+ clipRect.bottom = startY;
+ }
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ bool newClip;
+ if (GetClipRgn(dc, clipRgn.get()) <= 0) {
+ newClip = true;
+ clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
+ SelectClipRgn(dc, clipRgn.get());
+ } else {
+ newClip = false;
+ IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+ }
+
+ HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
+ Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ SelectObject(dc, oldBrush);
+
+ if (newClip)
+ SelectClipRgn(dc, 0);
+ else
+ SelectClipRgn(dc, clipRgn.get());
+
+ SelectObject(dc, oldPen);
+ DeleteObject(pen);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (!m_data->m_opacity || paintingDisabled() || npoints <= 1 || !points)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ Vector<POINT, 20> winPoints(npoints);
+ FloatPoint trPoint = m_data->mapPoint(points[0]);
+ winPoints[0].x = stableRound(trPoint.x());
+ winPoints[0].y = stableRound(trPoint.y());
+ RECT rect = { winPoints[0].x, winPoints[0].y, winPoints[0].x, winPoints[0].y };
+ for (size_t i = 1; i < npoints; ++i) {
+ trPoint = m_data->mapPoint(points[i]);
+ winPoints[i].x = stableRound(trPoint.x());
+ winPoints[i].y = stableRound(trPoint.y());
+ if (rect.left > winPoints[i].x)
+ rect.left = winPoints[i].x;
+ else if (rect.right < winPoints[i].x)
+ rect.right = winPoints[i].x;
+ if (rect.top > winPoints[i].y)
+ rect.top = winPoints[i].y;
+ else if (rect.bottom < winPoints[i].y)
+ rect.bottom = winPoints[i].y;
+ }
+ rect.bottom += 1;
+ rect.right += 1;
+
+ IntRect intRect(rect);
+ TransparentLayerDC transparentDC(m_data, intRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+
+ for (size_t i = 0; i < npoints; ++i) {
+ winPoints[i].x += transparentDC.toShift().width();
+ winPoints[i].y += transparentDC.toShift().height();
+ }
+
+ HGDIOBJ brush = 0;
+ HGDIOBJ oldBrush;
+ if (fillColor().alpha()) {
+ brush = createBrush(fillColor());
+ oldBrush = SelectObject(dc, brush);
+ } else
+ SelectObject(dc, GetStockObject(NULL_BRUSH));
+
+ HGDIOBJ pen = 0;
+ HGDIOBJ oldPen;
+ if (strokeStyle() != NoStroke) {
+ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ oldPen = SelectObject(dc, pen);
+ } else
+ SelectObject(dc, GetStockObject(NULL_PEN));
+
+ if (!brush && !pen)
+ return;
+
+ Polygon(dc, winPoints.data(), npoints);
+
+ if (pen) {
+ SelectObject(dc, oldPen);
+ DeleteObject(pen);
+ }
+
+ if (brush) {
+ SelectObject(dc, oldBrush);
+ DeleteObject(brush);
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled() || !m_data->m_opacity)
+ return;
+
+ int alpha = color.alpha();
+ if (!alpha)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intRect = enclosingIntRect(rect);
+ TransparentLayerDC transparentDC(m_data, m_data->mapRect(intRect), &intRect, alpha);
+
+ if (!transparentDC.hdc())
+ return;
+
+ OwnPtr<HBRUSH> hbrush(CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
+ FillRect(transparentDC.hdc(), &transparentDC.rect(), hbrush.get());
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0)
+ IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+ else {
+ clipRgn.set(CreateRectRgn(trRect.x(), trRect.y(), trRect.right(), trRect.bottom()));
+ SelectClipRgn(m_data->m_dc, clipRgn.get());
+ }
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+
+ ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom());
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (!m_data->m_opacity || paintingDisabled())
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ int radius = (focusRingWidth() - 1) / 2;
+ int offset = radius + focusRingOffset();
+
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+ IntRect finalFocusRect;
+ for (unsigned i = 0; i < rectCount; i++) {
+ IntRect focusRect = rects[i];
+ focusRect.inflate(offset);
+ finalFocusRect.unite(focusRect);
+ }
+
+ IntRect intRect = finalFocusRect;
+ IntRect trRect = m_data->mapRect(finalFocusRect);
+ TransparentLayerDC transparentDC(m_data, trRect, &intRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rect = trRect;
+ DrawFocusRect(dc, &rect);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle oldStyle = strokeStyle();
+ setStrokeStyle(SolidStroke);
+ drawLine(origin, origin + IntSize(width, 0));
+ setStrokeStyle(oldStyle);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& col)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& col)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ // We can only clip rectangles on WINCE
+ clip(rect);
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->hasAlpha()) {
+ IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
+ m_data->m_bitmap->clearPixels(trRect);
+ return;
+ }
+
+ fillRect(rect, Color(Color::white));
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float width)
+{
+ if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intRect = enclosingIntRect(rect);
+ IntRect trRect = m_data->mapRect(intRect);
+ TransparentLayerDC transparentDC(m_data, trRect, &intRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(dc, pen);
+
+ int right = trRect.right() - 1;
+ int bottom = trRect.bottom() - 1;
+ const POINT intPoints[5] =
+ {
+ { trRect.x(), trRect.y() },
+ { right, trRect.y() },
+ { right, bottom },
+ { trRect.x(), bottom },
+ { trRect.x(), trRect.y() }
+ };
+
+ Polyline(dc, intPoints, 5);
+
+ SelectObject(dc, oldPen);
+ DeleteObject(pen);
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ m_data->save();
+ m_data->m_opacity *= opacity;
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ m_data->restore();
+}
+
+void GraphicsContext::concatCTM(const TransformationMatrix& transform)
+{
+ m_data->concatCTM(transform);
+}
+
+TransformationMatrix& GraphicsContext::affineTransform()
+{
+ return m_data->m_transform;
+}
+
+const TransformationMatrix& GraphicsContext::affineTransform() const
+{
+ return m_data->m_transform;
+}
+
+void GraphicsContext::resetAffineTransform()
+{
+ m_data->m_transform.makeIdentity();
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ m_data->translate(x, y);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ m_data->rotate(radians);
+}
+
+IntPoint GraphicsContext::origin()
+{
+ return m_data->origin();
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ m_data->scale(size);
+}
+
+void GraphicsContext::setLineCap(LineCap lineCap)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineJoin(LineJoin lineJoin)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setMiterLimit(float miter)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_data->m_opacity = alpha;
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ notImplemented();
+}
+
+void GraphicsContext::beginPath()
+{
+ m_data->m_paths.clear();
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ m_data->m_paths.append(path);
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipOut(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect&)
+{
+ notImplemented();
+}
+
+static inline IntPoint rectCenterPoint(const RECT& rect)
+{
+ return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2);
+}
+void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c)
+{
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntSize shadowSize;
+ int shadowBlur = 0;
+ Color shadowColor;
+
+ getShadow(shadowSize, shadowBlur, shadowColor);
+
+ IntRect dstRect = fillRect;
+
+ dstRect.move(shadowSize);
+ dstRect.inflate(shadowBlur);
+ dstRect = m_data->mapRect(dstRect);
+
+ FloatSize newTopLeft(m_data->mapSize(topLeft));
+ FloatSize newTopRight(m_data->mapSize(topRight));
+ FloatSize newBottomLeft(m_data->mapSize(bottomLeft));
+ FloatSize newBottomRight(m_data->mapSize(bottomRight));
+
+ TransparentLayerDC transparentDc(m_data, dstRect, &fillRect);
+ HDC dc = transparentDc.hdc();
+ if (!dc)
+ return;
+
+ dstRect.move(transparentDc.toShift());
+
+ RECT rectWin = dstRect;
+
+ HGDIOBJ brush = createBrush(shadowColor);
+ HGDIOBJ oldBrush = SelectObject(dc, brush);
+
+ SelectObject(dc, GetStockObject(NULL_PEN));
+
+ IntPoint centerPoint = rectCenterPoint(rectWin);
+ // Draw top left half
+ RECT clipRect(rectWin);
+ clipRect.right = centerPoint.x();
+ clipRect.bottom = centerPoint.y();
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ bool needsNewClip = (GetClipRgn(dc, clipRgn.get()) <= 0);
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopLeft.width() * 2), stableRound(newTopLeft.height() * 2));
+
+ // Draw top right
+ clipRect = rectWin;
+ clipRect.left = centerPoint.x();
+ clipRect.bottom = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopRight.width() * 2), stableRound(newTopRight.height() * 2));
+
+ // Draw bottom left
+ clipRect = rectWin;
+ clipRect.right = centerPoint.x();
+ clipRect.top = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomLeft.width() * 2), stableRound(newBottomLeft.height() * 2));
+
+ // Draw bottom right
+ clipRect = rectWin;
+ clipRect.left = centerPoint.x();
+ clipRect.top = centerPoint.y();
+
+ drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2));
+
+ SelectObject(dc, oldBrush);
+ DeleteObject(brush);
+}
+
+
+void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height)
+{
+ if (!dc)
+ return;
+
+ OwnPtr<HRGN> clipRgn(CreateRectRgn(0, 0, 0, 0));
+ if (needsNewClip) {
+ clipRgn.set(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
+ SelectClipRgn(dc, clipRgn.get());
+ } else
+ IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+
+ ::RoundRect(dc, rectWin.left , rectWin.top , rectWin.right , rectWin.bottom , width, height);
+
+ SelectClipRgn(dc, needsNewClip ? 0 : clipRgn.get());
+}
+
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ notImplemented();
+ return frect;
+}
+
+Color gradientAverageColor(const Gradient* gradient)
+{
+ const Vector<Gradient::ColorStop>& stops = gradient->getStops();
+ if (stops.isEmpty())
+ return Color();
+
+ const Gradient::ColorStop& stop = stops.first();
+ if (stops.size() == 1)
+ return Color(stop.red, stop.green, stop.blue, stop.alpha);
+
+ const Gradient::ColorStop& lastStop = stops.last();
+ return Color((stop.red + lastStop.red) * 0.5f
+ , (stop.green + lastStop.green) * 0.5f
+ , (stop.blue + lastStop.blue) * 0.5f
+ , (stop.alpha + lastStop.alpha) * 0.5f);
+}
+
+void GraphicsContext::fillPath()
+{
+ Color c = m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient
+ ? gradientAverageColor(m_common->state.fillGradient.get())
+ : fillColor();
+
+ if (!c.alpha() || !m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
+ HGDIOBJ brush = createBrush(c);
+ for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) {
+ IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect()));
+ trRect.inflate(1);
+ TransparentLayerDC transparentDC(m_data, trRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ continue;
+
+ TransformationMatrix tr = m_data->m_transform;
+ tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
+
+ SelectObject(dc, GetStockObject(NULL_PEN));
+ HGDIOBJ oldBrush = SelectObject(dc, brush);
+ i->platformPath()->fillPath(dc, &tr);
+ SelectObject(dc, oldBrush);
+ }
+ DeleteObject(brush);
+ } else {
+ SelectObject(m_data->m_dc, GetStockObject(NULL_PEN));
+ HGDIOBJ brush = createBrush(c);
+ HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush);
+ for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i)
+ i->platformPath()->fillPath(m_data->m_dc, &m_data->m_transform);
+ SelectObject(m_data->m_dc, oldBrush);
+ DeleteObject(brush);
+ }
+}
+
+
+void GraphicsContext::strokePath()
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
+ HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) {
+ IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect()));
+ trRect.inflate(1);
+ TransparentLayerDC transparentDC(m_data, trRect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ continue;
+
+ TransformationMatrix tr = m_data->m_transform;
+ tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
+
+ SelectObject(dc, GetStockObject(NULL_BRUSH));
+ HGDIOBJ oldPen = SelectObject(dc, pen);
+ i->platformPath()->strokePath(dc, &tr);
+ SelectObject(dc, oldPen);
+ }
+ DeleteObject(pen);
+ } else {
+ SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH));
+ HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
+ HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen);
+ for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i)
+ i->platformPath()->strokePath(m_data->m_dc, &m_data->m_transform);
+ SelectObject(m_data->m_dc, oldPen);
+ DeleteObject(pen);
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ const Vector<Gradient::ColorStop>& stops = gradient->getStops();
+ if (stops.isEmpty())
+ return;
+
+ size_t numStops = stops.size();
+ if (numStops == 1) {
+ const Gradient::ColorStop& stop = stops.first();
+ Color color(stop.red, stop.green, stop.blue, stop.alpha);
+ fillRect(r, color);
+ return;
+ }
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intRect = enclosingIntRect(r);
+ IntRect rect = m_data->mapRect(intRect);
+ TransparentLayerDC transparentDC(m_data, rect, &intRect, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+
+ rect.move(transparentDC.toShift());
+ FloatPoint fp0 = m_data->mapPoint(gradient->p0());
+ FloatPoint fp1 = m_data->mapPoint(gradient->p1());
+ IntPoint p0(stableRound(fp0.x()), stableRound(fp0.y()));
+ IntPoint p1(stableRound(fp1.x()), stableRound(fp1.y()));
+ p0 += transparentDC.toShift();
+ p1 += transparentDC.toShift();
+
+ if (gradient->isRadial()) {
+ if (g_radialGradientFiller) {
+ // FIXME: don't support 2D scaling at this time
+ double scale = (m_data->m_transform.a() + m_data->m_transform.d()) * 0.5;
+ float r0 = gradient->r0() * scale;
+ float r1 = gradient->r1() * scale;
+ g_radialGradientFiller(dc, rect, p0, p1, r0, r1, gradient->getStops());
+ return;
+ }
+ } else if (g_linearGradientFiller) {
+ g_linearGradientFiller(dc, rect, p0, p1, gradient->getStops());
+ return;
+ }
+
+ // Simple 1D linear solution that assumes p0 is on the top or left side, and p1 is on the right or bottom side
+ size_t numRects = (numStops - 1);
+ Vector<TRIVERTEX, 20> tv;
+ tv.resize(numRects * 2);
+ Vector<GRADIENT_RECT, 10> mesh;
+ mesh.resize(numRects);
+ int x = rect.x();
+ int y = rect.y();
+ int width = rect.width();
+ int height = rect.height();
+ FloatSize d = gradient->p1() - gradient->p0();
+ bool vertical = abs(d.height()) > abs(d.width());
+ for (size_t i = 0; i < numStops; ++i) {
+ const Gradient::ColorStop& stop = stops[i];
+ int iTv = i ? 2 * i - 1 : 0;
+ tv[iTv].Red = stop.red * 0xFFFF;
+ tv[iTv].Green = stop.green * 0xFFFF;
+ tv[iTv].Blue = stop.blue * 0xFFFF;
+ tv[iTv].Alpha = stop.alpha * 0xFFFF;
+ if (i) {
+ tv[iTv].x = vertical ? x + width: x + width * stop.stop;
+ tv[iTv].y = vertical ? y + height * stop.stop : y + height;
+ mesh[i - 1].UpperLeft = iTv - 1;
+ mesh[i - 1].LowerRight = iTv;
+ } else {
+ tv[iTv].x = x;
+ tv[iTv].y = y;
+ }
+
+ if (i && i < numRects) {
+ tv[iTv + 1] = tv[iTv];
+ if (vertical)
+ tv[iTv + 1].x = x;
+ else
+ tv[iTv + 1].y = y;
+ }
+ }
+
+ GradientFill(dc, tv.data(), tv.size(), mesh.data(), mesh.size(), vertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
+}
+
+TransformationMatrix GraphicsContext::getCTM() const
+{
+ return m_data->m_transform;
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
+{
+ notImplemented();
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient)
+ fillRect(rect, m_common->state.fillGradient.get());
+ else
+ fillRect(rect, fillColor());
+}
+
+void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ notImplemented();
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+ notImplemented();
+}
+
+static inline bool isCharVisible(UChar c)
+{
+ return c && c != zeroWidthSpace;
+}
+
+void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to)
+{
+ if (paintingDisabled() || !fillColor().alpha() || !m_data->m_opacity)
+ return;
+
+ bool mustSupportAlpha = m_data->hasAlpha();
+
+ if (!mustSupportAlpha && fillColor().alpha() == 0xFF && m_data->m_opacity >= 1.0) {
+ font.drawText(this, run, point, from, to);
+ return;
+ }
+
+ float oldOpacity = m_data->m_opacity;
+ m_data->m_opacity *= fillColor().alpha() / 255.0;
+
+ FloatRect textRect = font.selectionRectForText(run, point, font.height(), from, to);
+ textRect.setY(textRect.y() - font.ascent());
+ IntRect trRect = enclosingIntRect(m_data->mapRect(textRect));
+ RECT bmpRect;
+ AlphaPaintType alphaPaintType = mustSupportAlpha ? AlphaPaintOther : AlphaPaintNone;
+ if (RefPtr<SharedBitmap> bmp = m_data->getTransparentLayerBitmap(trRect, alphaPaintType, bmpRect, true, mustSupportAlpha)) {
+ {
+ GraphicsContext gc(0);
+ gc.setBitmap(bmp);
+ gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d()));
+ font.drawText(&gc, run, IntPoint(0, font.ascent()), from, to);
+ }
+ unsigned key1, key2;
+ HDC memDC = bmp->getDC(&key1, &key2);
+ if (memDC) {
+ m_data->paintBackTransparentLayerBitmap(memDC, bmp.get(), trRect, alphaPaintType, bmpRect);
+ bmp->releaseDC(memDC, key1, key2);
+ }
+ }
+
+ m_data->m_opacity = oldOpacity;
+}
+
+void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ for (;;) {
+ if (!numGlyphs)
+ return;
+ if (isCharVisible(*glyphBuffer.glyphs(from)))
+ break;
+ ++from;
+ --numGlyphs;
+ }
+
+ double scaleX = m_data->m_transform.a();
+ double scaleY = m_data->m_transform.d();
+
+ int height = fontData->platformData().size() * scaleY;
+ int width = fontData->platformData().averageCharWidth() * scaleX;
+
+ if (!height || !width)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ HFONT hFont = height > 1
+ ? fontData->platformData().getScaledFontHandle(height, scaleX == scaleY ? 0 : width)
+ : 0;
+
+ FloatPoint startPoint(point.x(), point.y() - fontData->ascent());
+ FloatPoint trPoint = m_data->mapPoint(startPoint);
+ int y = stableRound(trPoint.y());
+
+ Color color = fillColor();
+ if (!color.alpha())
+ return;
+
+ COLORREF fontColor = RGB(color.red(), color.green(), color.blue());
+
+ if (!hFont) {
+ double offset = trPoint.x();
+ const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
+ if (scaleX == 1.)
+ for (int i = 1; i < numGlyphs; ++i)
+ offset += *advance++;
+ else
+ for (int i = 1; i < numGlyphs; ++i)
+ offset += *advance++ * scaleX;
+
+ offset += width;
+
+ OwnPtr<HPEN> hPen(CreatePen(PS_DASH, 1, fontColor));
+ HGDIOBJ oldPen = SelectObject(m_data->m_dc, hPen.get());
+
+ MoveToEx(m_data->m_dc, stableRound(trPoint.x()), y, 0);
+ LineTo(m_data->m_dc, stableRound(offset), y);
+
+ SelectObject(m_data->m_dc, oldPen);
+ return;
+ }
+
+ IntSize shadowSize;
+ int shadowBlur = 0;
+ Color shadowColor;
+ bool hasShadow = textDrawingMode() == cTextFill
+ && getShadow(shadowSize, shadowBlur, shadowColor)
+ && shadowColor.alpha();
+ COLORREF shadowRGBColor;
+ FloatPoint trShadowPoint;
+ if (hasShadow) {
+ shadowRGBColor = RGB(shadowColor.red(), shadowColor.green(), shadowColor.blue());
+ trShadowPoint = m_data->mapPoint(startPoint + shadowSize);
+ }
+
+ HGDIOBJ hOldFont = SelectObject(m_data->m_dc, hFont);
+ COLORREF oldTextColor = GetTextColor(m_data->m_dc);
+ int oldTextAlign = GetTextAlign(m_data->m_dc);
+ SetTextAlign(m_data->m_dc, 0);
+
+ int oldBkMode = GetBkMode(m_data->m_dc);
+ SetBkMode(m_data->m_dc, TRANSPARENT);
+
+ if (numGlyphs > 1) {
+ double offset = trPoint.x();
+ Vector<int, 256> glyphSpace(numGlyphs);
+ Vector<UChar, 256> text(numGlyphs);
+ int* curSpace = glyphSpace.data();
+ UChar* curChar = text.data();
+ const UChar* srcChar = glyphBuffer.glyphs(from);
+ const UChar* const srcCharEnd = srcChar + numGlyphs;
+ *curChar++ = *srcChar++;
+ int firstOffset = stableRound(offset);
+ int lastOffset = firstOffset;
+ const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
+ // FIXME: ExtTextOut() can flip over each word for RTL languages, even when TA_RTLREADING is off.
+ // (this can be GDI bug or font driver bug?)
+ // We are not clear how it processes characters and handles specified spaces. On the other side,
+ // our glyph buffer is already in the correct order for rendering. So, the solution is that we
+ // call ExtTextOut() for each single character when the text contains any RTL character.
+ // This solution is not perfect as it is slower than calling ExtTextOut() one time for all characters.
+ // Drawing characters one by one may be too slow.
+ bool drawOneByOne = false;
+ if (scaleX == 1.) {
+ for (; srcChar < srcCharEnd; ++srcChar) {
+ offset += *advance++;
+ int offsetInt = stableRound(offset);
+ if (isCharVisible(*srcChar)) {
+ if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
+ drawOneByOne = true;
+ *curChar++ = *srcChar;
+ *curSpace++ = offsetInt - lastOffset;
+ lastOffset = offsetInt;
+ }
+ }
+ } else {
+ for (; srcChar < srcCharEnd; ++srcChar) {
+ offset += *advance++ * scaleX;
+ int offsetInt = stableRound(offset);
+ if (isCharVisible(*srcChar)) {
+ if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
+ drawOneByOne = true;
+ *curChar++ = *srcChar;
+ *curSpace++ = offsetInt - lastOffset;
+ lastOffset = offsetInt;
+ }
+ }
+ }
+ numGlyphs = curChar - text.data();
+ if (hasShadow) {
+ SetTextColor(m_data->m_dc, shadowRGBColor);
+ if (drawOneByOne) {
+ int xShadow = firstOffset + stableRound(trShadowPoint.x() - trPoint.x());
+ int yShadow = stableRound(trShadowPoint.y());
+ for (int i = 0; i < numGlyphs; ++i) {
+ ExtTextOut(m_data->m_dc, xShadow, yShadow, 0, NULL, text.data() + i, 1, 0);
+ xShadow += glyphSpace[i];
+ }
+ } else
+ ExtTextOut(m_data->m_dc, firstOffset + stableRound(trShadowPoint.x() - trPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, text.data(), numGlyphs, glyphSpace.data());
+ }
+ SetTextColor(m_data->m_dc, fontColor);
+ if (drawOneByOne) {
+ int x = firstOffset;
+ for (int i = 0; i < numGlyphs; ++i) {
+ ExtTextOut(m_data->m_dc, x, y, 0, NULL, text.data() + i, 1, 0);
+ x += glyphSpace[i];
+ }
+ } else
+ ExtTextOut(m_data->m_dc, firstOffset, y, 0, NULL, text.data(), numGlyphs, glyphSpace.data());
+ } else {
+ UChar c = *glyphBuffer.glyphs(from);
+ if (hasShadow) {
+ SetTextColor(m_data->m_dc, shadowRGBColor);
+ ExtTextOut(m_data->m_dc, stableRound(trShadowPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, &c, 1, 0);
+ }
+ SetTextColor(m_data->m_dc, fontColor);
+ ExtTextOut(m_data->m_dc, stableRound(trPoint.x()), y, 0, NULL, &c, 1, 0);
+ }
+
+ SetTextAlign(m_data->m_dc, oldTextAlign);
+ SetTextColor(m_data->m_dc, oldTextColor);
+ SetBkMode(m_data->m_dc, oldBkMode);
+ SelectObject(m_data->m_dc, hOldFont);
+}
+
+void GraphicsContext::drawFrameControl(const IntRect& rect, unsigned type, unsigned state)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ const int boxWidthBest = 8;
+ const int boxHeightBest = 8;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rectWin = trRect;
+
+ if ((rectWin.right - rectWin.left) < boxWidthBest) {
+ RefPtr<SharedBitmap> bmp = SharedBitmap::createInstance(true, boxWidthBest, boxHeightBest, true);
+ SharedBitmap::DCHolder memDC(bmp.get());
+ if (memDC.get()) {
+ RECT tempRect = {0, 0, boxWidthBest, boxHeightBest};
+ DrawFrameControl(memDC.get(), &tempRect, type, state);
+
+ ::StretchBlt(dc, rectWin.left, rectWin.top, rectWin.right - rectWin.left, rectWin.bottom - rectWin.top, memDC.get(), 0, 0, boxWidthBest, boxHeightBest, SRCCOPY);
+ return;
+ }
+ }
+
+ DrawFrameControl(dc, &rectWin, type, state);
+}
+
+void GraphicsContext::drawFocusRect(const IntRect& rect)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rectWin = trRect;
+ DrawFocusRect(dc, &rectWin);
+}
+
+void GraphicsContext::paintTextField(const IntRect& rect, unsigned state)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect trRect = m_data->mapRect(rect);
+ TransparentLayerDC transparentDC(m_data, trRect, &rect);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+
+ RECT rectWin = trRect;
+ DrawEdge(dc, &rectWin, EDGE_ETCHED, BF_RECT | BF_ADJUST);
+ FillRect(dc, &rectWin, reinterpret_cast<HBRUSH>(((state & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
+}
+
+void GraphicsContext::drawBitmap(SharedBitmap* bmp, const IntRect& dstRectIn, const IntRect& srcRect, CompositeOperator compositeOp)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect dstRect = m_data->mapRect(dstRectIn);
+ TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ dstRect.move(transparentDC.toShift());
+
+ bmp->draw(dc, dstRect, srcRect, compositeOp);
+
+ if (bmp->is16bit())
+ transparentDC.fillAlphaChannel();
+}
+
+void GraphicsContext::drawBitmapPattern(SharedBitmap* bmp, const FloatRect& tileRectIn, const TransformationMatrix& patternTransform,
+ const FloatPoint& phase, CompositeOperator op, const FloatRect& destRectIn, const IntSize& origSourceSize)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect intDstRect = enclosingIntRect(destRectIn);
+ IntRect trRect = m_data->mapRect(intDstRect);
+ TransparentLayerDC transparentDC(m_data, trRect, &intDstRect, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ trRect.move(transparentDC.toShift());
+ FloatRect movedDstRect = m_data->m_transform.inverse().mapRect(FloatRect(trRect));
+ FloatSize moved(movedDstRect.location() - destRectIn.location());
+ TransformationMatrix transform = m_data->m_transform;
+ transform.translate(moved.width(), moved.height());
+
+ bmp->drawPattern(dc, transform, tileRectIn, patternTransform, phase, op, destRectIn, origSourceSize);
+
+ if (!bmp->hasAlpha())
+ transparentDC.fillAlphaChannel();
+}
+
+void GraphicsContext::drawIcon(HICON icon, const IntRect& dstRectIn, UINT flags)
+{
+ if (!m_data->m_opacity)
+ return;
+
+ ScopeDCProvider dcProvider(m_data);
+ if (!m_data->m_dc)
+ return;
+
+ IntRect dstRect = m_data->mapRect(dstRectIn);
+ TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
+ HDC dc = transparentDC.hdc();
+ if (!dc)
+ return;
+ dstRect.move(transparentDC.toShift());
+
+ DrawIconEx(dc, dstRect.x(), dstRect.y(), icon, dstRect.width(), dstRect.height(), 0, NULL, flags);
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineDash(const DashArray&, float)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipPath(WindRule)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/wince/SimpleFontDataWince.cpp b/WebCore/platform/graphics/wince/SimpleFontDataWince.cpp
new file mode 100644
index 0000000..1195294
--- /dev/null
+++ b/WebCore/platform/graphics/wince/SimpleFontDataWince.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+#include <mlang.h>
+#include <tchar.h>
+
+namespace WebCore {
+
+extern HDC g_screenDC;
+
+void SimpleFontData::platformInit()
+{
+ if (!m_platformData.isValid())
+ return;
+
+ const TEXTMETRIC& tm = m_platformData.metrics();
+ m_isSystemFont = m_platformData.isSystemFont();
+
+ m_ascent = (tm.tmAscent * m_platformData.size() + 36) / 72;
+ m_descent = (tm.tmDescent * m_platformData.size() + 36) / 72;
+ m_lineGap = (tm.tmExternalLeading * m_platformData.size() + 36) / 72;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_xHeight = m_ascent * 0.56f;
+}
+
+void SimpleFontData::platformDestroy()
+{
+ delete m_smallCapsFontData;
+ m_smallCapsFontData = 0;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ FontDescription fontDesc(fontDescription);
+ fontDesc.setComputedSize(lroundf(0.70f * fontDesc.computedSize()));
+ fontDesc.setSpecifiedSize(lroundf(0.70f * fontDesc.specifiedSize()));
+ fontDesc.setKeywordSize(lroundf(0.70f * fontDesc.keywordSize()));
+ FontPlatformData* result = fontCache()->getCachedFontPlatformData(fontDesc, m_platformData.family());
+ if (result)
+ m_smallCapsFontData = new SimpleFontData(*result);
+ }
+ return m_smallCapsFontData;
+}
+
+DWORD getKnownFontCodePages(const wchar_t* family);
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ if (m_platformData.isDisabled())
+ return true;
+
+ // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC
+ // merely by testing code page intersection. This seems suspect though. Can't a font only partially
+ // cover a given code page?
+
+ // FIXME: in the case that we failed to get the interface, still use the font.
+#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2)
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
+#else
+ IMLangFontLink* langFontLink = fontCache()->getFontLinkInterface();
+#endif
+ if (!langFontLink)
+ return true;
+
+ DWORD fontCodePages = m_platformData.codePages();
+ if (!fontCodePages)
+ return false;
+
+ DWORD acpCodePages = 0;
+ langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
+
+ DWORD actualCodePages;
+ long numCharactersProcessed;
+ while (length) {
+ langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
+ if (actualCodePages && !(actualCodePages & fontCodePages))
+ return false;
+
+ length -= numCharactersProcessed;
+ characters += numCharactersProcessed;
+ }
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (!m_platformData.isValid())
+ return;
+
+ const TEXTMETRIC& tm = m_platformData.metrics();
+
+ // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
+ // is *not* fixed pitch. Unbelievable but true.
+ m_treatAsFixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_platformData.isDisabled())
+ return 0;
+
+ HGDIOBJ hOldFont = SelectObject(g_screenDC, m_platformData.hfont());
+
+ SIZE fontSize;
+ wchar_t c = glyph;
+ GetTextExtentPoint32(g_screenDC, &c, 1, &fontSize);
+
+ SelectObject(g_screenDC, hOldFont);
+
+ return (float)fontSize.cx * (float)m_platformData.size() / 72.f;
+}
+
+
+void SimpleFontData::platformCharWidthInit()
+{
+ if (!m_platformData.isValid())
+ return;
+
+ const TEXTMETRIC& tm = m_platformData.metrics();
+ m_avgCharWidth = (tm.tmAveCharWidth * m_platformData.size() + 36) / 72;
+ m_maxCharWidth = (tm.tmMaxCharWidth * m_platformData.size() + 36) / 72;
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h
index c77968a..3b99830 100644
--- a/WebCore/platform/graphics/wx/FontPlatformData.h
+++ b/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -40,6 +40,8 @@
namespace WebCore {
+class String;
+
class FontHolder: public WTF::RefCounted<FontHolder>
{
public:
@@ -111,7 +113,9 @@ public:
bool isHashTableDeletedValue() const { return m_fontState == DELETED; }
-
+#ifndef NDEBUG
+ String description() const;
+#endif
private:
WTF::RefPtr<FontHolder> m_font;
diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
index ce5e40e..de92fcd 100644
--- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
+++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
@@ -27,7 +27,7 @@
#include "FontPlatformData.h"
#include "FontDescription.h"
-
+#include "PlatformString.h"
#include <wx/defs.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
@@ -122,4 +122,11 @@ FontPlatformData::~FontPlatformData()
m_font = 0;
}
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
}
diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp
index ea3dfe8..e71dbde 100644
--- a/WebCore/platform/graphics/wx/ImageBufferWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp
@@ -36,7 +36,7 @@ ImageBufferData::ImageBufferData(const IntSize&)
{
}
-ImageBuffer::ImageBuffer(const IntSize&, bool grayScale, bool& success) :
+ImageBuffer::ImageBuffer(const IntSize&, ImageColorSpace imageColorSpace, bool& success) :
m_data(IntSize())
{
notImplemented();
diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
index 2f71d62..06c165d 100644
--- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
@@ -110,6 +110,8 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
// This method will examine the data and instantiate an instance of the appropriate decoder plugin.
// If insufficient bytes are available to determine the image type, no decoder plugin will be
// made.
+ if (m_decoder)
+ delete m_decoder;
m_decoder = createDecoder(*data);
if (!m_decoder)
return;
@@ -132,9 +134,12 @@ IntSize ImageSource::size() const
return m_decoder->size();
}
-IntSize ImageSource::frameSizeAtIndex(size_t) const
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
{
- return size();
+ if (!m_decoder)
+ return IntSize();
+
+ return m_decoder->frameSizeAtIndex(index);
}
int ImageSource::repetitionCount()
@@ -185,56 +190,7 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
return 0;
- IntRect imageRect = buffer->rect();
- unsigned char* bytes = (unsigned char*)buffer->bytes().data();
- long colorSize = buffer->bytes().size();
-
- typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> PixelData;
-
- int width = size().width();
- int height = size().height();
-
- wxBitmap* bmp = new wxBitmap(width, height, 32);
- PixelData data(*bmp);
-
- int rowCounter = 0;
- long pixelCounter = 0;
-
- PixelData::Iterator p(data);
-
- PixelData::Iterator rowStart = p;
-
- // NB: It appears that the data is in BGRA format instead of RGBA format.
- // This code works properly on both ppc and intel, meaning the issue is
- // likely not an issue of byte order getting mixed up on different archs.
- for (long i = 0; i < buffer->bytes().size()*4; i+=4) {
- p.Red() = bytes[i+2];
- p.Green() = bytes[i+1];
- p.Blue() = bytes[i+0];
- p.Alpha() = bytes[i+3];
-
- p++;
-
- pixelCounter++;
- if ( (pixelCounter % width ) == 0 ) {
- rowCounter++;
- p = rowStart;
- p.MoveTo(data, 0, rowCounter);
- }
-
- }
-#if !wxCHECK_VERSION(2,9,0)
- bmp->UseAlpha();
-#endif
- ASSERT(bmp->IsOk());
-
-#if USE(WXGC)
- wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp));
- delete bmp;
- return bitmap;
-#else
- return bmp;
-#endif
+ return buffer->asNewNativeImage();
}
float ImageSource::frameDurationAtIndex(size_t index)
diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp
index 04a952d..cebc05a 100644
--- a/WebCore/platform/graphics/wx/PathWx.cpp
+++ b/WebCore/platform/graphics/wx/PathWx.cpp
@@ -227,4 +227,9 @@ bool Path::isEmpty() const
return true;
}
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
}