summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp171
-rw-r--r--WebCore/platform/graphics/BitmapImage.h40
-rw-r--r--WebCore/platform/graphics/Color.cpp15
-rw-r--r--WebCore/platform/graphics/FloatPoint.cpp4
-rw-r--r--WebCore/platform/graphics/FloatPoint.h11
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.cpp46
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.h15
-rw-r--r--WebCore/platform/graphics/FloatQuad.cpp60
-rw-r--r--WebCore/platform/graphics/FloatQuad.h138
-rw-r--r--WebCore/platform/graphics/FloatRect.cpp12
-rw-r--r--WebCore/platform/graphics/FloatRect.h4
-rw-r--r--WebCore/platform/graphics/FloatSize.h7
-rw-r--r--WebCore/platform/graphics/Font.cpp390
-rw-r--r--WebCore/platform/graphics/Font.h77
-rw-r--r--WebCore/platform/graphics/FontCache.cpp24
-rw-r--r--WebCore/platform/graphics/FontCache.h42
-rw-r--r--WebCore/platform/graphics/FontFallbackList.cpp18
-rw-r--r--WebCore/platform/graphics/FontFastPath.cpp367
-rw-r--r--WebCore/platform/graphics/GeneratedImage.cpp2
-rw-r--r--WebCore/platform/graphics/GeneratedImage.h5
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h14
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp47
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h45
-rw-r--r--WebCore/platform/graphics/GraphicsContextPrivate.h11
-rw-r--r--WebCore/platform/graphics/Image.cpp29
-rw-r--r--WebCore/platform/graphics/Image.h23
-rw-r--r--WebCore/platform/graphics/ImageBuffer.h7
-rw-r--r--WebCore/platform/graphics/ImageObserver.h3
-rw-r--r--WebCore/platform/graphics/ImageSource.h41
-rw-r--r--WebCore/platform/graphics/IntSize.h6
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h3
-rw-r--r--WebCore/platform/graphics/Path.h20
-rw-r--r--WebCore/platform/graphics/Pattern.h4
-rw-r--r--WebCore/platform/graphics/SegmentedFontData.cpp17
-rw-r--r--WebCore/platform/graphics/SegmentedFontData.h12
-rw-r--r--WebCore/platform/graphics/SimpleFontData.cpp26
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h9
-rw-r--r--WebCore/platform/graphics/StrokeStyleApplier.h38
-rw-r--r--WebCore/platform/graphics/android/FontCacheAndroid.cpp2
-rw-r--r--WebCore/platform/graphics/android/GraphicsContextAndroid.cpp52
-rw-r--r--WebCore/platform/graphics/android/ImageAndroid.cpp11
-rw-r--r--WebCore/platform/graphics/android/ImageBufferAndroid.cpp7
-rw-r--r--WebCore/platform/graphics/android/ImageSourceAndroid.cpp8
-rw-r--r--WebCore/platform/graphics/android/PathAndroid.cpp52
-rw-r--r--WebCore/platform/graphics/android/PatternAndroid.cpp2
-rw-r--r--WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp (renamed from WebCore/platform/graphics/android/AffineTransformAndroid.cpp)162
-rw-r--r--WebCore/platform/graphics/android/android_graphics.cpp2
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp69
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h4
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp4
-rw-r--r--WebCore/platform/graphics/cairo/ImageCairo.cpp14
-rw-r--r--WebCore/platform/graphics/cairo/ImageSourceCairo.cpp20
-rw-r--r--WebCore/platform/graphics/cairo/PathCairo.cpp125
-rw-r--r--WebCore/platform/graphics/cairo/PatternCairo.cpp7
-rw-r--r--WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp (renamed from WebCore/platform/graphics/cairo/AffineTransformCairo.cpp)68
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp140
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h6
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferCG.cpp4
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp19
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp23
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.h41
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCGMac.mm48
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCGWin.cpp84
-rw-r--r--WebCore/platform/graphics/cg/PDFDocumentImage.h7
-rw-r--r--WebCore/platform/graphics/cg/PathCG.cpp80
-rw-r--r--WebCore/platform/graphics/cg/PatternCG.cpp6
-rw-r--r--WebCore/platform/graphics/cg/TransformationMatrixCG.cpp (renamed from WebCore/platform/graphics/cg/AffineTransformCG.cpp)68
-rw-r--r--WebCore/platform/graphics/chromium/ColorChromium.cpp62
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp602
-rw-r--r--WebCore/platform/graphics/chromium/FontCacheLinux.cpp179
-rw-r--r--WebCore/platform/graphics/chromium/FontChromiumWin.cpp327
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp232
-rw-r--r--WebCore/platform/graphics/chromium/FontCustomPlatformData.h70
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp111
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformData.h40
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp156
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h129
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp139
-rw-r--r--WebCore/platform/graphics/chromium/FontPlatformDataLinux.h112
-rw-r--r--WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp352
-rw-r--r--WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h96
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp248
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp72
-rw-r--r--WebCore/platform/graphics/chromium/IconChromiumLinux.cpp66
-rw-r--r--WebCore/platform/graphics/chromium/IconChromiumMac.cpp60
-rw-r--r--WebCore/platform/graphics/chromium/IconChromiumWin.cpp87
-rw-r--r--WebCore/platform/graphics/chromium/ImageBufferData.h50
-rw-r--r--WebCore/platform/graphics/chromium/ImageChromiumMac.mm58
-rw-r--r--WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h101
-rw-r--r--WebCore/platform/graphics/chromium/PlatformIcon.h42
-rw-r--r--WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp171
-rw-r--r--WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp162
-rw-r--r--WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp104
-rw-r--r--WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h98
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelper.cpp902
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelper.h400
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp138
-rw-r--r--WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h96
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp1
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp15
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.h1
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm20
-rw-r--r--WebCore/platform/graphics/mac/CoreTextController.cpp6
-rw-r--r--WebCore/platform/graphics/mac/FontCacheMac.mm13
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.cpp2
-rw-r--r--WebCore/platform/graphics/mac/FontMacATSUI.mm5
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformDataMac.mm4
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm54
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm31
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm11
-rw-r--r--WebCore/platform/graphics/qt/FontCacheQt.cpp22
-rw-r--r--WebCore/platform/graphics/qt/FontCustomPlatformData.cpp19
-rw-r--r--WebCore/platform/graphics/qt/FontCustomPlatformData.h3
-rw-r--r--WebCore/platform/graphics/qt/FontFallbackListQt.cpp106
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformData.h22
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformDataQt.cpp78
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp550
-rw-r--r--WebCore/platform/graphics/qt/FontQt43.cpp356
-rw-r--r--WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp7
-rw-r--r--WebCore/platform/graphics/qt/GradientQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp106
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp30
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.h19
-rw-r--r--WebCore/platform/graphics/qt/ImageQt.cpp16
-rw-r--r--WebCore/platform/graphics/qt/ImageSourceQt.cpp45
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp62
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h11
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp54
-rw-r--r--WebCore/platform/graphics/qt/PatternQt.cpp4
-rw-r--r--WebCore/platform/graphics/qt/SimpleFontDataQt.cpp35
-rw-r--r--WebCore/platform/graphics/qt/StillImageQt.h2
-rw-r--r--WebCore/platform/graphics/qt/TransformationMatrixQt.cpp (renamed from WebCore/platform/graphics/qt/AffineTransformQt.cpp)66
-rw-r--r--WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h86
-rw-r--r--WebCore/platform/graphics/skia/FloatPointSkia.cpp51
-rw-r--r--WebCore/platform/graphics/skia/FloatRectSkia.cpp50
-rw-r--r--WebCore/platform/graphics/skia/GradientSkia.cpp164
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h55
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextSkia.cpp1122
-rw-r--r--WebCore/platform/graphics/skia/ImageBufferSkia.cpp210
-rw-r--r--WebCore/platform/graphics/skia/ImageSkia.cpp462
-rw-r--r--WebCore/platform/graphics/skia/ImageSourceSkia.cpp247
-rw-r--r--WebCore/platform/graphics/skia/ImageSourceSkia.h60
-rw-r--r--WebCore/platform/graphics/skia/IntPointSkia.cpp56
-rw-r--r--WebCore/platform/graphics/skia/IntRectSkia.cpp57
-rw-r--r--WebCore/platform/graphics/skia/NativeImageSkia.cpp109
-rw-r--r--WebCore/platform/graphics/skia/NativeImageSkia.h104
-rw-r--r--WebCore/platform/graphics/skia/PathSkia.cpp316
-rw-r--r--WebCore/platform/graphics/skia/PatternSkia.cpp77
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp427
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h173
-rw-r--r--WebCore/platform/graphics/skia/PlatformGraphics.h37
-rw-r--r--WebCore/platform/graphics/skia/SkiaFontWin.cpp218
-rw-r--r--WebCore/platform/graphics/skia/SkiaFontWin.h54
-rw-r--r--WebCore/platform/graphics/skia/SkiaUtils.cpp199
-rw-r--r--WebCore/platform/graphics/skia/SkiaUtils.h82
-rw-r--r--WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp222
-rw-r--r--WebCore/platform/graphics/transforms/IdentityTransformOperation.h67
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp50
-rw-r--r--WebCore/platform/graphics/transforms/MatrixTransformOperation.h82
-rw-r--r--WebCore/platform/graphics/transforms/RotateTransformOperation.cpp40
-rw-r--r--WebCore/platform/graphics/transforms/RotateTransformOperation.h74
-rw-r--r--WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp41
-rw-r--r--WebCore/platform/graphics/transforms/ScaleTransformOperation.h74
-rw-r--r--WebCore/platform/graphics/transforms/SkewTransformOperation.cpp41
-rw-r--r--WebCore/platform/graphics/transforms/SkewTransformOperation.h74
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperation.h64
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperations.cpp49
-rw-r--r--WebCore/platform/graphics/transforms/TransformOperations.h59
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.cpp (renamed from WebCore/platform/graphics/AffineTransform.cpp)51
-rw-r--r--WebCore/platform/graphics/transforms/TransformationMatrix.h (renamed from WebCore/platform/graphics/AffineTransform.h)82
-rw-r--r--WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp41
-rw-r--r--WebCore/platform/graphics/transforms/TranslateTransformOperation.h75
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp24
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp10
-rw-r--r--WebCore/platform/graphics/win/FontPlatformData.h1
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp8
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp18
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp4
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp2
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp7
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp10
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.h4
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataWin.cpp4
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformData.h4
-rw-r--r--WebCore/platform/graphics/wx/GraphicsContextWx.cpp18
-rw-r--r--WebCore/platform/graphics/wx/ImageSourceWx.cpp24
-rw-r--r--WebCore/platform/graphics/wx/ImageWx.cpp60
-rw-r--r--WebCore/platform/graphics/wx/PathWx.cpp113
-rw-r--r--WebCore/platform/graphics/wx/TransformationMatrixWx.cpp (renamed from WebCore/platform/graphics/wx/AffineTransformWx.cpp)126
190 files changed, 14195 insertions, 2024 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 4b21de0..45b32ab 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -30,22 +30,18 @@
#include "FloatRect.h"
#include "ImageObserver.h"
#include "IntRect.h"
+#include "MIMETypeRegistry.h"
#include "PlatformString.h"
-#include "SystemTime.h"
#include "Timer.h"
+#include <wtf/CurrentTime.h>
#include <wtf/Vector.h>
-#include "MIMETypeRegistry.h"
namespace WebCore {
-// Animated images >5MB are considered large enough that we'll only hang on to
-// one frame at a time.
-const unsigned cLargeAnimationCutoff = 5242880;
-
-// When an animated image is more than five minutes out of date, don't try to
-// resync on repaint, so we don't waste CPU cycles on an edge case the user
-// doesn't care about.
-const double cAnimationResyncCutoff = 5 * 60;
+static int frameBytes(const IntSize& frameSize)
+{
+ return frameSize.width() * frameSize.height() * 4;
+}
BitmapImage::BitmapImage(ImageObserver* observer)
: Image(observer)
@@ -75,40 +71,42 @@ BitmapImage::~BitmapImage()
stopAnimation();
}
-void BitmapImage::destroyDecodedData(bool incremental, bool preserveNearbyFrames)
+void BitmapImage::destroyDecodedData(bool destroyAll)
{
- // Destroy the cached images and release them.
- if (m_frames.size()) {
- int sizeChange = 0;
- int frameSize = m_size.width() * m_size.height() * 4;
- const size_t nextFrame = (preserveNearbyFrames && frameCount()) ? ((m_currentFrame + 1) % frameCount()) : 0;
- for (unsigned i = incremental ? m_frames.size() - 1 : 0; i < m_frames.size(); i++) {
- if (m_frames[i].m_frame && (!preserveNearbyFrames || (i != m_currentFrame && i != nextFrame))) {
- sizeChange -= frameSize;
- m_frames[i].clear();
- }
- }
-
- // We just always invalidate our platform data, even in the incremental case.
- // This could be better, but it's not a big deal.
- m_isSolidColor = false;
- invalidatePlatformData();
-
- if (sizeChange) {
- m_decodedSize += sizeChange;
- if (imageObserver())
- imageObserver()->decodedSizeChanged(this, sizeChange);
- }
-
- if (!incremental) {
- // Reset the image source, since Image I/O has an underlying cache that it uses
- // while animating that it seems to never clear.
-#if !PLATFORM(SGL)
- m_source.clear();
- m_source.setData(m_data.get(), m_allDataReceived);
-#endif
- }
+ int framesCleared = 0;
+ const size_t clearBeforeFrame = destroyAll ? m_frames.size() : m_currentFrame;
+ for (size_t i = 0; i < clearBeforeFrame; ++i) {
+ // The underlying frame isn't actually changing (we're just trying to
+ // save the memory for the framebuffer data), so we don't need to clear
+ // the metadata.
+ if (m_frames[i].clear(false))
+ ++framesCleared;
}
+
+ destroyMetadataAndNotify(framesCleared);
+
+ m_source.clear(destroyAll, clearBeforeFrame, m_data.get(), m_allDataReceived);
+ return;
+}
+
+void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll)
+{
+ // Animated images >5MB are considered large enough that we'll only hang on
+ // to one frame at a time.
+ static const unsigned cLargeAnimationCutoff = 5242880;
+ if (frameCount() * frameBytes(m_size) > cLargeAnimationCutoff)
+ destroyDecodedData(destroyAll);
+}
+
+void BitmapImage::destroyMetadataAndNotify(int framesCleared)
+{
+ m_isSolidColor = false;
+ invalidatePlatformData();
+
+ const int deltaBytes = framesCleared * -frameBytes(m_size);
+ m_decodedSize += deltaBytes;
+ if (deltaBytes && imageObserver())
+ imageObserver()->decodedSizeChanged(this, deltaBytes);
}
void BitmapImage::cacheFrame(size_t index)
@@ -129,19 +127,14 @@ void BitmapImage::cacheFrame(size_t index)
m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
- int sizeChange;
- if (index) {
- IntSize frameSize = m_source.frameSizeAtIndex(index);
- if (frameSize != m_size)
- m_hasUniformFrameSize = false;
- sizeChange = m_frames[index].m_frame ? frameSize.width() * frameSize.height() * 4 : 0;
- } else
- sizeChange = m_frames[index].m_frame ? m_size.width() * m_size.height() * 4 : 0;
-
- if (sizeChange) {
- m_decodedSize += sizeChange;
+ const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size);
+ if (frameSize != m_size)
+ m_hasUniformFrameSize = false;
+ if (m_frames[index].m_frame) {
+ const int deltaBytes = frameBytes(frameSize);
+ m_decodedSize += deltaBytes;
if (imageObserver())
- imageObserver()->decodedSizeChanged(this, sizeChange);
+ imageObserver()->decodedSizeChanged(this, deltaBytes);
}
}
@@ -163,7 +156,9 @@ IntSize BitmapImage::currentFrameSize() const
bool BitmapImage::dataChanged(bool allDataReceived)
{
- destroyDecodedData(true);
+ // Because we're modifying the current frame, clear its (now possibly
+ // inaccurate) metadata as well.
+ destroyMetadataAndNotify((!m_frames.isEmpty() && m_frames[m_frames.size() - 1].clear(true)) ? 1 : 0);
// Feed all the data we've seen so far to the image decoder.
m_allDataReceived = allDataReceived;
@@ -179,6 +174,11 @@ bool BitmapImage::dataChanged(bool allDataReceived)
return isSizeAvailable();
}
+String BitmapImage::filenameExtension() const
+{
+ return m_source.filenameExtension();
+}
+
size_t BitmapImage::frameCount()
{
if (!m_haveFrameCount) {
@@ -274,16 +274,18 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary)
m_desiredFrameStartTime = time + currentDuration;
} else {
m_desiredFrameStartTime += currentDuration;
- // If we're too far behind, the user probably doesn't care about
- // resyncing and we could burn a lot of time looping through frames
- // below. Just reset the timings.
+
+ // When an animated image is more than five minutes out of date, the
+ // user probably doesn't care about resyncing and we could burn a lot of
+ // time looping through frames below. Just reset the timings.
+ const double cAnimationResyncCutoff = 5 * 60;
if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff)
m_desiredFrameStartTime = time + currentDuration;
}
// Don't advance the animation to an incomplete frame.
size_t nextFrame = (m_currentFrame + 1) % frameCount();
- if (!frameIsCompleteAtIndex(nextFrame))
+ if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
return;
// Don't advance past the last frame if we haven't decoded the whole image
@@ -369,14 +371,12 @@ void BitmapImage::resetAnimation()
m_repetitionsComplete = 0;
m_desiredFrameStartTime = 0;
m_animationFinished = false;
- int frameSize = m_size.width() * m_size.height() * 4;
-
+
// For extremely large animations, when the animation is reset, we just throw everything away.
- if (frameCount() * frameSize > cLargeAnimationCutoff)
- destroyDecodedData();
+ destroyDecodedDataIfNecessary(true);
}
-void BitmapImage::advanceAnimation(Timer<BitmapImage>* timer)
+void BitmapImage::advanceAnimation(Timer<BitmapImage>*)
{
internalAdvanceAnimation(false);
// At this point the image region has been marked dirty, and if it's
@@ -394,45 +394,32 @@ bool BitmapImage::internalAdvanceAnimation(bool skippingFrames)
if (!skippingFrames && imageObserver()->shouldPauseAnimation(this))
return false;
- m_currentFrame++;
+ ++m_currentFrame;
+ bool advancedAnimation = true;
+ bool destroyAll = false;
if (m_currentFrame >= frameCount()) {
++m_repetitionsComplete;
+
// Get the repetition count again. If we weren't able to get a
// repetition count before, we should have decoded the whole image by
// now, so it should now be available.
if (repetitionCount(true) && m_repetitionsComplete >= m_repetitionCount) {
m_animationFinished = true;
m_desiredFrameStartTime = 0;
- m_currentFrame--;
- if (skippingFrames) {
- // Uh oh. We tried to skip past the end of the animation. We'd
- // better draw this last frame.
- notifyObserverAndTrimDecodedData();
- }
- return false;
+ --m_currentFrame;
+ advancedAnimation = false;
+ } else {
+ m_currentFrame = 0;
+ destroyAll = true;
}
- m_currentFrame = 0;
}
+ destroyDecodedDataIfNecessary(destroyAll);
- if (!skippingFrames)
- notifyObserverAndTrimDecodedData();
-
- return true;
-}
-
-void BitmapImage::notifyObserverAndTrimDecodedData()
-{
- // Notify our observer that the animation has advanced.
- imageObserver()->animationAdvanced(this);
-
- // For large animated images, go ahead and throw away frames as we go to
- // save footprint.
- int frameSize = m_size.width() * m_size.height() * 4;
- if (frameCount() * frameSize > cLargeAnimationCutoff) {
- // Destroy all of our frames and just redecode every time. We save the
- // current frame since we'll need it in draw() anyway.
- destroyDecodedData(false, true);
- }
+ // We need to draw this frame if we advanced to it while not skipping, or if
+ // while trying to skip frames we hit the last frame and thus had to stop.
+ if (skippingFrames != advancedAnimation)
+ imageObserver()->animationAdvanced(this);
+ return advancedAnimation;
}
}
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
index c5f2a72..110aec4 100644
--- a/WebCore/platform/graphics/BitmapImage.h
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -80,10 +80,12 @@ struct FrameData : Noncopyable {
~FrameData()
{
- clear();
+ clear(true);
}
- void clear();
+ // Clear the cached image data on the frame, and (optionally) the metadata.
+ // Returns whether there was cached image data to clear.
+ bool clear(bool clearMetadata);
NativeImagePtr m_frame;
bool m_haveMetadata;
@@ -118,6 +120,7 @@ public:
IntSize currentFrameSize() const;
virtual bool dataChanged(bool allDataReceived);
+ virtual String filenameExtension() const;
// It may look unusual that there is no start animation call as public API. This is because
// we start and stop animating lazily. Animation begins whenever someone draws the image. It will
@@ -164,7 +167,7 @@ protected:
#endif
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
#if PLATFORM(QT) || PLATFORM(WX)
- virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
#endif
size_t currentFrame() const { return m_currentFrame; }
@@ -177,18 +180,22 @@ protected:
// Decodes and caches a frame. Never accessed except internally.
void cacheFrame(size_t index);
- // Called to invalidate all our cached data. If an image is loading
- // incrementally, we only invalidate the last cached frame. For large
- // animated images, where we throw away the decoded data after every frame,
- // |preserveNearbyFrames| can be set to preserve the current frame's data
- // and eliminate some unnecessary duplicated decoding work. This also
- // preserves the next frame's data, if available. In most cases this has no
- // effect; either that frame isn't decoded yet, or it's already been
- // destroyed by a previous call. But when we fall behind on the very first
- // animation loop and startAnimation() needs to "catch up" one or more
- // frames, this briefly preserves some of that decoding work, to ease CPU
- // load and make it less likely that we'll keep falling behind.
- virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false);
+ // Called to invalidate cached data. When |destroyAll| is true, we wipe out
+ // the entire frame buffer cache and tell the image source to destroy
+ // everything; this is used when e.g. we want to free some room in the image
+ // cache. If |destroyAll| is false, we only delete frames up to the current
+ // one; this is used while animating large images to keep memory footprint
+ // low without redecoding the whole image on every frame.
+ virtual void destroyDecodedData(bool destroyAll = true);
+
+ // If the image is large enough, calls destroyDecodedData() and passes
+ // |destroyAll| along.
+ void destroyDecodedDataIfNecessary(bool destroyAll);
+
+ // Generally called by destroyDecodedData(), destroys whole-image metadata
+ // and notifies observers that the memory footprint has (hopefully)
+ // decreased by |framesCleared| times the size (in bytes) of a frame.
+ void destroyMetadataAndNotify(int framesCleared);
// Whether or not size is available yet.
bool isSizeAvailable();
@@ -206,9 +213,6 @@ protected:
// Returns whether the animation was advanced.
bool internalAdvanceAnimation(bool skippingFrames);
- // Helper for internalAdvanceAnimation().
- void notifyObserverAndTrimDecodedData();
-
// Handle platform-specific data
void initPlatformData();
void invalidatePlatformData();
diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp
index 3ff589d..c7e11ee 100644
--- a/WebCore/platform/graphics/Color.cpp
+++ b/WebCore/platform/graphics/Color.cpp
@@ -38,8 +38,17 @@ using namespace WTF;
namespace WebCore {
-const RGBA32 lightenedBlack = 0xFF545454;
-const RGBA32 darkenedWhite = 0xFFABABAB;
+#if !COMPILER(MSVC)
+const RGBA32 Color::black;
+const RGBA32 Color::white;
+const RGBA32 Color::darkGray;
+const RGBA32 Color::gray;
+const RGBA32 Color::lightGray;
+const RGBA32 Color::transparent;
+#endif
+
+static const RGBA32 lightenedBlack = 0xFF545454;
+static const RGBA32 darkenedWhite = 0xFFABABAB;
RGBA32 makeRGB(int r, int g, int b)
{
@@ -51,7 +60,7 @@ RGBA32 makeRGBA(int r, int g, int b, int a)
return max(0, min(a, 255)) << 24 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
}
-int colorFloatToRGBAByte(float f)
+static int colorFloatToRGBAByte(float f)
{
// We use lroundf and 255 instead of nextafterf(256, 0) to match CG's rounding
return max(0, min(static_cast<int>(lroundf(255.0f * f)), 255));
diff --git a/WebCore/platform/graphics/FloatPoint.cpp b/WebCore/platform/graphics/FloatPoint.cpp
index 3ca0361..564ea86 100644
--- a/WebCore/platform/graphics/FloatPoint.cpp
+++ b/WebCore/platform/graphics/FloatPoint.cpp
@@ -27,7 +27,7 @@
#include "config.h"
#include "FloatPoint.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatConversion.h"
#include "IntPoint.h"
@@ -37,7 +37,7 @@ FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y())
{
}
-FloatPoint FloatPoint::matrixTransform(const AffineTransform& transform) const
+FloatPoint FloatPoint::matrixTransform(const TransformationMatrix& transform) const
{
double newX, newY;
transform.map(static_cast<double>(m_x), static_cast<double>(m_y), &newX, &newY);
diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h
index 6b3c769..35b3036 100644
--- a/WebCore/platform/graphics/FloatPoint.h
+++ b/WebCore/platform/graphics/FloatPoint.h
@@ -28,6 +28,8 @@
#define FloatPoint_h
#include "FloatSize.h"
+#include "IntPoint.h"
+#include <wtf/MathExtras.h>
#include <wtf/Platform.h>
#if PLATFORM(CG)
@@ -59,7 +61,7 @@ struct SkPoint;
namespace WebCore {
-class AffineTransform;
+class TransformationMatrix;
class IntPoint;
class FloatPoint {
@@ -102,7 +104,7 @@ public:
FloatPoint(const SkPoint&);
#endif
- FloatPoint matrixTransform(const AffineTransform&) const;
+ FloatPoint matrixTransform(const TransformationMatrix&) const;
private:
float m_x, m_y;
@@ -146,6 +148,11 @@ inline bool operator!=(const FloatPoint& a, const FloatPoint& b)
return a.x() != b.x() || a.y() != b.y();
}
+inline IntPoint roundedIntPoint(const FloatPoint& p)
+{
+ return IntPoint(static_cast<int>(roundf(p.x())), static_cast<int>(roundf(p.y())));
+}
+
}
#endif
diff --git a/WebCore/platform/graphics/FloatPoint3D.cpp b/WebCore/platform/graphics/FloatPoint3D.cpp
index ec52d40..e3ba422 100644
--- a/WebCore/platform/graphics/FloatPoint3D.cpp
+++ b/WebCore/platform/graphics/FloatPoint3D.cpp
@@ -23,14 +23,15 @@
#if ENABLE(SVG)
#include <math.h>
+#include "FloatPoint.h"
#include "FloatPoint3D.h"
namespace WebCore {
FloatPoint3D::FloatPoint3D()
- : m_x(0.f)
- , m_y(0.f)
- , m_z(0.f)
+ : m_x(0)
+ , m_y(0)
+ , m_z(0)
{
}
@@ -41,43 +42,22 @@ FloatPoint3D::FloatPoint3D(float x, float y, float z)
{
}
-float FloatPoint3D::x() const
+FloatPoint3D::FloatPoint3D(const FloatPoint& p)
+ : m_x(p.x())
+ , m_y(p.y())
+ , m_z(0)
{
- return m_x;
-}
-
-void FloatPoint3D::setX(float x)
-{
- m_x = x;
-}
-
-float FloatPoint3D::y() const
-{
- return m_y;
-}
-
-void FloatPoint3D::setY(float y)
-{
- m_y = y;
-}
-
-float FloatPoint3D::z() const
-{
- return m_z;
-}
-
-void FloatPoint3D::setZ(float z)
-{
- m_z = z;
}
void FloatPoint3D::normalize()
{
float length = sqrtf(m_x * m_x + m_y * m_y + m_z * m_z);
- m_x /= length;
- m_y /= length;
- m_z /= length;
+ if (length != 0) {
+ m_x /= length;
+ m_y /= length;
+ m_z /= length;
+ }
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h
index 55f70e7..184e914 100644
--- a/WebCore/platform/graphics/FloatPoint3D.h
+++ b/WebCore/platform/graphics/FloatPoint3D.h
@@ -26,19 +26,22 @@
namespace WebCore {
+class FloatPoint;
+
class FloatPoint3D {
public:
FloatPoint3D();
FloatPoint3D(float x, float y, float z);
+ FloatPoint3D(const FloatPoint&);
- float x() const;
- void setX(float x);
+ float x() const { return m_x; }
+ void setX(float x) { m_x = x; }
- float y() const;
- void setY(float y);
+ float y() const { return m_y; }
+ void setY(float y) { m_y = y; }
- float z() const;
- void setZ(float z);
+ float z() const { return m_z; }
+ void setZ(float z) { m_z = z; }
void normalize();
diff --git a/WebCore/platform/graphics/FloatQuad.cpp b/WebCore/platform/graphics/FloatQuad.cpp
new file mode 100644
index 0000000..a32d8ab
--- /dev/null
+++ b/WebCore/platform/graphics/FloatQuad.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 "FloatQuad.h"
+
+#include <algorithm>
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+static inline float min4(float a, float b, float c, float d)
+{
+ return min(min(a, b), min(c, d));
+}
+
+static inline float max4(float a, float b, float c, float d)
+{
+ return max(max(a, b), max(c, d));
+}
+
+FloatRect FloatQuad::boundingBox() const
+{
+ float left = min4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x());
+ float top = min4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y());
+
+ float right = max4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x());
+ float bottom = max4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y());
+
+ return FloatRect(left, top, right - left, bottom - top);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/FloatQuad.h b/WebCore/platform/graphics/FloatQuad.h
new file mode 100644
index 0000000..e05b27d
--- /dev/null
+++ b/WebCore/platform/graphics/FloatQuad.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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.
+ */
+
+#ifndef FloatQuad_h
+#define FloatQuad_h
+
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+
+namespace WebCore {
+
+// A FloatQuad is a collection of 4 points, often representing the result of
+// mapping a rectangle through transforms. When initialized from a rect, the
+// points are in clockwise order from top left.
+class FloatQuad {
+public:
+ FloatQuad()
+ {
+ }
+
+ FloatQuad(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3, const FloatPoint& p4)
+ : m_p1(p1)
+ , m_p2(p2)
+ , m_p3(p3)
+ , m_p4(p4)
+ {
+ }
+
+ FloatQuad(const FloatRect& inRect)
+ : m_p1(inRect.location())
+ , m_p2(inRect.right(), inRect.y())
+ , m_p3(inRect.right(), inRect.bottom())
+ , m_p4(inRect.x(), inRect.bottom())
+ {
+ }
+
+ FloatPoint p1() const { return m_p1; }
+ FloatPoint p2() const { return m_p2; }
+ FloatPoint p3() const { return m_p3; }
+ FloatPoint p4() const { return m_p4; }
+
+ void setP1(const FloatPoint& p) { m_p1 = p; }
+ void setP2(const FloatPoint& p) { m_p2 = p; }
+ void setP3(const FloatPoint& p) { m_p3 = p; }
+ void setP4(const FloatPoint& p) { m_p4 = p; }
+
+ // isEmpty tests that the bounding box is empty. This will not identify
+ // "slanted" empty quads.
+ bool isEmpty() const { return boundingBox().isEmpty(); }
+
+ FloatRect boundingBox() const;
+ IntRect enclosingBoundingBox() const
+ {
+ return enclosingIntRect(boundingBox());
+ }
+
+ void move(const FloatSize& offset)
+ {
+ m_p1 += offset;
+ m_p2 += offset;
+ m_p3 += offset;
+ m_p4 += offset;
+ }
+
+ void move(float dx, float dy)
+ {
+ m_p1.move(dx, dy);
+ m_p2.move(dx, dy);
+ m_p3.move(dx, dy);
+ m_p4.move(dx, dy);
+ }
+
+private:
+ FloatPoint m_p1;
+ FloatPoint m_p2;
+ FloatPoint m_p3;
+ FloatPoint m_p4;
+};
+
+inline FloatQuad& operator+=(FloatQuad& a, const FloatSize& b)
+{
+ a.move(b);
+ return a;
+}
+
+inline FloatQuad& operator-=(FloatQuad& a, const FloatSize& b)
+{
+ a.move(-b.width(), -b.height());
+ return a;
+}
+
+inline bool operator==(const FloatQuad& a, const FloatQuad& b)
+{
+ return a.p1() == b.p1() &&
+ a.p2() == b.p2() &&
+ a.p3() == b.p3() &&
+ a.p4() == b.p4();
+}
+
+inline bool operator!=(const FloatQuad& a, const FloatQuad& b)
+{
+ return a.p1() != b.p1() ||
+ a.p2() != b.p2() ||
+ a.p3() != b.p3() ||
+ a.p4() != b.p4();
+}
+
+} // namespace WebCore
+
+
+#endif // FloatQuad_h
+
diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp
index ec7b3fa..532f719 100644
--- a/WebCore/platform/graphics/FloatRect.cpp
+++ b/WebCore/platform/graphics/FloatRect.cpp
@@ -119,4 +119,16 @@ IntRect enclosingIntRect(const FloatRect& rect)
return IntRect(l, t, r - l, b - t);
}
+FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect)
+{
+ if (srcRect.width() == 0 || srcRect.height() == 0)
+ return FloatRect();
+
+ float widthScale = destRect.width() / srcRect.width();
+ float heightScale = destRect.height() / srcRect.height();
+ return FloatRect(destRect.x() + (r.x() - srcRect.x()) * widthScale,
+ destRect.y() + (r.y() - srcRect.y()) * heightScale,
+ r.width() * widthScale, r.height() * heightScale);
+}
+
}
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
index 11e3791..a87c949 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -167,6 +167,7 @@ inline FloatRect unionRect(const FloatRect& a, const FloatRect& b)
return c;
}
+
inline bool operator==(const FloatRect& a, const FloatRect& b)
{
return a.location() == b.location() && a.size() == b.size();
@@ -179,6 +180,9 @@ inline bool operator!=(const FloatRect& a, const FloatRect& b)
IntRect enclosingIntRect(const FloatRect&);
+// Map rect r from srcRect to an equivalent rect in destRect.
+FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect);
+
}
#endif
diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h
index cf1e1c5..6e792b6 100644
--- a/WebCore/platform/graphics/FloatSize.h
+++ b/WebCore/platform/graphics/FloatSize.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2005 Nokia. All rights reserved.
+ * 2008 Eric Seidel <eric@webkit.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -67,6 +68,12 @@ public:
m_height > other.m_height ? m_height : other.m_height);
}
+ FloatSize shrunkTo(const FloatSize& other) const
+ {
+ return FloatSize(m_width < other.m_width ? m_width : other.m_width,
+ m_height < other.m_height ? m_height : other.m_height);
+ }
+
#if PLATFORM(CG)
explicit FloatSize(const CGSize&); // don't do this implicitly since it's lossy
operator CGSize() const;
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp
index 138e322..f8bec82 100644
--- a/WebCore/platform/graphics/Font.cpp
+++ b/WebCore/platform/graphics/Font.cpp
@@ -38,6 +38,7 @@ using namespace Unicode;
namespace WebCore {
+#if USE(FONT_FAST_PATH)
const uint8_t Font::gRoundingHackCharacterTable[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
@@ -50,6 +51,7 @@ const uint8_t Font::gRoundingHackCharacterTable[256] = {
};
Font::CodePath Font::s_codePath = Auto;
+#endif
// ============================================================================================
// Font Implementation (Cross-Platform Portion)
@@ -133,132 +135,6 @@ bool Font::operator==(const Font& other) const
&& (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
}
-const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const
-{
- bool useSmallCapsFont = forceSmallCaps;
- if (m_fontDescription.smallCaps()) {
- UChar32 upperC = Unicode::toUpper(c);
- if (upperC != c) {
- c = upperC;
- useSmallCapsFont = true;
- }
- }
-
- if (mirror)
- c = mirroredChar(c);
-
- unsigned pageNumber = (c / GlyphPage::size);
-
- GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero;
- if (!node) {
- node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
- if (pageNumber)
- m_pages.set(pageNumber, node);
- else
- m_pageZero = node;
- }
-
- GlyphPage* page;
- if (!useSmallCapsFont) {
- // Fastest loop, for the common case (not small caps).
- while (true) {
- page = node->page();
- if (page) {
- const GlyphData& data = page->glyphDataForCharacter(c);
- if (data.fontData)
- return data;
- if (node->isSystemFallback())
- break;
- }
-
- // Proceed with the fallback list.
- node = node->getChild(fontDataAt(node->level()), pageNumber);
- if (pageNumber)
- m_pages.set(pageNumber, node);
- else
- m_pageZero = node;
- }
- } else {
- while (true) {
- page = node->page();
- if (page) {
- const GlyphData& data = page->glyphDataForCharacter(c);
- if (data.fontData) {
- // The smallCapsFontData function should not normally return 0.
- // But if it does, we will just render the capital letter big.
- const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription);
- if (!smallCapsFontData)
- return data;
-
- GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
- const GlyphPage* smallCapsPage = smallCapsNode->page();
- if (smallCapsPage) {
- const GlyphData& data = smallCapsPage->glyphDataForCharacter(c);
- if (data.fontData)
- return data;
- }
-
- // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
- // a font has the lowercase character but the small caps font does not have its uppercase version.
- return smallCapsFontData->missingGlyphData();
- }
-
- if (node->isSystemFallback())
- break;
- }
-
- // Proceed with the fallback list.
- node = node->getChild(fontDataAt(node->level()), pageNumber);
- if (pageNumber)
- m_pages.set(pageNumber, node);
- else
- m_pageZero = node;
- }
- }
-
- ASSERT(page);
- ASSERT(node->isSystemFallback());
-
- // System fallback is character-dependent. When we get here, we
- // know that the character in question isn't in the system fallback
- // font's glyph page. Try to lazily create it here.
- UChar codeUnits[2];
- int codeUnitsLength;
- if (c <= 0xFFFF) {
- UChar c16 = c;
- if (Font::treatAsSpace(c16))
- codeUnits[0] = ' ';
- else if (Font::treatAsZeroWidthSpace(c16))
- codeUnits[0] = zeroWidthSpace;
- else
- codeUnits[0] = c16;
- codeUnitsLength = 1;
- } else {
- codeUnits[0] = U16_LEAD(c);
- codeUnits[1] = U16_TRAIL(c);
- codeUnitsLength = 2;
- }
- const SimpleFontData* characterFontData = FontCache::getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
- if (useSmallCapsFont)
- characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
- if (characterFontData) {
- // Got the fallback glyph and font.
- GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
- const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
- // Cache it so we don't have to do system fallback again next time.
- if (!useSmallCapsFont)
- page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
- 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.
- const GlyphData& data = primaryFont()->missingGlyphData();
- if (!useSmallCapsFont)
- page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
- return data;
-}
-
void Font::cachePrimaryFont() const
{
ASSERT(m_fontList);
@@ -293,184 +169,12 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const
m_pages.clear();
}
-int Font::width(const TextRun& run) const
-{
- return lroundf(floatWidth(run));
-}
-
-int Font::ascent() const
-{
- return primaryFont()->ascent();
-}
-
-int Font::descent() const
-{
- return primaryFont()->descent();
-}
-
-int Font::lineSpacing() const
-{
- return primaryFont()->lineSpacing();
-}
-
-int Font::lineGap() const
-{
- return primaryFont()->lineGap();
-}
-
-float Font::xHeight() const
-{
- return primaryFont()->xHeight();
-}
-
-unsigned Font::unitsPerEm() const
-{
- return primaryFont()->unitsPerEm();
-}
-
-int Font::spaceWidth() const
-{
- return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing);
-}
-
bool Font::isFixedPitch() const
{
ASSERT(m_fontList);
return m_fontList->isFixedPitch(this);
}
-void Font::setCodePath(CodePath p)
-{
- s_codePath = p;
-}
-
-Font::CodePath Font::codePath()
-{
- return s_codePath;
-}
-
-bool Font::canUseGlyphCache(const TextRun& run) const
-{
- switch (s_codePath) {
- case Auto:
- break;
- case Simple:
- return true;
- case Complex:
- return false;
- }
-
- // Start from 0 since drawing and highlighting also measure the characters before run->from
- for (int i = 0; i < run.length(); i++) {
- const UChar c = run[i];
- if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
- continue;
- if (c <= 0x36F)
- return false;
-
- if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
- continue;
- if (c <= 0x05CF)
- return false;
-
- if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
- continue;
- if (c <= 0x1059)
- return false;
-
- if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
- continue;
- if (c <= 0x11FF)
- return false;
-
- if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
- continue;
- if (c <= 0x18AF)
- return false;
-
- if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
- continue;
- if (c <= 0x194F)
- return false;
-
- if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
- continue;
- if (c <= 0x20FF)
- return false;
-
- if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
- continue;
- if (c <= 0xFE2F)
- return false;
- }
-
- return true;
-
-}
-
-void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
-{
- // This glyph buffer holds our glyphs+advances+font data for each glyph.
- GlyphBuffer glyphBuffer;
-
- float startX = point.x();
- WidthIterator it(this, run);
- it.advance(from);
- float beforeWidth = it.m_runWidthSoFar;
- it.advance(to, &glyphBuffer);
-
- // We couldn't generate any glyphs for the run. Give up.
- if (glyphBuffer.isEmpty())
- return;
-
- float afterWidth = it.m_runWidthSoFar;
-
- if (run.rtl()) {
- float finalRoundingWidth = it.m_finalRoundingWidth;
- it.advance(run.length());
- startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
- } else
- startX += beforeWidth;
-
- // Swap the order of the glyphs if right-to-left.
- if (run.rtl())
- for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
- glyphBuffer.swap(i, end);
-
- // Calculate the starting point of the glyphs to be displayed by adding
- // all the advances up to the first glyph.
- FloatPoint startPoint(startX, point.y());
- drawGlyphBuffer(context, glyphBuffer, run, startPoint);
-}
-
-void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer,
- const TextRun& run, const FloatPoint& point) const
-{
- // Draw each contiguous run of glyphs that use the same font data.
- const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
- FloatSize offset = glyphBuffer.offsetAt(0);
- FloatPoint startPoint(point);
- float nextX = startPoint.x();
- int lastFrom = 0;
- int nextGlyph = 0;
- while (nextGlyph < glyphBuffer.size()) {
- const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
- FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
- if (nextFontData != fontData || nextOffset != offset) {
- drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
-
- lastFrom = nextGlyph;
- fontData = nextFontData;
- offset = nextOffset;
- startPoint.setX(nextX);
- }
- nextX += glyphBuffer.advanceAt(nextGlyph);
- nextGlyph++;
- }
-
- drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
-}
-
void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
// Don't draw anything while we are using custom fonts that are in the process of loading.
@@ -486,10 +190,12 @@ void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi
}
#endif
+#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
- drawSimpleText(context, run, point, from, to);
- else
- drawComplexText(context, run, point, from, to);
+ return drawSimpleText(context, run, point, from, to);
+#endif
+
+ return drawComplexText(context, run, point, from, to);
}
float Font::floatWidth(const TextRun& run) const
@@ -499,8 +205,11 @@ float Font::floatWidth(const TextRun& run) const
return floatWidthUsingSVGFont(run);
#endif
+#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
return floatWidthForSimpleText(run, 0);
+#endif
+
return floatWidthForComplexText(run);
}
@@ -513,16 +222,13 @@ float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsCo
charsConsumed = run.length();
glyphName = "";
+
+#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
return floatWidthForSimpleText(run, 0);
- return floatWidthForComplexText(run);
-}
+#endif
-float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const
-{
- WidthIterator it(this, run);
- it.advance(run.length(), glyphBuffer);
- return it.m_runWidthSoFar;
+ return floatWidthForComplexText(run);
}
FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
@@ -533,27 +239,13 @@ FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point,
#endif
to = (to == -1 ? run.length() : to);
+
+#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
return selectionRectForSimpleText(run, point, h, from, to);
- return selectionRectForComplexText(run, point, h, from, to);
-}
+#endif
-FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
-{
- WidthIterator it(this, run);
- it.advance(from);
- float beforeWidth = it.m_runWidthSoFar;
- it.advance(to);
- float afterWidth = it.m_runWidthSoFar;
-
- // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
- if (run.rtl()) {
- it.advance(run.length());
- float totalWidth = it.m_runWidthSoFar;
- return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
- } else {
- return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
- }
+ return selectionRectForComplexText(run, point, h, from, to);
}
int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const
@@ -563,52 +255,12 @@ int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs
return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
#endif
+#if USE(FONT_FAST_PATH)
if (canUseGlyphCache(run))
return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
- return offsetForPositionForComplexText(run, x, includePartialGlyphs);
-}
-
-int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
-{
- float delta = (float)x;
-
- WidthIterator it(this, run);
- GlyphBuffer localGlyphBuffer;
- unsigned offset;
- if (run.rtl()) {
- delta -= floatWidthForSimpleText(run, 0);
- while (1) {
- offset = it.m_currentCharacter;
- float w;
- if (!it.advanceOneCharacter(w, &localGlyphBuffer))
- break;
- delta += w;
- if (includePartialGlyphs) {
- if (delta - w / 2 >= 0)
- break;
- } else {
- if (delta >= 0)
- break;
- }
- }
- } else {
- while (1) {
- offset = it.m_currentCharacter;
- float w;
- if (!it.advanceOneCharacter(w, &localGlyphBuffer))
- break;
- delta -= w;
- if (includePartialGlyphs) {
- if (delta + w / 2 <= 0)
- break;
- } else {
- if (delta <= 0)
- break;
- }
- }
- }
+#endif
- return offset;
+ return offsetForPositionForComplexText(run, x, includePartialGlyphs);
}
#if ENABLE(SVG_FONTS)
diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h
index a99ce12..1bfee8f 100644
--- a/WebCore/platform/graphics/Font.h
+++ b/WebCore/platform/graphics/Font.h
@@ -3,6 +3,7 @@
* (C) 2000 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2003, 2006, 2007 Apple Computer, Inc.
+ * Copyright (C) 2008 Holger Hans Peter Freyther
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,11 +27,12 @@
#include "TextRun.h"
#include "FontDescription.h"
+#include "SimpleFontData.h"
#include <wtf/HashMap.h>
+#include <wtf/MathExtras.h>
#if PLATFORM(QT)
-#include <QtGui/qfont.h>
-#include <QtGui/qfontmetrics.h>
+#include <QFont>
#endif
namespace WebCore {
@@ -45,18 +47,18 @@ class GlyphBuffer;
class GlyphPageTreeNode;
class GraphicsContext;
class IntPoint;
-class SimpleFontData;
class SVGFontElement;
struct GlyphData;
+const unsigned defaultUnitsPerEm = 1000;
+
class Font {
public:
Font();
Font(const FontDescription&, short letterSpacing, short wordSpacing);
-#if !PLATFORM(QT)
- Font(const FontPlatformData&, bool isPrinting); // This constructor is only used if the platform wants to start with a native font.
-#endif
+ // This constructor is only used if the platform wants to start with a native font.
+ Font(const FontPlatformData&, bool isPrinting);
~Font();
Font(const Font&);
@@ -76,7 +78,7 @@ public:
void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const;
- int width(const TextRun&) const;
+ int width(const TextRun& run) const { return lroundf(floatWidth(run)); }
float floatWidth(const TextRun&) const;
float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const;
@@ -87,13 +89,8 @@ public:
short wordSpacing() const { return m_wordSpacing; }
short letterSpacing() const { return m_letterSpacing; }
-#if !PLATFORM(QT)
void setWordSpacing(short s) { m_wordSpacing = s; }
void setLetterSpacing(short s) { m_letterSpacing = s; }
-#else
- void setWordSpacing(short s);
- void setLetterSpacing(short s);
-#endif
bool isFixedPitch() const;
bool isPrinterFont() const { return m_fontDescription.usePrinterFont(); }
@@ -105,27 +102,19 @@ public:
bool italic() const { return m_fontDescription.italic(); }
FontWeight weight() const { return m_fontDescription.weight(); }
-#if !PLATFORM(QT)
bool isPlatformFont() const { return m_isPlatformFont; }
-#endif
-
-#if PLATFORM(QT)
- inline const QFont &font() const { return m_font; }
- inline const QFont &scFont() const { return m_scFont; }
-#endif
// Metrics that we query the FontFallbackList for.
- int ascent() const;
- int descent() const;
+ int ascent() const { return primaryFont()->ascent(); }
+ int descent() const { return primaryFont()->descent(); }
int height() const { return ascent() + descent(); }
- int lineSpacing() const;
- int lineGap() const;
- float xHeight() const;
- unsigned unitsPerEm() const;
- int spaceWidth() const;
+ int lineSpacing() const { return primaryFont()->lineSpacing(); }
+ int lineGap() const { return primaryFont()->lineGap(); }
+ float xHeight() const { return primaryFont()->xHeight(); }
+ unsigned unitsPerEm() const { return primaryFont()->unitsPerEm(); }
+ int spaceWidth() const { return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); }
int tabWidth() const { return 8 * spaceWidth(); }
-#if !PLATFORM(QT)
const SimpleFontData* primaryFont() const {
if (!m_cachedPrimaryFont)
cachePrimaryFont();
@@ -137,9 +126,11 @@ public:
// Used for complex text, and does not utilize the glyph map cache.
const FontData* fontDataForCharacters(const UChar*, int length) const;
+#if PLATFORM(QT)
+ QFont font() const;
+#endif
+
private:
- bool canUseGlyphCache(const TextRun&) const;
- void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
#if ENABLE(SVG_FONTS)
void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
float floatWidthUsingSVGFont(const TextRun&) const;
@@ -147,24 +138,28 @@ private:
FloatRect selectionRectForTextUsingSVGFont(const TextRun&, const IntPoint&, int h, int from, int to) const;
int offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const;
#endif
+
+#if USE(FONT_FAST_PATH)
+ bool canUseGlyphCache(const TextRun&) const;
+ void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const;
void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const TextRun&, const FloatPoint&) const;
- void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
float floatWidthForSimpleText(const TextRun&, GlyphBuffer*) const;
- float floatWidthForComplexText(const TextRun&) const;
int offsetForPositionForSimpleText(const TextRun&, int position, bool includePartialGlyphs) const;
- int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const;
FloatRect selectionRectForSimpleText(const TextRun&, const IntPoint&, int h, int from, int to) const;
+#endif
+
+ void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const;
+ float floatWidthForComplexText(const TextRun&) 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;
-#endif
+
friend struct WidthIterator;
public:
-#if PLATFORM(QT)
- FontSelector* fontSelector() const { return 0; }
-#else
// Useful for debugging the different font rendering code paths.
+#if USE(FONT_FAST_PATH)
enum CodePath { Auto, Simple, Complex };
static void setCodePath(CodePath);
static CodePath codePath();
@@ -175,9 +170,9 @@ public:
{
return (((c & ~0xFF) == 0 && gRoundingHackCharacterTable[c]));
}
+#endif
FontSelector* fontSelector() const;
-#endif
static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; }
static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == 0x200e || c == 0x200f || (c >= 0x202a && c <= 0x202e) || c == 0xFFFC; }
@@ -188,21 +183,13 @@ public:
private:
FontDescription m_fontDescription;
-#if !PLATFORM(QT)
mutable RefPtr<FontFallbackList> m_fontList;
mutable HashMap<int, GlyphPageTreeNode*> m_pages;
mutable GlyphPageTreeNode* m_pageZero;
mutable const SimpleFontData* m_cachedPrimaryFont;
-#endif
short m_letterSpacing;
short m_wordSpacing;
-#if !PLATFORM(QT)
bool m_isPlatformFont;
-#else
- QFont m_font;
- QFont m_scFont;
- int m_spaceWidth;
-#endif
};
}
diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp
index 1c5a987..2d219be 100644
--- a/WebCore/platform/graphics/FontCache.cpp
+++ b/WebCore/platform/graphics/FontCache.cpp
@@ -37,11 +37,22 @@
#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/ListHashSet.h>
+#include <wtf/StdLibExtras.h>
using namespace WTF;
namespace WebCore {
+FontCache* fontCache()
+{
+ DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ());
+ return &globalFontCache;
+}
+
+FontCache::FontCache()
+{
+}
+
struct FontPlatformDataCacheKey {
FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false,
bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode)
@@ -104,7 +115,7 @@ struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataC
static const bool emptyValueIsZero = true;
static const FontPlatformDataCacheKey& emptyValue()
{
- static FontPlatformDataCacheKey key(nullAtom);
+ DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (nullAtom));
return key;
}
static void constructDeletedValue(FontPlatformDataCacheKey& slot)
@@ -124,21 +135,24 @@ static FontPlatformDataCache* gFontPlatformDataCache = 0;
static const AtomicString& alternateFamilyName(const AtomicString& familyName)
{
// Alias Courier <-> Courier New
- static AtomicString courier("Courier"), courierNew("Courier New");
+ DEFINE_STATIC_LOCAL(AtomicString, courier, ("Courier"));
+ DEFINE_STATIC_LOCAL(AtomicString, courierNew, ("Courier New"));
if (equalIgnoringCase(familyName, courier))
return courierNew;
if (equalIgnoringCase(familyName, courierNew))
return courier;
// Alias Times and Times New Roman.
- static AtomicString times("Times"), timesNewRoman("Times New Roman");
+ DEFINE_STATIC_LOCAL(AtomicString, times, ("Times"));
+ DEFINE_STATIC_LOCAL(AtomicString, timesNewRoman, ("Times New Roman"));
if (equalIgnoringCase(familyName, times))
return timesNewRoman;
if (equalIgnoringCase(familyName, timesNewRoman))
return times;
// Alias Arial and Helvetica
- static AtomicString arial("Arial"), helvetica("Helvetica");
+ DEFINE_STATIC_LOCAL(AtomicString, arial, ("Arial"));
+ DEFINE_STATIC_LOCAL(AtomicString, helvetica, ("Helvetica"));
if (equalIgnoringCase(familyName, arial))
return helvetica;
if (equalIgnoringCase(familyName, helvetica))
@@ -202,7 +216,7 @@ struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
static const bool needsDestruction = true;
static const FontPlatformData& emptyValue()
{
- static FontPlatformData key;
+ DEFINE_STATIC_LOCAL(FontPlatformData, key, ());
return key;
}
static void constructDeletedValue(FontPlatformData& slot)
diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h
index 816fe64..8820045 100644
--- a/WebCore/platform/graphics/FontCache.h
+++ b/WebCore/platform/graphics/FontCache.h
@@ -51,45 +51,51 @@ class SimpleFontData;
class FontCache {
public:
- static const FontData* getFontData(const Font&, int& familyIndex, FontSelector*);
- static void releaseFontData(const SimpleFontData*);
+ friend FontCache* fontCache();
+
+ const FontData* getFontData(const Font&, int& familyIndex, FontSelector*);
+ void releaseFontData(const SimpleFontData*);
// This method is implemented by the platform.
// FIXME: Font data returned by this method never go inactive because callers don't track and release them.
- static const SimpleFontData* getFontDataForCharacters(const Font&, const UChar* characters, int length);
+ const SimpleFontData* getFontDataForCharacters(const Font&, const UChar* characters, int length);
// Also implemented by the platform.
- static void platformInit();
+ void platformInit();
#if PLATFORM(WIN)
- static IMLangFontLink2* getFontLinkInterface();
+ IMLangFontLink2* getFontLinkInterface();
#endif
- static void getTraitsInFamily(const AtomicString&, Vector<unsigned>&);
+ void getTraitsInFamily(const AtomicString&, Vector<unsigned>&);
- static FontPlatformData* getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName = false);
- static SimpleFontData* getCachedFontData(const FontPlatformData*);
- static FontPlatformData* getLastResortFallbackFont(const FontDescription&);
+ FontPlatformData* getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName = false);
+ SimpleFontData* getCachedFontData(const FontPlatformData*);
+ FontPlatformData* getLastResortFallbackFont(const FontDescription&);
- static void addClient(FontSelector*);
- static void removeClient(FontSelector*);
+ void addClient(FontSelector*);
+ void removeClient(FontSelector*);
- static unsigned generation();
- static void invalidate();
+ unsigned generation();
+ void invalidate();
- static size_t fontDataCount();
- static size_t inactiveFontDataCount();
- static void purgeInactiveFontData(int count = INT_MAX);
+ size_t fontDataCount();
+ size_t inactiveFontDataCount();
+ void purgeInactiveFontData(int count = INT_MAX);
private:
+ FontCache();
+
// These methods are implemented by each platform.
- static FontPlatformData* getSimilarFontPlatformData(const Font&);
- static FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family);
+ FontPlatformData* getSimilarFontPlatformData(const Font&);
+ FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family);
friend class SimpleFontData;
friend class FontFallbackList;
};
+// Get the global fontCache.
+FontCache* fontCache();
}
#endif
diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp
index ef59c2f..06d52d7 100644
--- a/WebCore/platform/graphics/FontFallbackList.cpp
+++ b/WebCore/platform/graphics/FontFallbackList.cpp
@@ -40,7 +40,7 @@ FontFallbackList::FontFallbackList()
, m_pitch(UnknownPitch)
, m_loadingCustomFonts(false)
, m_fontSelector(0)
- , m_generation(FontCache::generation())
+ , m_generation(fontCache()->generation())
{
}
@@ -52,7 +52,7 @@ void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector)
m_pitch = UnknownPitch;
m_loadingCustomFonts = false;
m_fontSelector = fontSelector;
- m_generation = FontCache::generation();
+ m_generation = fontCache()->generation();
}
void FontFallbackList::releaseFontData()
@@ -61,7 +61,7 @@ void FontFallbackList::releaseFontData()
for (unsigned i = 0; i < numFonts; ++i) {
if (!m_fontList[i].second) {
ASSERT(!m_fontList[i].first->isSegmented());
- FontCache::releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first));
+ fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first));
}
}
}
@@ -96,8 +96,8 @@ const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realized
// We are obtaining this font for the first time. We keep track of the families we've looked at before
// in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our
// |m_familyIndex| as it scans for the right font to make.
- ASSERT(FontCache::generation() == m_generation);
- const FontData* result = FontCache::getFontData(*font, m_familyIndex, m_fontSelector.get());
+ ASSERT(fontCache()->generation() == m_generation);
+ const FontData* result = fontCache()->getFontData(*font, m_familyIndex, m_fontSelector.get());
if (result) {
m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont()));
if (result->isLoading())
@@ -116,8 +116,8 @@ const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const
fontData = fontDataAt(font, ++realizedFontIndex);
if (!fontData) {
- ASSERT(FontCache::generation() == m_generation);
- fontData = FontCache::getFontDataForCharacters(*font, characters, length);
+ ASSERT(fontCache()->generation() == m_generation);
+ fontData = fontCache()->getFontDataForCharacters(*font, characters, length);
}
return fontData;
@@ -126,8 +126,8 @@ const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const
void FontFallbackList::setPlatformFont(const FontPlatformData& platformData)
{
m_familyIndex = cAllFamiliesScanned;
- ASSERT(FontCache::generation() == m_generation);
- const FontData* fontData = FontCache::getCachedFontData(&platformData);
+ ASSERT(fontCache()->generation() == m_generation);
+ const FontData* fontData = fontCache()->getCachedFontData(&platformData);
m_fontList.append(pair<const FontData*, bool>(fontData, fontData->isCustomFont()));
}
diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp
new file mode 100644
index 0000000..635aba9
--- /dev/null
+++ b/WebCore/platform/graphics/FontFastPath.cpp
@@ -0,0 +1,367 @@
+/**
+ * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * 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 "Font.h"
+
+#include "CharacterNames.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "GlyphBuffer.h"
+#include "GlyphPageTreeNode.h"
+#include "IntPoint.h"
+#include "SimpleFontData.h"
+#include "WidthIterator.h"
+
+#include <wtf/unicode/Unicode.h>
+#include <wtf/MathExtras.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const
+{
+ bool useSmallCapsFont = forceSmallCaps;
+ if (m_fontDescription.smallCaps()) {
+ UChar32 upperC = Unicode::toUpper(c);
+ if (upperC != c) {
+ c = upperC;
+ useSmallCapsFont = true;
+ }
+ }
+
+ if (mirror)
+ c = mirroredChar(c);
+
+ unsigned pageNumber = (c / GlyphPage::size);
+
+ GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero;
+ if (!node) {
+ node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
+ if (pageNumber)
+ m_pages.set(pageNumber, node);
+ else
+ m_pageZero = node;
+ }
+
+ GlyphPage* page;
+ if (!useSmallCapsFont) {
+ // Fastest loop, for the common case (not small caps).
+ while (true) {
+ page = node->page();
+ if (page) {
+ const GlyphData& data = page->glyphDataForCharacter(c);
+ if (data.fontData)
+ return data;
+ if (node->isSystemFallback())
+ break;
+ }
+
+ // Proceed with the fallback list.
+ node = node->getChild(fontDataAt(node->level()), pageNumber);
+ if (pageNumber)
+ m_pages.set(pageNumber, node);
+ else
+ m_pageZero = node;
+ }
+ } else {
+ while (true) {
+ page = node->page();
+ if (page) {
+ const GlyphData& data = page->glyphDataForCharacter(c);
+ if (data.fontData) {
+ // The smallCapsFontData function should not normally return 0.
+ // But if it does, we will just render the capital letter big.
+ const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription);
+ if (!smallCapsFontData)
+ return data;
+
+ GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
+ const GlyphPage* smallCapsPage = smallCapsNode->page();
+ if (smallCapsPage) {
+ const GlyphData& data = smallCapsPage->glyphDataForCharacter(c);
+ if (data.fontData)
+ return data;
+ }
+
+ // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
+ // a font has the lowercase character but the small caps font does not have its uppercase version.
+ return smallCapsFontData->missingGlyphData();
+ }
+
+ if (node->isSystemFallback())
+ break;
+ }
+
+ // Proceed with the fallback list.
+ node = node->getChild(fontDataAt(node->level()), pageNumber);
+ if (pageNumber)
+ m_pages.set(pageNumber, node);
+ else
+ m_pageZero = node;
+ }
+ }
+
+ ASSERT(page);
+ ASSERT(node->isSystemFallback());
+
+ // System fallback is character-dependent. When we get here, we
+ // know that the character in question isn't in the system fallback
+ // font's glyph page. Try to lazily create it here.
+ UChar codeUnits[2];
+ int codeUnitsLength;
+ if (c <= 0xFFFF) {
+ UChar c16 = c;
+ if (Font::treatAsSpace(c16))
+ codeUnits[0] = ' ';
+ else if (Font::treatAsZeroWidthSpace(c16))
+ codeUnits[0] = zeroWidthSpace;
+ else
+ codeUnits[0] = c16;
+ codeUnitsLength = 1;
+ } else {
+ codeUnits[0] = U16_LEAD(c);
+ codeUnits[1] = U16_TRAIL(c);
+ codeUnitsLength = 2;
+ }
+ const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
+ if (useSmallCapsFont && characterFontData)
+ characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
+ if (characterFontData) {
+ // Got the fallback glyph and font.
+ GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
+ const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
+ // Cache it so we don't have to do system fallback again next time.
+ if (!useSmallCapsFont)
+ page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+ 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.
+ const GlyphData& data = primaryFont()->missingGlyphData();
+ if (!useSmallCapsFont)
+ page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
+ return data;
+}
+
+void Font::setCodePath(CodePath p)
+{
+ s_codePath = p;
+}
+
+Font::CodePath Font::codePath()
+{
+ return s_codePath;
+}
+
+bool Font::canUseGlyphCache(const TextRun& run) const
+{
+ switch (s_codePath) {
+ case Auto:
+ break;
+ case Simple:
+ return true;
+ case Complex:
+ return false;
+ }
+
+ // Start from 0 since drawing and highlighting also measure the characters before run->from
+ for (int i = 0; i < run.length(); i++) {
+ const UChar c = run[i];
+ if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
+ continue;
+ if (c <= 0x36F)
+ return false;
+
+ if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
+ continue;
+ if (c <= 0x05CF)
+ return false;
+
+ if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
+ continue;
+ if (c <= 0x1059)
+ return false;
+
+ if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
+ continue;
+ if (c <= 0x11FF)
+ return false;
+
+ if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
+ continue;
+ if (c <= 0x18AF)
+ return false;
+
+ if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
+ continue;
+ if (c <= 0x194F)
+ return false;
+
+ if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
+ continue;
+ if (c <= 0x20FF)
+ return false;
+
+ if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
+ continue;
+ if (c <= 0xFE2F)
+ return false;
+ }
+
+ return true;
+
+}
+
+void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ // This glyph buffer holds our glyphs+advances+font data for each glyph.
+ GlyphBuffer glyphBuffer;
+
+ float startX = point.x();
+ WidthIterator it(this, run);
+ it.advance(from);
+ float beforeWidth = it.m_runWidthSoFar;
+ it.advance(to, &glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ float afterWidth = it.m_runWidthSoFar;
+
+ if (run.rtl()) {
+ float finalRoundingWidth = it.m_finalRoundingWidth;
+ it.advance(run.length());
+ startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
+ } else
+ startX += beforeWidth;
+
+ // Swap the order of the glyphs if right-to-left.
+ if (run.rtl())
+ for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
+ glyphBuffer.swap(i, end);
+
+ // Calculate the starting point of the glyphs to be displayed by adding
+ // all the advances up to the first glyph.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, run, startPoint);
+}
+
+void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const
+{
+ // Draw each contiguous run of glyphs that use the same font data.
+ const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
+ FloatSize offset = glyphBuffer.offsetAt(0);
+ FloatPoint startPoint(point);
+ float nextX = startPoint.x();
+ int lastFrom = 0;
+ int nextGlyph = 0;
+ while (nextGlyph < glyphBuffer.size()) {
+ const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
+ FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
+ if (nextFontData != fontData || nextOffset != offset) {
+ drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
+
+ lastFrom = nextGlyph;
+ fontData = nextFontData;
+ offset = nextOffset;
+ startPoint.setX(nextX);
+ }
+ nextX += glyphBuffer.advanceAt(nextGlyph);
+ nextGlyph++;
+ }
+
+ drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
+}
+
+float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const
+{
+ WidthIterator it(this, run);
+ it.advance(run.length(), glyphBuffer);
+ return it.m_runWidthSoFar;
+}
+
+FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
+{
+ WidthIterator it(this, run);
+ it.advance(from);
+ float beforeWidth = it.m_runWidthSoFar;
+ it.advance(to);
+ float afterWidth = it.m_runWidthSoFar;
+
+ // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
+ if (run.rtl()) {
+ it.advance(run.length());
+ float totalWidth = it.m_runWidthSoFar;
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+ } else {
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+ }
+}
+
+int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ float delta = (float)x;
+
+ WidthIterator it(this, run);
+ GlyphBuffer localGlyphBuffer;
+ unsigned offset;
+ if (run.rtl()) {
+ delta -= floatWidthForSimpleText(run, 0);
+ while (1) {
+ offset = it.m_currentCharacter;
+ float w;
+ if (!it.advanceOneCharacter(w, &localGlyphBuffer))
+ break;
+ delta += w;
+ if (includePartialGlyphs) {
+ if (delta - w / 2 >= 0)
+ break;
+ } else {
+ if (delta >= 0)
+ break;
+ }
+ }
+ } else {
+ while (1) {
+ offset = it.m_currentCharacter;
+ float w;
+ if (!it.advanceOneCharacter(w, &localGlyphBuffer))
+ break;
+ delta -= w;
+ if (includePartialGlyphs) {
+ if (delta + w / 2 <= 0)
+ break;
+ } else {
+ if (delta <= 0)
+ break;
+ }
+ }
+ }
+
+ return offset;
+}
+
+}
diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp
index 5e50959..15e27d7 100644
--- a/WebCore/platform/graphics/GeneratedImage.cpp
+++ b/WebCore/platform/graphics/GeneratedImage.cpp
@@ -47,7 +47,7 @@ void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, co
context->restore();
}
-void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect)
{
// Create a BitmapImage and call drawPattern on it.
diff --git a/WebCore/platform/graphics/GeneratedImage.h b/WebCore/platform/graphics/GeneratedImage.h
index fb0661b..dea0c54 100644
--- a/WebCore/platform/graphics/GeneratedImage.h
+++ b/WebCore/platform/graphics/GeneratedImage.h
@@ -53,15 +53,14 @@ public:
virtual IntSize size() const { return m_size; }
// Assume that generated content has no decoded data we need to worry about
- virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) { }
+ virtual void destroyDecodedData(bool /*destroyAll*/ = true) { }
virtual unsigned decodedSize() const { return 0; }
protected:
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
- virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
-protected:
GeneratedImage(PassRefPtr<Generator> generator, const IntSize& size)
: m_generator(generator)
, m_size(size)
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
index 18957d5..fdb306f 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006, 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
@@ -30,14 +30,16 @@
#define GlyphBuffer_h
#include "FloatSize.h"
+#include <wtf/UnusedParam.h>
+#include <wtf/Vector.h>
#if PLATFORM(CG)
#include <ApplicationServices/ApplicationServices.h>
-#elif PLATFORM(CAIRO)
-#include <cairo.h>
#endif
-#include <wtf/Vector.h>
+#if PLATFORM(CAIRO)
+#include <cairo.h>
+#endif
namespace WebCore {
@@ -125,6 +127,7 @@ public:
#if PLATFORM(WIN)
return m_offsets[index];
#else
+ UNUSED_PARAM(index);
return FloatSize();
#endif
}
@@ -132,6 +135,7 @@ public:
void add(Glyph glyph, const SimpleFontData* font, float width, const FloatSize* offset = 0)
{
m_fontData.append(font);
+
#if PLATFORM(CAIRO)
cairo_glyph_t cairoGlyph;
cairoGlyph.index = glyph;
@@ -152,6 +156,8 @@ public:
m_offsets.append(*offset);
else
m_offsets.append(FloatSize());
+#else
+ UNUSED_PARAM(offset);
#endif
}
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
index 9cd2969..8426011 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -109,17 +109,6 @@ void GraphicsContext::restore()
restorePlatformState();
}
-const Font& GraphicsContext::font() const
-{
- return m_common->state.font;
-}
-
-void GraphicsContext::setFont(const Font& aFont)
-{
- m_common->state.font = aFont;
- setPlatformFont(aFont);
-}
-
void GraphicsContext::setStrokeThickness(float thickness)
{
m_common->state.strokeThickness = thickness;
@@ -211,6 +200,17 @@ Color GraphicsContext::fillColor() const
return m_common->state.fillColor;
}
+void GraphicsContext::setShouldAntialias(bool b)
+{
+ m_common->state.shouldAntialias = b;
+ setPlatformShouldAntialias(b);
+}
+
+bool GraphicsContext::shouldAntialias() const
+{
+ return m_common->state.shouldAntialias;
+}
+
void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
{
ASSERT(pattern);
@@ -255,6 +255,11 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
m_common->state.fillGradient = gradient;
}
+void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms)
+{
+ m_common->state.shadowsIgnoreTransforms = ignoreTransforms;
+}
+
bool GraphicsContext::updatingControlTints() const
{
return m_common->m_updatingControlTints;
@@ -296,15 +301,15 @@ void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect
drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale);
}
-void GraphicsContext::drawText(const TextRun& run, const IntPoint& point, int from, int to)
+void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to)
{
if (paintingDisabled())
return;
- font().drawText(this, run, point, from, to);
+ font.drawText(this, run, point, from, to);
}
-void GraphicsContext::drawBidiText(const TextRun& run, const FloatPoint& point)
+void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point)
{
if (paintingDisabled())
return;
@@ -329,23 +334,23 @@ void GraphicsContext::drawBidiText(const TextRun& run, const FloatPoint& point)
subrun.setRTL(bidiRun->level() % 2);
subrun.setDirectionalOverride(bidiRun->dirOverride(false));
- font().drawText(this, subrun, currPoint);
+ font.drawText(this, subrun, currPoint);
bidiRun = bidiRun->next();
// FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here.
if (bidiRun)
- currPoint.move(font().floatWidth(subrun), 0.f);
+ currPoint.move(font.floatWidth(subrun), 0.f);
}
bidiResolver.deleteRuns();
}
-void GraphicsContext::drawHighlightForText(const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to)
+void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to)
{
if (paintingDisabled())
return;
- fillRect(font().selectionRectForText(run, point, h, from, to), backgroundColor);
+ fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor);
}
void GraphicsContext::initFocusRing(int width, int offset)
@@ -498,10 +503,4 @@ void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&)
}
#endif
-#if !PLATFORM(QT)
-void GraphicsContext::setPlatformFont(const Font&)
-{
-}
-#endif
-
}
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index 95bdc90..c27f38f 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -98,7 +98,7 @@ namespace WebCore {
const int cMisspellingLinePatternWidth = 4;
const int cMisspellingLinePatternGapWidth = 1;
- class AffineTransform;
+ class TransformationMatrix;
class Font;
class Generator;
class Gradient;
@@ -145,9 +145,6 @@ namespace WebCore {
~GraphicsContext();
PlatformGraphicsContext* platformContext() const;
-
- const Font& font() const;
- void setFont(const Font&);
float strokeThickness() const;
void setStrokeThickness(float);
@@ -166,6 +163,15 @@ namespace WebCore {
void setFillColor(const Color&);
void setFillPattern(PassRefPtr<Pattern>);
void setFillGradient(PassRefPtr<Gradient>);
+ void setShadowsIgnoreTransforms(bool);
+
+ void setShouldAntialias(bool);
+ bool shouldAntialias() const;
+
+#if PLATFORM(CG)
+ void applyStrokePattern();
+ void applyFillPattern();
+#endif
#if PLATFORM(SGL)
/* these should be pused to apple. needed for CanvasStyle.cpp */
@@ -183,6 +189,10 @@ namespace WebCore {
bool willFill() const;
// returns true if there is a valid (non-transparent) stroke color
bool willStroke() const;
+
+ // may return NULL, since we lazily allocate the path. This is the path
+ // that is drawn by drawPath()
+ const SkPath* getCurrPath() const;
/** platform-specific factory method to return a bitmap graphicscontext,
called by <canvas> when we need to draw offscreen. Caller is responsible for
@@ -239,14 +249,15 @@ namespace WebCore {
void clipOut(const IntRect&);
void clipOutEllipseInRect(const IntRect&);
void clipOutRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight);
+ void clipPath(WindRule);
void clipToImageBuffer(const FloatRect&, const ImageBuffer*);
int textDrawingMode();
void setTextDrawingMode(int);
- void drawText(const TextRun&, const IntPoint&, int from = 0, int to = -1);
- void drawBidiText(const TextRun&, const FloatPoint&);
- void drawHighlightForText(const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1);
+ void drawText(const Font&, const TextRun&, const IntPoint&, int from = 0, int to = -1);
+ void drawBidiText(const Font&, const TextRun&, const FloatPoint&);
+ void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1);
FloatRect roundToDevicePixels(const FloatRect&);
@@ -297,10 +308,8 @@ namespace WebCore {
void setURLForRect(const KURL&, const IntRect&);
- void concatCTM(const AffineTransform&);
- AffineTransform getCTM() const;
-
- void setUseAntialiasing(bool = true);
+ void concatCTM(const TransformationMatrix&);
+ TransformationMatrix getCTM() const;
#if PLATFORM(WIN)
GraphicsContext(HDC, bool hasAlpha = false); // FIXME: To be removed.
@@ -308,6 +317,17 @@ namespace WebCore {
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.
void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in HDC should be the one handed back by getWindowsContext.
+ // When set to true, child windows should be rendered into this context
+ // rather than allowing them just to render to the screen. Defaults to
+ // false.
+ // FIXME: This is a layering violation. GraphicsContext shouldn't know
+ // what a "window" is. It would be much more appropriate for this flag
+ // to be passed as a parameter alongside the GraphicsContext, but doing
+ // that would require lots of changes in cross-platform code that we
+ // aren't sure we want to make.
+ void setShouldIncludeChildWindows(bool);
+ bool shouldIncludeChildWindows() const;
+
class WindowsBitmap : public Noncopyable {
public:
WindowsBitmap(HDC, IntSize);
@@ -341,6 +361,7 @@ namespace WebCore {
#if PLATFORM(QT)
bool inTransparencyLayer() const;
PlatformPath* currentPath();
+ QPen pen();
#endif
#if PLATFORM(GTK)
@@ -362,6 +383,8 @@ namespace WebCore {
void setPlatformFillColor(const Color&);
+ void setPlatformShouldAntialias(bool b);
+
void setPlatformShadow(const IntSize&, int blur, const Color&);
void clearPlatformShadow();
diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h
index de94527..87123eb 100644
--- a/WebCore/platform/graphics/GraphicsContextPrivate.h
+++ b/WebCore/platform/graphics/GraphicsContextPrivate.h
@@ -26,7 +26,7 @@
#ifndef GraphicsContextPrivate_h
#define GraphicsContextPrivate_h
-#include "Font.h"
+#include "TransformationMatrix.h"
#include "Gradient.h"
#include "GraphicsContext.h"
#include "Pattern.h"
@@ -58,18 +58,21 @@ namespace WebCore {
, fillRule(RULE_NONZERO)
, fillColorSpace(SolidColorSpace)
, fillColor(Color::black)
+ , shouldAntialias(true)
, paintingDisabled(false)
, shadowBlur(0)
+ , shadowsIgnoreTransforms(false)
{
}
- Font font;
int textDrawingMode;
StrokeStyle strokeStyle;
float strokeThickness;
#if PLATFORM(CAIRO)
float globalAlpha;
+#elif PLATFORM(QT)
+ TransformationMatrix pathTransform;
#endif
ColorSpace strokeColorSpace;
Color strokeColor;
@@ -83,11 +86,15 @@ namespace WebCore {
RefPtr<Gradient> fillGradient;
RefPtr<Pattern> fillPattern;
+ bool shouldAntialias;
+
bool paintingDisabled;
IntSize shadowSize;
unsigned shadowBlur;
Color shadowColor;
+
+ bool shadowsIgnoreTransforms;
};
class GraphicsContextPrivate {
diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp
index ca6954e..49961e1 100644
--- a/WebCore/platform/graphics/Image.cpp
+++ b/WebCore/platform/graphics/Image.cpp
@@ -27,11 +27,12 @@
#include "config.h"
#include "Image.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "BitmapImage.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "MIMETypeRegistry.h"
+#include <wtf/StdLibExtras.h>
#include <math.h>
@@ -52,7 +53,7 @@ Image::~Image()
Image* Image::nullImage()
{
- static RefPtr<Image> nullImage = BitmapImage::create();
+ DEFINE_STATIC_LOCAL(RefPtr<Image>, nullImage, (BitmapImage::create()));;
return nullImage.get();
}
@@ -61,11 +62,6 @@ bool Image::supportsType(const String& type)
return MIMETypeRegistry::isSupportedImageResourceMIMEType(type);
}
-bool Image::isNull() const
-{
- return size().isEmpty();
-}
-
bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived)
{
m_data = data;
@@ -79,21 +75,6 @@ bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived)
return dataChanged(allDataReceived);
}
-IntRect Image::rect() const
-{
- return IntRect(IntPoint(), size());
-}
-
-int Image::width() const
-{
- return size().width();
-}
-
-int Image::height() const
-{
- return size().height();
-}
-
void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op)
{
if (color.alpha() <= 0)
@@ -138,7 +119,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl
FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(),
scaledTileSize.height() / intrinsicTileSize.height());
- AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height());
+ TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height());
FloatRect oneTileRect;
oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width()));
@@ -177,7 +158,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const Flo
vRule = RepeatTile;
FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule);
- AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height());
+ TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height());
// We want to construct the phase such that the pattern is centered (when stretch is not
// set for a particular rule).
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
index 1419b2d..c3cf2e7 100644
--- a/WebCore/platform/graphics/Image.h
+++ b/WebCore/platform/graphics/Image.h
@@ -30,6 +30,7 @@
#include "Color.h"
#include "GraphicsTypes.h"
#include "ImageSource.h"
+#include "IntRect.h"
#include <wtf/RefPtr.h>
#include <wtf/PassRefPtr.h>
#include "SharedBuffer.h"
@@ -66,13 +67,11 @@ class SkBitmapRef;
namespace WebCore {
-class AffineTransform;
+class TransformationMatrix;
class FloatPoint;
class FloatRect;
class FloatSize;
class GraphicsContext;
-class IntRect;
-class IntSize;
class SharedBuffer;
class String;
@@ -96,7 +95,7 @@ public:
virtual bool hasSingleSecurityOrigin() const { return false; }
static Image* nullImage();
- bool isNull() const;
+ bool isNull() const { return size().isEmpty(); }
// These are only used for SVGImage right now
virtual void setContainerSize(const IntSize&) { }
@@ -105,14 +104,16 @@ public:
virtual bool hasRelativeHeight() const { return false; }
virtual IntSize size() const = 0;
- IntRect rect() const;
- int width() const;
- int height() const;
+ IntRect rect() const { return IntRect(IntPoint(), size()); }
+ int width() const { return size().width(); }
+ int height() const { return size().height(); }
bool setData(PassRefPtr<SharedBuffer> data, bool allDataReceived);
- virtual bool dataChanged(bool allDataReceived) { return false; }
+ virtual bool dataChanged(bool /*allDataReceived*/) { return false; }
+
+ virtual String filenameExtension() const { return String(); } // null string if unknown
- virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) = 0;
+ virtual void destroyDecodedData(bool destroyAll = true) = 0;
virtual unsigned decodedSize() const = 0;
SharedBuffer* data() { return m_data.get(); }
@@ -166,9 +167,9 @@ protected:
virtual bool mayFillWithSolidColor() const { return false; }
virtual Color solidColor() const { return Color(); }
- virtual void startAnimation() { }
+ virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { }
- virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ 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
diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h
index 7c68fc8..14f7461 100644
--- a/WebCore/platform/graphics/ImageBuffer.h
+++ b/WebCore/platform/graphics/ImageBuffer.h
@@ -27,6 +27,7 @@
#ifndef ImageBuffer_h
#define ImageBuffer_h
+#include "TransformationMatrix.h"
#include "Image.h"
#include "IntSize.h"
#include "ImageBufferData.h"
@@ -67,7 +68,11 @@ namespace WebCore {
void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint);
String toDataURL(const String& mimeType) const;
-
+#if !PLATFORM(CG)
+ TransformationMatrix baseTransform() const { return TransformationMatrix(); }
+#else
+ TransformationMatrix baseTransform() const { return TransformationMatrix(1, 0, 0, -1, 0, m_size.height()); }
+#endif
private:
ImageBufferData m_data;
diff --git a/WebCore/platform/graphics/ImageObserver.h b/WebCore/platform/graphics/ImageObserver.h
index 4be83bd..8b693d9 100644
--- a/WebCore/platform/graphics/ImageObserver.h
+++ b/WebCore/platform/graphics/ImageObserver.h
@@ -29,6 +29,7 @@
namespace WebCore {
class Image;
+class IntRect;
// Interface for notification about changes to an image, including decoding,
// drawing, and animating.
@@ -41,6 +42,8 @@ public:
virtual bool shouldPauseAnimation(const Image*) = 0;
virtual void animationAdvanced(const Image*) = 0;
+
+ virtual void changedInRect(const Image*, const IntRect&) = 0;
};
}
diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h
index a9f346d..55e0c5a 100644
--- a/WebCore/platform/graphics/ImageSource.h
+++ b/WebCore/platform/graphics/ImageSource.h
@@ -55,6 +55,7 @@ namespace WebCore {
class IntSize;
class SharedBuffer;
+class String;
#if PLATFORM(WX)
class ImageDecoder;
@@ -94,22 +95,49 @@ public:
ImageSource();
~ImageSource();
- void clear();
+ // Tells the ImageSource that the Image no longer cares about decoded frame
+ // data -- at all (if |destroyAll| is true), or before frame
+ // |clearBeforeFrame| (if |destroyAll| is false). The ImageSource should
+ // delete cached decoded data for these frames where possible to keep memory
+ // usage low. When |destroyAll| is true, the ImageSource should also reset
+ // any local state so that decoding can begin again.
+ //
+ // Implementations that delete less than what's specified above waste
+ // memory. Implementations that delete more may burn CPU re-decoding frames
+ // that could otherwise have been cached, or encounter errors if they're
+ // asked to decode frames they can't decode due to the loss of previous
+ // decoded frames.
+ //
+ // Callers should not call clear(false, n) and subsequently call
+ // createFrameAtIndex(m) with m < n, unless they first call clear(true).
+ // This ensures that stateful ImageSources/decoders will work properly.
+ //
+ // The |data| and |allDataReceived| parameters should be supplied by callers
+ // who set |destroyAll| to true if they wish to be able to continue using
+ // the ImageSource. This way implementations which choose to destroy their
+ // decoders in some cases can reconstruct them correctly.
+ void clear(bool destroyAll,
+ size_t clearBeforeFrame = 0,
+ SharedBuffer* data = NULL,
+ bool allDataReceived = false);
bool initialized() const;
-
+
void setData(SharedBuffer* data, bool allDataReceived);
+ String filenameExtension() const;
bool isSizeAvailable();
IntSize size() const;
IntSize frameSizeAtIndex(size_t) const;
int repetitionCount();
-
+
size_t frameCount() const;
-
+
+ // Callers should not call this after calling clear() with a higher index;
+ // see comments on clear() above.
NativeImagePtr createFrameAtIndex(size_t);
-
+
float frameDurationAtIndex(size_t);
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.
@@ -119,6 +147,9 @@ public:
void setURL(const String& url);
#endif
private:
+ // FIXME: This is protected only to allow ImageSourceSkia to set ICO decoder
+ // with a preferred size. See ImageSourceSkia.h for discussion.
+protected:
NativeImageSourcePtr m_decoder;
};
diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h
index 7245408..4d36545 100644
--- a/WebCore/platform/graphics/IntSize.h
+++ b/WebCore/platform/graphics/IntSize.h
@@ -67,6 +67,12 @@ public:
bool isEmpty() const { return m_width <= 0 || m_height <= 0; }
+ void expand(int width, int height)
+ {
+ m_width += width;
+ m_height += height;
+ }
+
IntSize expandedTo(const IntSize& other) const
{
return IntSize(m_width > other.m_width ? m_width : other.m_width,
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 1beab95..203f299 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -67,6 +67,9 @@ public:
void setFrameView(FrameView* frameView) { m_frameView = frameView; }
bool inMediaDocument();
+ // FIXME: it would be better to just have a getter and setter for size.
+ // This is currently an absolute rect, which is not appropriate for
+ // content with transforms
IntRect rect() const { return m_rect; }
void setRect(const IntRect& r);
diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h
index 06e6ee4..2b0a7d1 100644
--- a/WebCore/platform/graphics/Path.h
+++ b/WebCore/platform/graphics/Path.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
- * 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved.
+ * 2006 Rob Buis <buis@kde.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,6 +27,8 @@
#ifndef Path_h
#define Path_h
+#include <algorithm>
+
#if PLATFORM(CG)
typedef struct CGPath PlatformPath;
#elif PLATFORM(QT)
@@ -55,11 +57,13 @@ typedef void PlatformPath;
namespace WebCore {
- class AffineTransform;
class FloatPoint;
- class FloatSize;
class FloatRect;
+ class FloatSize;
+ class GraphicsContext;
class String;
+ class StrokeStyleApplier;
+ class TransformationMatrix;
enum WindRule {
RULE_NONZERO = 0,
@@ -79,7 +83,7 @@ namespace WebCore {
FloatPoint* points;
};
- typedef void (*PathApplierFunction) (void* info, const PathElement*);
+ typedef void (*PathApplierFunction)(void* info, const PathElement*);
class Path {
public:
@@ -89,8 +93,12 @@ namespace WebCore {
Path(const Path&);
Path& operator=(const Path&);
+ void swap(Path& other) { std::swap(m_path, other.m_path); }
+
bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const;
+ bool strokeContains(StrokeStyleApplier*, const FloatPoint&) const;
FloatRect boundingRect() const;
+ FloatRect strokeBoundingRect(StrokeStyleApplier* = 0);
float length();
FloatPoint pointAtLength(float length, bool& ok);
@@ -124,7 +132,7 @@ namespace WebCore {
static Path createLine(const FloatPoint&, const FloatPoint&);
void apply(void* info, PathApplierFunction) const;
- void transform(const AffineTransform&);
+ void transform(const TransformationMatrix&);
private:
PlatformPath* m_path;
diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h
index 985c7c0..716a645 100644
--- a/WebCore/platform/graphics/Pattern.h
+++ b/WebCore/platform/graphics/Pattern.h
@@ -54,7 +54,7 @@ typedef wxBrush* PlatformPatternPtr;
#endif
namespace WebCore {
- class AffineTransform;
+ class TransformationMatrix;
class Image;
class Pattern : public RefCounted<Pattern> {
@@ -67,7 +67,7 @@ namespace WebCore {
Image* tileImage() const { return m_tileImage.get(); }
- PlatformPatternPtr createPlatformPattern(const AffineTransform& patternTransform) const;
+ PlatformPatternPtr createPlatformPattern(const TransformationMatrix& patternTransform) const;
private:
Pattern(Image*, bool repeatX, bool repeatY);
diff --git a/WebCore/platform/graphics/SegmentedFontData.cpp b/WebCore/platform/graphics/SegmentedFontData.cpp
index ceefe4f..1731d16 100644
--- a/WebCore/platform/graphics/SegmentedFontData.cpp
+++ b/WebCore/platform/graphics/SegmentedFontData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -45,16 +45,27 @@ const SimpleFontData* SegmentedFontData::fontDataForCharacter(UChar32 c) const
return m_ranges[0].fontData();
}
-bool SegmentedFontData::containsCharacters(const UChar* characters, int length) const
+bool SegmentedFontData::containsCharacter(UChar32 c) const
{
Vector<FontDataRange>::const_iterator end = m_ranges.end();
for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) {
- if (it->from() <= characters[0] && it->to() >= characters[0])
+ if (c >= it->from() && c <= it->to())
return true;
}
return false;
}
+bool SegmentedFontData::containsCharacters(const UChar* characters, int length) const
+{
+ UChar32 c;
+ for (int i = 0; i < length; ) {
+ U16_NEXT(characters, i, length, c)
+ if (!containsCharacter(c))
+ return false;
+ }
+ return true;
+}
+
bool SegmentedFontData::isCustomFont() const
{
// All segmented fonts are custom fonts.
diff --git a/WebCore/platform/graphics/SegmentedFontData.h b/WebCore/platform/graphics/SegmentedFontData.h
index 1adec15..0a78321 100644
--- a/WebCore/platform/graphics/SegmentedFontData.h
+++ b/WebCore/platform/graphics/SegmentedFontData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 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
@@ -55,6 +55,11 @@ class SegmentedFontData : public FontData {
public:
virtual ~SegmentedFontData();
+ void appendRange(const FontDataRange& range) { m_ranges.append(range); }
+ unsigned numRanges() const { return m_ranges.size(); }
+ const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; }
+
+private:
virtual const SimpleFontData* fontDataForCharacter(UChar32) const;
virtual bool containsCharacters(const UChar*, int length) const;
@@ -62,11 +67,8 @@ public:
virtual bool isLoading() const;
virtual bool isSegmented() const;
- void appendRange(const FontDataRange& range) { m_ranges.append(range); }
- unsigned numRanges() const { return m_ranges.size(); }
- const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; }
+ bool containsCharacter(UChar32) const;
-private:
Vector<FontDataRange, 1> m_ranges;
};
diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp
index 372fcc8..9670b55 100644
--- a/WebCore/platform/graphics/SimpleFontData.cpp
+++ b/WebCore/platform/graphics/SimpleFontData.cpp
@@ -30,6 +30,7 @@
#include "config.h"
#include "SimpleFontData.h"
+#include "Font.h"
#include "FontCache.h"
#if ENABLE(SVG_FONTS)
#include "SVGFontData.h"
@@ -41,7 +42,8 @@
namespace WebCore {
SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData)
- : m_font(f)
+ : m_unitsPerEm(defaultUnitsPerEm)
+ , m_font(f)
, m_treatAsFixedPitch(false)
#if ENABLE(SVG_FONTS)
, m_svgFontData(svgFontData)
@@ -50,7 +52,7 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool
, m_isLoading(loading)
, m_smallCapsFontData(0)
{
-#if ENABLE(SVG_FONTS) && !PLATFORM(QT)
+#if ENABLE(SVG_FONTS)
if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) {
m_unitsPerEm = svgFontFaceElement->unitsPerEm();
@@ -75,7 +77,12 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool
#endif
platformInit();
+ platformGlyphInit();
+}
+#if !PLATFORM(QT)
+void SimpleFontData::platformGlyphInit()
+{
GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
if (!glyphPageZero) {
LOG_ERROR("Failed to get glyph page zero.");
@@ -113,21 +120,23 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool
m_missingGlyphData.fontData = this;
m_missingGlyphData.glyph = 0;
}
+#endif
SimpleFontData::~SimpleFontData()
{
+#if ENABLE(SVG_FONTS)
+ if (!m_svgFontData || !m_svgFontData->svgFontFaceElement())
+#endif
+ platformDestroy();
+
if (!isCustomFont()) {
if (m_smallCapsFontData)
- FontCache::releaseFontData(m_smallCapsFontData);
+ fontCache()->releaseFontData(m_smallCapsFontData);
GlyphPageTreeNode::pruneTreeFontData(this);
}
-
-#if ENABLE(SVG_FONTS) && !PLATFORM(QT)
- if (!m_svgFontData || !m_svgFontData->svgFontFaceElement())
-#endif
- platformDestroy();
}
+#if !PLATFORM(QT)
float SimpleFontData::widthForGlyph(Glyph glyph) const
{
float width = m_glyphToWidthMap.widthForGlyph(glyph);
@@ -139,6 +148,7 @@ float SimpleFontData::widthForGlyph(Glyph glyph) const
return width;
}
+#endif
const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
{
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
index 5f26cbf..e572e30 100644
--- a/WebCore/platform/graphics/SimpleFontData.h
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -41,6 +41,10 @@ typedef struct OpaqueATSUStyle* ATSUStyle;
#include <cairo.h>
#endif
+#if PLATFORM(QT)
+#include <QFont>
+#endif
+
namespace WebCore {
class FontDescription;
@@ -109,6 +113,10 @@ public:
}
#endif
+#if PLATFORM(QT)
+ QFont getQtFont() const { return m_font.font(); }
+#endif
+
#if PLATFORM(WIN)
bool isSystemFont() const { return m_isSystemFont; }
SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
@@ -128,6 +136,7 @@ public:
private:
void platformInit();
+ void platformGlyphInit();
void platformDestroy();
void commonInit();
diff --git a/WebCore/platform/graphics/StrokeStyleApplier.h b/WebCore/platform/graphics/StrokeStyleApplier.h
new file mode 100644
index 0000000..e40d3d1
--- /dev/null
+++ b/WebCore/platform/graphics/StrokeStyleApplier.h
@@ -0,0 +1,38 @@
+/*
+ Copyright (C) 2008 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
+ 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 StrokeStyleApplier_h
+#define StrokeStyleApplier_h
+
+namespace WebCore {
+
+ class GraphicsContext;
+
+ class StrokeStyleApplier {
+ public:
+ virtual void strokeStyle(GraphicsContext*) = 0;
+
+ protected:
+ StrokeStyleApplier() {}
+ virtual ~StrokeStyleApplier() {}
+ };
+}
+
+#endif
+
diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
index c257348..0b3655f 100644
--- a/WebCore/platform/graphics/android/FontCacheAndroid.cpp
+++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
@@ -113,7 +113,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
if (fontDescription.italic())
style |= SkTypeface::kItalic;
- SkTypeface* tf = SkTypeface::Create(name, (SkTypeface::Style)style);
+ SkTypeface* tf = SkTypeface::CreateFromName(name, (SkTypeface::Style)style);
FontPlatformData* result = new FontPlatformData(tf,
fontDescription.computedSize(),
diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
index c2e0f02..40d98ec 100644
--- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -40,7 +40,7 @@
#include "SkPaint.h"
#include "SkPorterDuff.h"
#include "PlatformGraphicsContext.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "android_graphics.h"
#include "SkGradientShader.h"
@@ -320,7 +320,7 @@ static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat,
case PatternColorSpace:
// createPlatformPattern() returns a new inst
paint->setShader(pat->createPlatformPattern(
- AffineTransform()))->safeUnref();
+ TransformationMatrix()))->safeUnref();
break;
case GradientColorSpace: {
// grad->getShader() returns a cached obj
@@ -389,6 +389,10 @@ bool GraphicsContext::willStroke() const {
return m_data->mState->mStrokeColor != 0;
}
+const SkPath* GraphicsContext::getCurrPath() const {
+ return m_data->mState->mPath;
+}
+
// Draws a filled rectangle with a stroked border.
void GraphicsContext::drawRect(const IntRect& rect)
{
@@ -771,19 +775,21 @@ KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext()
}
#endif
+/* These are the flags we need when we call saveLayer for transparency.
+ Since it does not appear that webkit intends this to also save/restore
+ the matrix or clip, I do not give those flags (for performance)
+ */
+#define TRANSPARENCY_SAVEFLAGS \
+ (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | \
+ SkCanvas::kFullColorLayer_SaveFlag)
+
void GraphicsContext::beginTransparencyLayer(float opacity)
{
if (paintingDisabled())
return;
SkCanvas* canvas = GC2Canvas(this);
-
- if (opacity < 1)
- {
- canvas->saveLayerAlpha(NULL, (int)(opacity * 255), SkCanvas::kHasAlphaLayer_SaveFlag);
- }
- else
- canvas->save();
+ canvas->saveLayerAlpha(NULL, (int)(opacity * 255), TRANSPARENCY_SAVEFLAGS);
}
void GraphicsContext::endTransparencyLayer()
@@ -976,7 +982,7 @@ void GraphicsContext::translate(float x, float y)
GC2Canvas(this)->translate(SkFloatToScalar(x), SkFloatToScalar(y));
}
-void GraphicsContext::concatCTM(const AffineTransform& xform)
+void GraphicsContext::concatCTM(const TransformationMatrix& xform)
{
if (paintingDisabled())
return;
@@ -1026,32 +1032,38 @@ if (urlRef) {
#endif
}
-void GraphicsContext::setUseAntialiasing(bool useAA) {
+void GraphicsContext::setPlatformShouldAntialias(bool useAA)
+{
if (paintingDisabled())
return;
m_data->mState->mUseAA = useAA;
}
-AffineTransform GraphicsContext::getCTM() const {
- return AffineTransform(GC2Canvas(this)->getTotalMatrix());
+TransformationMatrix GraphicsContext::getCTM() const
+{
+ return TransformationMatrix(GC2Canvas(this)->getTotalMatrix());
}
///////////////////////////////////////////////////////////////////////////////
-void GraphicsContext::beginPath() {
+void GraphicsContext::beginPath()
+{
m_data->beginPath();
}
-void GraphicsContext::addPath(const Path& p) {
+void GraphicsContext::addPath(const Path& p)
+{
m_data->addPath(*p.platformPath());
}
-void GraphicsContext::drawPath() {
+void GraphicsContext::drawPath()
+{
this->fillPath();
this->strokePath();
}
-void GraphicsContext::fillPath() {
+void GraphicsContext::fillPath()
+{
SkPath* path = m_data->getPath();
if (paintingDisabled() || !path)
return;
@@ -1075,7 +1087,8 @@ void GraphicsContext::fillPath() {
GC2Canvas(this)->drawPath(*path, paint);
}
-void GraphicsContext::strokePath() {
+void GraphicsContext::strokePath()
+{
const SkPath* path = m_data->getPath();
if (paintingDisabled() || !path || strokeStyle() == NoStroke)
return;
@@ -1112,7 +1125,8 @@ void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
///////////////////////////////////////////////////////////////////////////////
-SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc) {
+SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc)
+{
return gc->platformContext()->mCanvas;
}
diff --git a/WebCore/platform/graphics/android/ImageAndroid.cpp b/WebCore/platform/graphics/android/ImageAndroid.cpp
index 04235d5..da52d67 100644
--- a/WebCore/platform/graphics/android/ImageAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -25,7 +25,7 @@
*/
#include "config.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "BitmapImage.h"
#include "Image.h"
#include "FloatRect.h"
@@ -59,14 +59,19 @@ android::AssetManager* globalAssetManager() {
namespace WebCore {
-void FrameData::clear()
+bool FrameData::clear(bool clearMetadata)
{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
if (m_frame) {
m_frame->unref();
m_frame = 0;
m_duration = 0.;
m_hasAlpha = true;
+ return true;
}
+ return false;
}
BitmapImage::BitmapImage(SkBitmapRef* ref, ImageObserver* observer)
@@ -211,7 +216,7 @@ void BitmapImage::setURL(const String& str)
///////////////////////////////////////////////////////////////////////////////
void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
- const AffineTransform& patternTransform,
+ const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator compositeOp,
const FloatRect& destRect)
{
diff --git a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
index de88b33..7b3e8e8 100644
--- a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
@@ -99,8 +99,9 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
return 0;
}
- PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
- unsigned char* data = result->data()->data().data();
+ // ! Can't use PassRefPtr<>, otherwise the second access will cause crash.
+ RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
+ unsigned char* data = result->data()->data()->data();
if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
memset(data, 0, result->data()->length());
@@ -190,7 +191,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con
unsigned srcBytesPerRow = 4 * source->width();
unsigned dstPixelsPerRow = dst.rowBytesAsPixels();
- unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4;
+ unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
SkPMColor* dstRows = dst.getAddr32(destx, desty);
for (int y = 0; y < numRows; ++y) {
for (int x = 0; x < numColumns; x++) {
diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
index a6bf6c6..c8fe8dd 100644
--- a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
@@ -347,7 +347,7 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index)
return m_decoder.m_image && m_decoder.m_image->fAllDataReceived;
}
-void ImageSource::clear()
+void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
{
// do nothing, since the cache is managed elsewhere
}
@@ -358,4 +358,10 @@ IntSize ImageSource::frameSizeAtIndex(size_t index) const
return this->size();
}
+String ImageSource::filenameExtension() const
+{
+ // FIXME: need to add virtual to our decoders to return "jpg/png/gif/..."
+ return String();
+}
+
}
diff --git a/WebCore/platform/graphics/android/PathAndroid.cpp b/WebCore/platform/graphics/android/PathAndroid.cpp
index 819173b..cfcd2bc 100644
--- a/WebCore/platform/graphics/android/PathAndroid.cpp
+++ b/WebCore/platform/graphics/android/PathAndroid.cpp
@@ -26,7 +26,10 @@
#include "config.h"
#include "Path.h"
#include "FloatRect.h"
-#include "AffineTransform.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "StrokeStyleApplier.h"
+#include "TransformationMatrix.h"
#include "SkPath.h"
#include "SkRegion.h"
@@ -260,9 +263,54 @@ void Path::apply(void* info, PathApplierFunction function) const
}
}
-void Path::transform(const AffineTransform& xform)
+void Path::transform(const TransformationMatrix& xform)
{
m_path->transform(xform);
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Computes the bounding box for the stroke and style currently selected into
+// the given bounding box. This also takes into account the stroke width.
+static FloatRect boundingBoxForCurrentStroke(GraphicsContext* context)
+{
+ const SkPath* path = context->getCurrPath();
+ if (NULL == path) {
+ return FloatRect();
+ }
+
+ SkPaint paint;
+ context->setupStrokePaint(&paint);
+ SkPath fillPath;
+ paint.getFillPath(*path, &fillPath);
+ SkRect r;
+ fillPath.computeBounds(&r, SkPath::kExact_BoundsType);
+ return FloatRect(r.fLeft, r.fTop, r.width(), r.height());
+}
+
+static GraphicsContext* scratchContext()
+{
+ static ImageBuffer* scratch = 0;
+ if (!scratch)
+ scratch = ImageBuffer::create(IntSize(1, 1), false).release();
+ // We don't bother checking for failure creating the ImageBuffer, since our
+ // ImageBuffer initializer won't fail.
+ return scratch->context();
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ GraphicsContext* scratch = scratchContext();
+ scratch->save();
+ scratch->beginPath();
+ scratch->addPath(*this);
+
+ if (applier)
+ applier->strokeStyle(scratch);
+
+ FloatRect r = boundingBoxForCurrentStroke(scratch);
+ scratch->restore();
+ return r;
+}
}
diff --git a/WebCore/platform/graphics/android/PatternAndroid.cpp b/WebCore/platform/graphics/android/PatternAndroid.cpp
index 2840faa..ffdbbb1 100644
--- a/WebCore/platform/graphics/android/PatternAndroid.cpp
+++ b/WebCore/platform/graphics/android/PatternAndroid.cpp
@@ -40,7 +40,7 @@ static SkShader::TileMode toTileMode(bool doRepeat) {
return doRepeat ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
}
-SkShader* Pattern::createPlatformPattern(const AffineTransform& transform) const
+SkShader* Pattern::createPlatformPattern(const TransformationMatrix& transform) const
{
SkBitmapRef* ref = tileImage()->nativeImageForCurrentFrame();
SkShader* s = SkShader::CreateBitmapShader(ref->bitmap(),
diff --git a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp b/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp
index c01d078..154d4f3 100644
--- a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
+++ b/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp
@@ -24,7 +24,7 @@
*/
#include "config.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatRect.h"
#include "IntRect.h"
@@ -35,14 +35,14 @@ namespace WebCore {
static const double deg2rad = 0.017453292519943295769; // pi/180
-AffineTransform::AffineTransform()
+TransformationMatrix::TransformationMatrix()
{
m_transform.reset();
}
-AffineTransform::AffineTransform(const SkMatrix& mat) : m_transform(mat) {}
+TransformationMatrix::TransformationMatrix(const SkMatrix& mat) : m_transform(mat) {}
-AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
{
m_transform.reset();
@@ -55,7 +55,7 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double
m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
}
-void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
+void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
{
m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
@@ -66,150 +66,164 @@ void AffineTransform::setMatrix(double a, double b, double c, double d, double t
m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
}
-void AffineTransform::map(double x, double y, double *x2, double *y2) const
+void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
{
- SkPoint src, dst;
- src.set(SkDoubleToScalar(x), SkDoubleToScalar(y));
- m_transform.mapPoints(&dst, &src, 1);
+ SkPoint pt;
- *x2 = SkScalarToDouble(dst.fX);
- *y2 = SkScalarToDouble(dst.fY);
+ m_transform.mapXY(SkDoubleToScalar(x), SkDoubleToScalar(y), &pt);
+ *x2 = SkScalarToDouble(pt.fX);
+ *y2 = SkScalarToDouble(pt.fY);
}
-IntRect AffineTransform::mapRect(const IntRect &rect) const
+IntRect TransformationMatrix::mapRect(const IntRect &rect) const
{
SkRect src, dst;
SkIRect ir;
android_setrect(&src, rect);
m_transform.mapRect(&dst, src);
- dst.round(&ir);
+ // we round out to mimic enclosingIntRect()
+ dst.roundOut(&ir);
return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
}
-FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
{
- SkRect src, dst;
- SkIRect ir;
+ SkRect r;
- android_setrect(&src, rect);
- m_transform.mapRect(&dst, src);
- dst.round(&ir);
+ android_setrect(&r, rect);
+ m_transform.mapRect(&r);
- return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
+ return FloatRect(r.fLeft, r.fTop, r.width(), r.height());
}
-bool AffineTransform::isIdentity() const
+bool TransformationMatrix::isIdentity() const
{
return m_transform.isIdentity();
}
-void AffineTransform::reset()
+void TransformationMatrix::reset()
{
m_transform.reset();
}
- double AffineTransform::a() const {
- return SkScalarToDouble(m_transform[0]);
- }
- void AffineTransform::setA(double a) {
- m_transform.set(0, SkDoubleToScalar(a));
- }
+double TransformationMatrix::a() const
+{
+ return SkScalarToDouble(m_transform[0]);
+}
- double AffineTransform::b() const {
- return SkScalarToDouble(m_transform[1]);
- }
- void AffineTransform::setB(double b) {
- m_transform.set(1, SkDoubleToScalar(b));
- }
-
- double AffineTransform::c() const {
- return SkScalarToDouble(m_transform[3]);
- }
- void AffineTransform::setC(double c) {
- m_transform.set(3, SkDoubleToScalar(c));
- }
-
- double AffineTransform::d() const {
- return SkScalarToDouble(m_transform[4]);
- }
- void AffineTransform::setD(double d) {
- m_transform.set(4, SkDoubleToScalar(d));
- }
-
- double AffineTransform::e() const {
- return SkScalarToDouble(m_transform[2]);
- }
- void AffineTransform::setE(double e) {
- m_transform.set(2, SkDoubleToScalar(e));
- }
-
- double AffineTransform::f() const {
- return SkScalarToDouble(m_transform[5]);
- }
- void AffineTransform::setF(double f) {
- m_transform.set(5, SkDoubleToScalar(f));
- }
+void TransformationMatrix::setA(double a)
+{
+ m_transform.set(0, SkDoubleToScalar(a));
+}
+
+double TransformationMatrix::b() const
+{
+ return SkScalarToDouble(m_transform[1]);
+}
+
+void TransformationMatrix::setB(double b)
+{
+ m_transform.set(1, SkDoubleToScalar(b));
+}
+
+double TransformationMatrix::c() const
+{
+ return SkScalarToDouble(m_transform[3]);
+}
+
+void TransformationMatrix::setC(double c)
+{
+ m_transform.set(3, SkDoubleToScalar(c));
+}
+
+double TransformationMatrix::d() const {
+ return SkScalarToDouble(m_transform[4]);
+}
+
+void TransformationMatrix::setD(double d)
+{
+ m_transform.set(4, SkDoubleToScalar(d));
+}
+
+double TransformationMatrix::e() const
+{
+ return SkScalarToDouble(m_transform[2]);
+}
+
+void TransformationMatrix::setE(double e)
+{
+ m_transform.set(2, SkDoubleToScalar(e));
+}
+
+double TransformationMatrix::f() const {
+ return SkScalarToDouble(m_transform[5]);
+}
+void TransformationMatrix::setF(double f) {
+ m_transform.set(5, SkDoubleToScalar(f));
+}
-AffineTransform &AffineTransform::scale(double sx, double sy)
+TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
{
m_transform.preScale(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
return *this;
}
-AffineTransform &AffineTransform::rotate(double d)
+TransformationMatrix &TransformationMatrix::rotate(double d)
{
m_transform.preRotate(SkDoubleToScalar(d));
return *this;
}
-AffineTransform &AffineTransform::translate(double tx, double ty)
+TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
{
m_transform.preTranslate(SkDoubleToScalar(tx), SkDoubleToScalar(ty));
return *this;
}
-AffineTransform &AffineTransform::shear(double sx, double sy)
+TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
{
m_transform.preSkew(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
return *this;
}
-double AffineTransform::det() const
+double TransformationMatrix::det() const
{
return SkScalarToDouble(m_transform[SkMatrix::kMScaleX]) * SkScalarToDouble(m_transform[SkMatrix::kMScaleY]) -
SkScalarToDouble(m_transform[SkMatrix::kMSkewX]) * SkScalarToDouble(m_transform[SkMatrix::kMSkewY]);
}
-AffineTransform AffineTransform::inverse() const
+TransformationMatrix TransformationMatrix::inverse() const
{
- AffineTransform inverse;
+ // the constructor initializes inverse to the identity
+ TransformationMatrix inverse;
+ // if we are not invertible, inverse will stay identity
m_transform.invert(&inverse.m_transform);
return inverse;
}
-AffineTransform::operator SkMatrix() const
+TransformationMatrix::operator SkMatrix() const
{
return m_transform;
}
-bool AffineTransform::operator==(const AffineTransform &m2) const
+bool TransformationMatrix::operator==(const TransformationMatrix &m2) const
{
return m_transform == m2.m_transform;
}
-AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
{
m_transform.setConcat(m2.m_transform, m_transform);
return *this;
}
-AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
{
- AffineTransform cat;
+ TransformationMatrix cat;
cat.m_transform.setConcat(m2.m_transform, m_transform);
return cat;
diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp
index 2bc0c8f..1decfd8 100644
--- a/WebCore/platform/graphics/android/android_graphics.cpp
+++ b/WebCore/platform/graphics/android/android_graphics.cpp
@@ -98,7 +98,7 @@ static const struct CompositOpToPorterDuffMode {
uint8_t mPorterDuffMode;
} gMapCompositOpsToPorterDuffModes[] = {
{ WebCore::CompositeClear, SkPorterDuff::kClear_Mode },
- { WebCore::CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { WebCore::CompositeCopy, SkPorterDuff::kSrc_Mode },
{ WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
{ WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
{ WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index c403f44..ef748cf 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -31,7 +31,7 @@
#if PLATFORM(CAIRO)
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "CairoPath.h"
#include "FloatRect.h"
#include "Font.h"
@@ -62,6 +62,15 @@
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;
@@ -90,9 +99,6 @@ static inline cairo_pattern_t* applySpreadMethod(cairo_pattern_t* pattern, Gradi
case SpreadMethodRepeat:
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
break;
- default:
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_NONE);
- break;
}
return pattern;
}
@@ -111,7 +117,7 @@ GraphicsContext::~GraphicsContext()
delete m_data;
}
-AffineTransform GraphicsContext::getCTM() const
+TransformationMatrix GraphicsContext::getCTM() const
{
cairo_t* cr = platformContext();
cairo_matrix_t m;
@@ -444,19 +450,19 @@ void GraphicsContext::fillPath()
cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
switch (m_common->state.fillColorSpace) {
case SolidColorSpace:
- if (fillColor().alpha()) {
- setColor(cr, fillColor());
- cairo_clip(cr);
- cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
- }
+ setColor(cr, fillColor());
+ cairo_clip(cr);
+ cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
break;
- case PatternColorSpace:
- cairo_set_source(cr, m_common->state.fillPattern.get()->createPlatformPattern(getCTM()));
+ case PatternColorSpace: {
+ TransformationMatrix affine;
+ cairo_set_source(cr, m_common->state.fillPattern->createPlatformPattern(affine));
cairo_clip(cr);
cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
break;
+ }
case GradientColorSpace:
- cairo_pattern_t* pattern = m_common->state.fillGradient.get()->platformGradient();
+ cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient();
pattern = applySpreadMethod(pattern, spreadMethod());
cairo_set_source(cr, pattern);
cairo_clip(cr);
@@ -475,18 +481,16 @@ void GraphicsContext::strokePath()
cairo_save(cr);
switch (m_common->state.strokeColorSpace) {
case SolidColorSpace:
- if (strokeColor().alpha()) {
- setColor(cr, strokeColor());
- if (m_common->state.globalAlpha < 1.0f) {
- cairo_push_group(cr);
- cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
- cairo_pop_group_to_source(cr);
- }
- cairo_stroke(cr);
- }
+ float red, green, blue, alpha;
+ strokeColor().getRGBA(red, green, blue, alpha);
+ if (m_common->state.globalAlpha < 1.0f)
+ alpha *= m_common->state.globalAlpha;
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+ cairo_stroke(cr);
break;
- case PatternColorSpace:
- cairo_set_source(cr, m_common->state.strokePattern.get()->createPlatformPattern(getCTM()));
+ case PatternColorSpace: {
+ TransformationMatrix affine;
+ cairo_set_source(cr, m_common->state.strokePattern->createPlatformPattern(affine));
if (m_common->state.globalAlpha < 1.0f) {
cairo_push_group(cr);
cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
@@ -494,8 +498,9 @@ void GraphicsContext::strokePath()
}
cairo_stroke(cr);
break;
+ }
case GradientColorSpace:
- cairo_pattern_t* pattern = m_common->state.strokeGradient.get()->platformGradient();
+ cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient();
pattern = applySpreadMethod(pattern, spreadMethod());
cairo_set_source(cr, pattern);
if (m_common->state.globalAlpha < 1.0f) {
@@ -548,6 +553,16 @@ void GraphicsContext::clip(const FloatRect& rect)
m_data->clip(rect);
}
+void GraphicsContext::clipPath(WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+}
+
void GraphicsContext::drawFocusRing(const Color& color)
{
if (paintingDisabled())
@@ -729,7 +744,7 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
notImplemented();
}
-void GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContext::concatCTM(const TransformationMatrix& transform)
{
if (paintingDisabled())
return;
@@ -1079,7 +1094,7 @@ GdkDrawable* GraphicsContext::gdkDrawable() const
}
#endif
-void GraphicsContext::setUseAntialiasing(bool enable)
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
{
if (paintingDisabled())
return;
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
index 9a14555..535f70d 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -69,7 +69,7 @@ public:
void scale(const FloatSize&);
void rotate(float);
void translate(float, float);
- void concatCTM(const AffineTransform&);
+ void concatCTM(const TransformationMatrix&);
void beginTransparencyLayer() { m_transparencyCount++; }
void endTransparencyLayer() { m_transparencyCount--; }
#else
@@ -81,7 +81,7 @@ public:
void scale(const FloatSize&) {}
void rotate(float) {}
void translate(float, float) {}
- void concatCTM(const AffineTransform&) {}
+ void concatCTM(const TransformationMatrix&) {}
void beginTransparencyLayer() {}
void endTransparencyLayer() {}
#endif
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 5f65ed2..3e06669 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -94,7 +94,7 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface);
- unsigned char* dataDst = result->data()->data().data();
+ unsigned char* dataDst = result->data()->data()->data();
if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
memset(dataSrc, 0, result->data()->length());
@@ -179,7 +179,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con
unsigned srcBytesPerRow = 4 * source->width();
int stride = cairo_image_surface_get_stride(m_data.m_surface);
- unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4;
+ unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
for (int y = 0; y < numRows; ++y) {
unsigned char *row = dataDst + stride * (y + desty);
for (int x = 0; x < numColumns; x++) {
diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp
index 0a35cf2..2850488 100644
--- a/WebCore/platform/graphics/cairo/ImageCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -29,7 +29,7 @@
#if PLATFORM(CAIRO)
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatRect.h"
#include "GraphicsContext.h"
#include "ImageObserver.h"
@@ -38,15 +38,17 @@
namespace WebCore {
-void FrameData::clear()
+bool FrameData::clear(bool clearMetadata)
{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
if (m_frame) {
cairo_surface_destroy(m_frame);
m_frame = 0;
- // NOTE: We purposefully don't reset metadata here, so that even if we
- // throw away previously-decoded data, animation loops can still access
- // properties like frame durations without re-decoding.
+ return true;
}
+ return false;
}
BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer)
@@ -139,7 +141,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo
imageObserver()->didDraw(this);
}
-void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform,
+void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
cairo_surface_t* image = nativeImageForCurrentFrame();
diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
index b7a4cbb..6841599 100644
--- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
@@ -97,13 +97,21 @@ ImageSource::ImageSource()
ImageSource::~ImageSource()
{
- clear();
+ clear(true);
}
-void ImageSource::clear()
+void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
{
+ if (!destroyAll) {
+ if (m_decoder)
+ m_decoder->clearFrameBufferCache(clearBeforeFrame);
+ return;
+ }
+
delete m_decoder;
m_decoder = 0;
+ if (data)
+ setData(data, allDataReceived);
}
bool ImageSource::initialized() const
@@ -126,6 +134,14 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
m_decoder->setData(data, allDataReceived);
}
+String ImageSource::filenameExtension() const
+{
+ if (!m_decoder)
+ return String();
+
+ return m_decoder->filenameExtension();
+}
+
bool ImageSource::isSizeAvailable()
{
if (!m_decoder)
diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp
index 3f8d588..24354d2 100644
--- a/WebCore/platform/graphics/cairo/PathCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -4,6 +4,7 @@
2004, 2005, 2006 Rob Buis <buis@kde.org>
2005, 2007 Apple Inc. All Rights reserved.
2007 Alp Toker <alp@atoker.com>
+ 2008 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,11 +25,13 @@
#include "config.h"
#include "Path.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "CairoPath.h"
#include "FloatRect.h"
+#include "GraphicsContext.h"
#include "NotImplemented.h"
#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
#include <cairo.h>
#include <math.h>
@@ -153,9 +156,78 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlo
void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
{
- // FIXME: cairo_arc_to not yet in cairo see cairo.h
- // cairo_arc_to(m_cr, p1.x(), p1.y(), p2.x(), p2.y());
- notImplemented();
+ if (isEmpty())
+ return;
+
+ cairo_t* cr = platformPath()->m_cr;
+
+ double x0, y0;
+ cairo_get_current_point(cr, &x0, &y0);
+ FloatPoint p0(x0, y0);
+ if ((p1.x() == p0.x() && p1.y() == p0.y()) || (p1.x() == p2.x() && p1.y() == p2.y()) || radius == 0.f) {
+ cairo_line_to(cr, p1.x(), p1.y());
+ return;
+ }
+
+ 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());
+
+ double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+ // all points on a line logic
+ if (cos_phi == -1) {
+ cairo_line_to(cr, p1.x(), p1.y());
+ return;
+ }
+ if (cos_phi == 1) {
+ // add infinite far away point
+ unsigned int max_length = 65535;
+ double factor_max = max_length / p1p0_length;
+ FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y()));
+ cairo_line_to(cr, ep.x(), ep.y());
+ return;
+ }
+
+ float tangent = radius / tan(acos(cos_phi) / 2);
+ float factor_p1p0 = tangent / p1p0_length;
+ FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+ FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+ float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+ float factor_ra = radius / orth_p1p0_length;
+
+ // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+ double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ if (cos_alpha < 0.f)
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+ FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+ // calculate angles for addArc
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+ float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+ if (orth_p1p0.y() < 0.f)
+ sa = 2 * piDouble - sa;
+
+ // anticlockwise logic
+ bool anticlockwise = false;
+
+ 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()));
+ 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)
+ ea = 2 * piDouble - ea;
+ if ((sa > ea) && ((sa - ea) < piDouble))
+ anticlockwise = true;
+ if ((sa < ea) && ((ea - sa) > piDouble))
+ anticlockwise = true;
+
+ cairo_line_to(cr, t_p1p0.x(), t_p1p0.y());
+
+ addArc(p, radius, sa, ea, anticlockwise);
}
void Path::addEllipse(const FloatRect& rect)
@@ -188,6 +260,19 @@ FloatRect Path::boundingRect() const
return FloatRect(x0, y0, x1 - x0, y1 - y0);
}
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ if (applier) {
+ GraphicsContext gc(cr);
+ applier->strokeStyle(&gc);
+ }
+
+ double x0, x1, y0, y1;
+ cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
+ return FloatRect(x0, y0, x1 - x0, y1 - y0);
+}
+
bool Path::contains(const FloatPoint& point, WindRule rule) const
{
if (!boundingRect().contains(point))
@@ -201,6 +286,16 @@ bool Path::contains(const FloatPoint& point, WindRule rule) const
return contains;
}
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+ cairo_t* cr = platformPath()->m_cr;
+ GraphicsContext gc(cr);
+ applier->strokeStyle(&gc);
+
+ return cairo_in_stroke(cr, point.x(), point.y());
+}
+
void Path::apply(void* info, PathApplierFunction function) const
{
cairo_t* cr = platformPath()->m_cr;
@@ -239,7 +334,7 @@ void Path::apply(void* info, PathApplierFunction function) const
cairo_path_destroy(path);
}
-void Path::transform(const AffineTransform& trans)
+void Path::transform(const TransformationMatrix& trans)
{
cairo_t* m_cr = platformPath()->m_cr;
cairo_matrix_t c_matrix = cairo_matrix_t(trans);
@@ -249,37 +344,39 @@ void Path::transform(const AffineTransform& trans)
String Path::debugString() const
{
- String string = "";
+ if (isEmpty())
+ return String();
+
+ String pathString;
cairo_path_t* path = cairo_copy_path(platformPath()->m_cr);
cairo_path_data_t* data;
- if (!path->num_data )
- string = "EMPTY";
-
for (int i = 0; i < path->num_data; i += path->data[i].header.length) {
data = &path->data[i];
switch (data->header.type) {
case CAIRO_PATH_MOVE_TO:
- string += String::format("M %.2f,%.2f",
+ if (i < (path->num_data - path->data[i].header.length))
+ pathString += String::format("M%.2f,%.2f ",
data[1].point.x, data[1].point.y);
break;
case CAIRO_PATH_LINE_TO:
- string += String::format("L %.2f,%.2f",
+ pathString += String::format("L%.2f,%.2f ",
data[1].point.x, data[1].point.y);
break;
case CAIRO_PATH_CURVE_TO:
- string += String::format("C %.2f,%.2f,%.2f,%.2f,%.2f,%.2f",
+ pathString += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ",
data[1].point.x, data[1].point.y,
data[2].point.x, data[2].point.y,
data[3].point.x, data[3].point.y);
break;
case CAIRO_PATH_CLOSE_PATH:
- string += "X";
+ pathString += "Z ";
break;
}
}
+
cairo_path_destroy(path);
- return string;
+ return pathString.simplifyWhiteSpace();
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/cairo/PatternCairo.cpp b/WebCore/platform/graphics/cairo/PatternCairo.cpp
index 16cebf8..7d75db3 100644
--- a/WebCore/platform/graphics/cairo/PatternCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PatternCairo.cpp
@@ -26,21 +26,22 @@
#include "config.h"
#include "Pattern.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "GraphicsContext.h"
#include <cairo.h>
namespace WebCore {
-cairo_pattern_t* Pattern::createPlatformPattern(const AffineTransform& patternTransform) const
+cairo_pattern_t* Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const
{
cairo_surface_t* surface = tileImage()->nativeImageForCurrentFrame();
if (!surface)
return 0;
cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
- const cairo_matrix_t* pattern_matrix = reinterpret_cast<const cairo_matrix_t*>(&patternTransform);
+ const TransformationMatrix& inverse = patternTransform.inverse();
+ const cairo_matrix_t* pattern_matrix = reinterpret_cast<const cairo_matrix_t*>(&inverse);
cairo_pattern_set_matrix(pattern, pattern_matrix);
if (m_repeatX || m_repeatY)
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
diff --git a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
index 0f2fccd..b78620f 100644
--- a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp
+++ b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp
@@ -23,7 +23,7 @@
*/
#include "config.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "IntRect.h"
#include "FloatRect.h"
@@ -34,34 +34,34 @@ namespace WebCore {
static const double deg2rad = 0.017453292519943295769; // pi/180
-AffineTransform::AffineTransform()
+TransformationMatrix::TransformationMatrix()
{
cairo_matrix_init_identity(&m_transform);
}
-AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
{
cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
}
-AffineTransform::AffineTransform(const PlatformAffineTransform& matrix)
+TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
{
m_transform = matrix;
}
-void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
+void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
{
cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
}
-void AffineTransform::map(double x, double y, double* x2, double* y2) const
+void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
{
*x2 = x;
*y2 = y;
cairo_matrix_transform_point(&m_transform, x2, y2);
}
-IntRect AffineTransform::mapRect(const IntRect &rect) const
+IntRect TransformationMatrix::mapRect(const IntRect &rect) const
{
FloatRect floatRect(rect);
FloatRect enclosingFloatRect = this->mapRect(floatRect);
@@ -69,7 +69,7 @@ IntRect AffineTransform::mapRect(const IntRect &rect) const
return enclosingIntRect(enclosingFloatRect);
}
-FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
{
double rectMinX = rect.x();
double rectMaxX = rect.x() + rect.width();
@@ -128,97 +128,97 @@ FloatRect AffineTransform::mapRect(const FloatRect &rect) const
return FloatRect(enclosingRectMinX, enclosingRectMinY, enclosingRectWidth, enclosingRectHeight);
}
-bool AffineTransform::isIdentity() const
+bool TransformationMatrix::isIdentity() const
{
return ((m_transform.xx == 1) && (m_transform.yy == 1)
&& (m_transform.xy == 0) && (m_transform.yx == 0)
&& (m_transform.x0 == 0) && (m_transform.y0 == 0));
}
-double AffineTransform::a() const
+double TransformationMatrix::a() const
{
return m_transform.xx;
}
-void AffineTransform::setA(double a)
+void TransformationMatrix::setA(double a)
{
m_transform.xx = a;
}
-double AffineTransform::b() const
+double TransformationMatrix::b() const
{
return m_transform.yx;
}
-void AffineTransform::setB(double b)
+void TransformationMatrix::setB(double b)
{
m_transform.yx = b;
}
-double AffineTransform::c() const
+double TransformationMatrix::c() const
{
return m_transform.xy;
}
-void AffineTransform::setC(double c)
+void TransformationMatrix::setC(double c)
{
m_transform.xy = c;
}
-double AffineTransform::d() const
+double TransformationMatrix::d() const
{
return m_transform.yy;
}
-void AffineTransform::setD(double d)
+void TransformationMatrix::setD(double d)
{
m_transform.yy = d;
}
-double AffineTransform::e() const
+double TransformationMatrix::e() const
{
return m_transform.x0;
}
-void AffineTransform::setE(double e)
+void TransformationMatrix::setE(double e)
{
m_transform.x0 = e;
}
-double AffineTransform::f() const
+double TransformationMatrix::f() const
{
return m_transform.y0;
}
-void AffineTransform::setF(double f)
+void TransformationMatrix::setF(double f)
{
m_transform.y0 = f;
}
-void AffineTransform::reset()
+void TransformationMatrix::reset()
{
cairo_matrix_init_identity(&m_transform);
}
-AffineTransform &AffineTransform::scale(double sx, double sy)
+TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
{
cairo_matrix_scale(&m_transform, sx, sy);
return *this;
}
-AffineTransform &AffineTransform::rotate(double d)
+TransformationMatrix &TransformationMatrix::rotate(double d)
{
cairo_matrix_rotate(&m_transform, d * deg2rad);
return *this;
}
-AffineTransform &AffineTransform::translate(double tx, double ty)
+TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
{
cairo_matrix_translate(&m_transform, tx, ty);
return *this;
}
-AffineTransform &AffineTransform::shear(double sx, double sy)
+TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
{
cairo_matrix_t shear;
cairo_matrix_init(&shear, 1, sy, sx, 1, 0, 0);
@@ -230,26 +230,26 @@ AffineTransform &AffineTransform::shear(double sx, double sy)
return *this;
}
-double AffineTransform::det() const
+double TransformationMatrix::det() const
{
return m_transform.xx * m_transform.yy - m_transform.xy * m_transform.yx;
}
-AffineTransform AffineTransform::inverse() const
+TransformationMatrix TransformationMatrix::inverse() const
{
- if (!isInvertible()) return AffineTransform();
+ if (!isInvertible()) return TransformationMatrix();
cairo_matrix_t result = m_transform;
cairo_matrix_invert(&result);
- return AffineTransform(result);
+ return TransformationMatrix(result);
}
-AffineTransform::operator cairo_matrix_t() const
+TransformationMatrix::operator cairo_matrix_t() const
{
return m_transform;
}
-bool AffineTransform::operator== (const AffineTransform &m2) const
+bool TransformationMatrix::operator== (const TransformationMatrix &m2) const
{
return ((m_transform.xx == m2.m_transform.xx)
&& (m_transform.yy == m2.m_transform.yy)
@@ -260,7 +260,7 @@ bool AffineTransform::operator== (const AffineTransform &m2) const
}
-AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
{
cairo_matrix_t result;
cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
@@ -269,7 +269,7 @@ AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
return *this;
}
-AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
{
cairo_matrix_t result;
cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index 3f0e6e7..1cc55a4 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -28,7 +28,7 @@
#include "config.h"
#include "GraphicsContext.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatConversion.h"
#include "GraphicsContextPrivate.h"
#include "GraphicsContextPlatformPrivateCG.h"
@@ -191,11 +191,13 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
}
CGContextRef context = platformContext();
- CGContextSaveGState(context);
-
- CGContextSetShouldAntialias(context, false);
+
+ if (shouldAntialias())
+ CGContextSetShouldAntialias(context, false);
if (patWidth) {
+ CGContextSaveGState(context);
+
// 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.
setCGFillColor(context, strokeColor()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color.
@@ -245,7 +247,11 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
CGContextStrokePath(context);
- CGContextRestoreGState(context);
+ if (patWidth)
+ CGContextRestoreGState(context);
+
+ if (shouldAntialias())
+ CGContextSetShouldAntialias(context, true);
}
// This method is only used to draw the little circles used in lists.
@@ -358,7 +364,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp
CGContextRestoreGState(context);
}
-void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool antialiased)
{
if (paintingDisabled() || !fillColor().alpha() && (strokeThickness() <= 0 || strokeStyle() == NoStroke))
return;
@@ -368,9 +374,8 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
CGContextRef context = platformContext();
- CGContextSaveGState(context);
-
- CGContextSetShouldAntialias(context, shouldAntialias);
+ if (antialiased != shouldAntialias())
+ CGContextSetShouldAntialias(context, antialiased);
CGContextBeginPath(context);
CGContextMoveToPoint(context, points[0].x(), points[0].y());
@@ -379,15 +384,16 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
CGContextClosePath(context);
drawPath();
-
- CGContextRestoreGState(context);
+
+ if (antialiased != shouldAntialias())
+ CGContextSetShouldAntialias(context, shouldAntialias());
}
-static void applyStrokePattern(GraphicsContext* context, Pattern* pattern)
+void GraphicsContext::applyStrokePattern()
{
- CGContextRef cgContext = context->platformContext();
+ CGContextRef cgContext = platformContext();
- CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM());
+ CGPatternRef platformPattern = m_common->state.strokePattern.get()->createPlatformPattern(getCTM());
if (!platformPattern)
return;
@@ -400,11 +406,11 @@ static void applyStrokePattern(GraphicsContext* context, Pattern* pattern)
CGPatternRelease(platformPattern);
}
-static void applyFillPattern(GraphicsContext* context, Pattern* pattern)
+void GraphicsContext::applyFillPattern()
{
- CGContextRef cgContext = context->platformContext();
+ CGContextRef cgContext = platformContext();
- CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM());
+ CGPatternRef platformPattern = m_common->state.fillPattern.get()->createPlatformPattern(getCTM());
if (!platformPattern)
return;
@@ -460,9 +466,9 @@ void GraphicsContext::drawPath()
}
if (state.fillColorSpace == PatternColorSpace)
- applyFillPattern(this, m_common->state.fillPattern.get());
+ applyFillPattern();
if (state.strokeColorSpace == PatternColorSpace)
- applyStrokePattern(this, m_common->state.strokePattern.get());
+ applyStrokePattern();
CGPathDrawingMode drawingMode;
if (calculateDrawingMode(state, drawingMode))
@@ -489,7 +495,7 @@ void GraphicsContext::fillPath()
fillPathWithFillRule(context, fillRule());
break;
case PatternColorSpace:
- applyFillPattern(this, m_common->state.fillPattern.get());
+ applyFillPattern();
fillPathWithFillRule(context, fillRule());
break;
case GradientColorSpace:
@@ -512,11 +518,11 @@ void GraphicsContext::strokePath()
CGContextRef context = platformContext();
switch (m_common->state.strokeColorSpace) {
case SolidColorSpace:
- if (fillColor().alpha())
+ if (strokeColor().alpha())
CGContextStrokePath(context);
break;
case PatternColorSpace:
- applyStrokePattern(this, m_common->state.strokePattern.get());
+ applyStrokePattern();
CGContextStrokePath(context);
break;
case GradientColorSpace:
@@ -540,7 +546,7 @@ void GraphicsContext::fillRect(const FloatRect& rect)
CGContextFillRect(context, rect);
break;
case PatternColorSpace:
- applyFillPattern(this, m_common->state.fillPattern.get());
+ applyFillPattern();
CGContextFillRect(context, rect);
break;
case GradientColorSpace:
@@ -614,6 +620,21 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
CGContextEOClip(platformContext());
}
+void GraphicsContext::clipPath(WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ if (!CGContextIsPathEmpty(context)) {
+ if (clipRule == RULE_EVENODD)
+ CGContextEOClip(context);
+ else
+ CGContextClip(context);
+ }
+}
+
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
{
if (paintingDisabled())
@@ -670,23 +691,30 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col
{
if (paintingDisabled())
return;
+ CGFloat width = size.width();
+ CGFloat height = size.height();
+ CGFloat blurRadius = blur;
CGContextRef context = platformContext();
- CGAffineTransform transform = CGContextGetCTM(context);
- CGFloat A = transform.a * transform.a + transform.b * transform.b;
- CGFloat B = transform.a * transform.c + transform.b * transform.d;
- CGFloat C = B;
- CGFloat D = transform.c * transform.c + transform.d * transform.d;
+ if (!m_common->state.shadowsIgnoreTransforms) {
+ CGAffineTransform transform = CGContextGetCTM(context);
- CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D)))));
+ CGFloat A = transform.a * transform.a + transform.b * transform.b;
+ CGFloat B = transform.a * transform.c + transform.b * transform.d;
+ CGFloat C = B;
+ CGFloat D = transform.c * transform.c + transform.d * transform.d;
- // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
- CGFloat blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0));
+ CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D)))));
- CGSize sizeInDeviceSpace = CGSizeApplyAffineTransform(size, transform);
+ // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
+ blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0));
- CGFloat width = sizeInDeviceSpace.width;
- CGFloat height = sizeInDeviceSpace.height;
+ CGSize sizeInDeviceSpace = CGSizeApplyAffineTransform(size, transform);
+
+ width = sizeInDeviceSpace.width;
+ height = sizeInDeviceSpace.height;
+
+ }
// Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated
// to the desired integer.
@@ -747,7 +775,27 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth)
{
if (paintingDisabled())
return;
- CGContextStrokeRectWithWidth(platformContext(), r, lineWidth);
+
+ CGContextRef context = platformContext();
+ switch (m_common->state.strokeColorSpace) {
+ case SolidColorSpace:
+ if (strokeColor().alpha())
+ CGContextStrokeRectWithWidth(context, r, lineWidth);
+ break;
+ case PatternColorSpace:
+ applyStrokePattern();
+ CGContextStrokeRectWithWidth(context, r, lineWidth);
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ setStrokeThickness(lineWidth);
+ CGContextAddRect(context, r);
+ CGContextReplacePathWithStrokedPath(context);
+ CGContextClip(context);
+ CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
+ }
}
void GraphicsContext::setLineCap(LineCap cap)
@@ -848,7 +896,7 @@ void GraphicsContext::translate(float x, float y)
m_data->m_userToDeviceTransformKnownToBeIdentity = false;
}
-void GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContext::concatCTM(const TransformationMatrix& transform)
{
if (paintingDisabled())
return;
@@ -857,7 +905,7 @@ void GraphicsContext::concatCTM(const AffineTransform& transform)
m_data->m_userToDeviceTransformKnownToBeIdentity = false;
}
-AffineTransform GraphicsContext::getCTM() const
+TransformationMatrix GraphicsContext::getCTM() const
{
return CGContextGetCTM(platformContext());
}
@@ -909,8 +957,6 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri
if (width <= 0)
return;
- CGContextSaveGState(platformContext());
-
float x = point.x();
float y = point.y();
float lineLength = width;
@@ -919,6 +965,8 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri
// See http://bugs.webkit.org/show_bug.cgi?id=4255 for details of why 0.5 is the right minimum thickness to use.
float thickness = max(strokeThickness(), 0.5f);
+ bool restoreAntialiasMode = false;
+
if (!printing) {
// On screen, use a minimum thickness of 1.0 in user space (later rounded to an integral number in device space).
float adjustedThickness = max(thickness, 1.0f);
@@ -933,15 +981,21 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri
y = lineRect.origin.y;
lineLength = lineRect.size.width;
thickness = lineRect.size.height;
- CGContextSetShouldAntialias(platformContext(), false);
+ if (shouldAntialias()) {
+ CGContextSetShouldAntialias(platformContext(), false);
+ restoreAntialiasMode = true;
+ }
}
}
if (fillColor() != strokeColor())
setCGFillColor(platformContext(), strokeColor());
CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness));
-
- CGContextRestoreGState(platformContext());
+ if (fillColor() != strokeColor())
+ setCGFillColor(platformContext(), fillColor());
+
+ if (restoreAntialiasMode)
+ CGContextSetShouldAntialias(platformContext(), true);
}
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
@@ -1078,7 +1132,7 @@ void GraphicsContext::setPlatformFillColor(const Color& color)
setCGFillColor(platformContext(), color);
}
-void GraphicsContext::setUseAntialiasing(bool enable)
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
{
if (paintingDisabled())
return;
diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
index 8827ff7..beee660 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
+++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
@@ -34,6 +34,7 @@ public:
#if PLATFORM(WIN)
, m_hdc(0)
, m_transparencyCount(0)
+ , m_shouldIncludeChildWindows(false)
#endif
, m_userToDeviceTransformKnownToBeIdentity(false)
{
@@ -54,7 +55,7 @@ public:
void scale(const FloatSize&) {}
void rotate(float) {}
void translate(float, float) {}
- void concatCTM(const AffineTransform&) {}
+ void concatCTM(const TransformationMatrix&) {}
void beginTransparencyLayer() {}
void endTransparencyLayer() {}
#endif
@@ -68,12 +69,13 @@ public:
void scale(const FloatSize&);
void rotate(float);
void translate(float, float);
- void concatCTM(const AffineTransform&);
+ void concatCTM(const TransformationMatrix&);
void beginTransparencyLayer() { m_transparencyCount++; }
void endTransparencyLayer() { m_transparencyCount--; }
HDC m_hdc;
unsigned m_transparencyCount;
+ bool m_shouldIncludeChildWindows;
#endif
CGContextRef m_cgContext;
diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
index 502313b..96e5604 100644
--- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -107,7 +107,7 @@ Image* ImageBuffer::image() const
PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
{
PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
- unsigned char* data = result->data()->data().data();
+ unsigned char* data = result->data()->data()->data();
if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
memset(data, 0, result->data()->length());
@@ -188,7 +188,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con
unsigned srcBytesPerRow = 4 * source->width();
unsigned destBytesPerRow = 4 * m_size.width();
- unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4;
+ unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4;
unsigned char* destRows = reinterpret_cast<unsigned char*>(m_data.m_data) + desty * destBytesPerRow + destx * 4;
for (int y = 0; y < numRows; ++y) {
for (int x = 0; x < numColumns; x++) {
diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp
index 8609c46..13c8c07 100644
--- a/WebCore/platform/graphics/cg/ImageCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -28,7 +28,7 @@
#if PLATFORM(CG)
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatConversion.h"
#include "FloatRect.h"
#include "GraphicsContext.h"
@@ -47,15 +47,17 @@
namespace WebCore {
-void FrameData::clear()
+bool FrameData::clear(bool clearMetadata)
{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
if (m_frame) {
CGImageRelease(m_frame);
m_frame = 0;
- // NOTE: We purposefully don't reset metadata here, so that even if we
- // throw away previously-decoded data, animation loops can still access
- // properties like frame durations without re-decoding.
+ return true;
}
+ return false;
}
// ================================================
@@ -207,7 +209,7 @@ void Image::drawPatternCallback(void* info, CGContextRef context)
CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect(0, 0, CGImageGetWidth(image), CGImageGetHeight(image))), image);
}
-void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
if (!nativeImageForCurrentFrame())
@@ -251,9 +253,14 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const
// its buffer is the same size as the overall image. Because a partially decoded CGImageRef with a smaller width or height than the
// overall image buffer needs to tile with "gaps", we can't use the optimized tiling call in that case.
// FIXME: Could create WebKitSystemInterface SPI for CGCreatePatternWithImage2 and probably make Tiger tile faster as well.
+ // FIXME: We cannot use CGContextDrawTiledImage with scaled tiles on Leopard, because it suffers from rounding errors. Snow Leopard is ok.
float scaledTileWidth = tileRect.width() * narrowPrecisionToFloat(patternTransform.a());
float w = CGImageGetWidth(tileImage);
+#ifdef BUILDING_ON_LEOPARD
+ if (w == size().width() && h == size().height() && scaledTileWidth == tileRect.width() && scaledTileHeight == tileRect.height())
+#else
if (w == size().width() && h == size().height())
+#endif
CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage);
else {
#endif
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
index 73907c9..0b276cc 100644
--- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -27,8 +27,10 @@
#include "ImageSource.h"
#if PLATFORM(CG)
+#include "ImageSourceCG.h"
#include "IntSize.h"
+#include "MIMETypeRegistry.h"
#include "SharedBuffer.h"
#include <ApplicationServices/ApplicationServices.h>
@@ -43,18 +45,23 @@ ImageSource::ImageSource()
ImageSource::~ImageSource()
{
- clear();
+ clear(true);
}
-void ImageSource::clear()
+void ImageSource::clear(bool, size_t, SharedBuffer* data, bool allDataReceived)
{
+ // We always destroy the decoder, because there is no API to get it to
+ // selectively release some of the frames it's holding, and if we don't
+ // release any of them, we use too much memory on large images.
if (m_decoder) {
CFRelease(m_decoder);
m_decoder = 0;
}
+ if (data)
+ setData(data, allDataReceived);
}
-CFDictionaryRef imageSourceOptions()
+static CFDictionaryRef imageSourceOptions()
{
static CFDictionaryRef options;
@@ -89,6 +96,14 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
CFRelease(cfData);
}
+String ImageSource::filenameExtension() const
+{
+ if (!m_decoder)
+ return String();
+ CFStringRef imageSourceType = CGImageSourceGetType(m_decoder);
+ return WebCore::preferredExtensionForImageSourceType(imageSourceType);
+}
+
bool ImageSource::isSizeAvailable()
{
bool result = false;
@@ -210,7 +225,7 @@ float ImageSource::frameDurationAtIndex(size_t index)
return duration;
}
-bool ImageSource::frameHasAlphaAtIndex(size_t index)
+bool ImageSource::frameHasAlphaAtIndex(size_t)
{
// Might be interesting to do this optimization on Mac some day, but for now we're just using this
// for the Cairo source, since it uses our decoders, and our decoders can answer this question.
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.h b/WebCore/platform/graphics/cg/ImageSourceCG.h
new file mode 100644
index 0000000..d5b4b5a
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageSourceCG_h
+#define ImageSourceCG_h
+
+#include "ImageSource.h"
+
+namespace WebCore {
+
+class String;
+
+String preferredExtensionForImageSourceType(const String& type);
+
+String MIMETypeForImageSourceType(const String& type);
+
+}
+
+#endif // ImageSourceCG_h
diff --git a/WebCore/platform/graphics/cg/ImageSourceCGMac.mm b/WebCore/platform/graphics/cg/ImageSourceCGMac.mm
new file mode 100644
index 0000000..297e30a
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageSourceCGMac.mm
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008, 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "ImageSourceCG.h"
+
+#import "PlatformString.h"
+#import "wtf/RetainPtr.h"
+
+namespace WebCore {
+
+String MIMETypeForImageSourceType(const String& uti)
+{
+ RetainPtr<CFStringRef> utiref(AdoptCF, uti.createCFString());
+ RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(utiref.get(), kUTTagClassMIMEType));
+ return mime.get();
+}
+
+String preferredExtensionForImageSourceType(const String& uti)
+{
+ RetainPtr<CFStringRef> type(AdoptCF, uti.createCFString());
+ RetainPtr<CFStringRef> extension(AdoptCF, UTTypeCopyPreferredTagWithClass(type.get(), kUTTagClassFilenameExtension));
+ return extension.get();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp b/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp
new file mode 100644
index 0000000..c7d9a0b
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageSourceCG.h"
+
+#include "StdLibExtras.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+String MIMETypeForImageSourceType(const String& type)
+{
+ String mimeType;
+ // FIXME: This approach of taking a UTI like public.type and giving back
+ // a MIME type like image/type will work for common image UTIs like jpeg,
+ // png, tiff, gif but won't work for UTIs like: public.jpeg-2000,
+ // public.xbitmap-image, com.apple.quicktime-image, and others.
+ if (int dotLocation = type.reverseFind('.'))
+ mimeType = "image/" + type.substring(dotLocation + 1);
+ return mimeType;
+}
+
+String preferredExtensionForImageSourceType(const String& type)
+{
+ if (type.isEmpty())
+ return String();
+
+ typedef HashMap<String, String> StringMap;
+ DEFINE_STATIC_LOCAL(StringMap, UTIMap, ());
+ if (UTIMap.isEmpty()) {
+ UTIMap.add("public.html", "html");
+ UTIMap.add("public.jpeg", "jpeg");
+ UTIMap.add("public.jpeg-2000", "jp2");
+ UTIMap.add("public.plain-text", "txt");
+ UTIMap.add("public.png", "png");
+ UTIMap.add("public.tiff", "tiff");
+ UTIMap.add("public.xbitmap-image", "xbm");
+ UTIMap.add("public.xml", "xml");
+ UTIMap.add("com.adobe.illustrator.ai-image", "ai");
+ UTIMap.add("com.adobe.pdf", "pdf");
+ UTIMap.add("com.adobe.photoshop-image", "psd");
+ UTIMap.add("com.adobe.postscript", "ps");
+ UTIMap.add("com.apple.icns", "icns");
+ UTIMap.add("com.apple.macpaint-image", "pntg");
+ UTIMap.add("com.apple.pict", "pict");
+ UTIMap.add("com.apple.quicktime-image", "qtif");
+ UTIMap.add("com.apple.webarchive", "webarchive");
+ UTIMap.add("com.compuserve.gif", "gif");
+ UTIMap.add("com.ilm.openexr-image", "exr");
+ UTIMap.add("com.kodak.flashpix-image", "fpx");
+ UTIMap.add("com.microsoft.bmp", "bmp");
+ UTIMap.add("com.microsoft.ico", "ico");
+ UTIMap.add("com.netscape.javascript-source", "js");
+ UTIMap.add("com.sgi.sgi-image", "sgi");
+ UTIMap.add("com.truevision.tga-image", "tga");
+ }
+ return UTIMap.get(type);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h
index 5c9d4e1..130c12c 100644
--- a/WebCore/platform/graphics/cg/PDFDocumentImage.h
+++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h
@@ -42,7 +42,9 @@ namespace WebCore {
{
return adoptRef(new PDFDocumentImage);
}
- ~PDFDocumentImage();
+
+ private:
+ virtual ~PDFDocumentImage();
virtual bool hasSingleSecurityOrigin() const { return true; }
@@ -50,12 +52,11 @@ namespace WebCore {
// FIXME: PDF Images are underreporting decoded sizes and will be unable
// to prune because these functions are not implemented yet.
- virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) { }
+ virtual void destroyDecodedData(bool /*destroyAll*/ = true) { }
virtual unsigned decodedSize() const { return 0; }
virtual IntSize size() const;
- private:
PDFDocumentImage();
virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp
index 1382589..ebd0359 100644
--- a/WebCore/platform/graphics/cg/PathCG.cpp
+++ b/WebCore/platform/graphics/cg/PathCG.cpp
@@ -29,16 +29,43 @@
#if PLATFORM(CG)
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include <ApplicationServices/ApplicationServices.h>
#include "FloatRect.h"
+#include "GraphicsContext.h"
#include "IntRect.h"
#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
#include <wtf/MathExtras.h>
namespace WebCore {
+static size_t putBytesNowhere(void*, const void*, size_t count)
+{
+ return count;
+}
+
+static CGContextRef createScratchContext()
+{
+ CGDataConsumerCallbacks callbacks = { putBytesNowhere, 0 };
+ CGDataConsumerRef consumer = CGDataConsumerCreate(0, &callbacks);
+ CGContextRef context = CGPDFContextCreate(consumer, 0, 0);
+ CGDataConsumerRelease(consumer);
+
+ CGFloat black[4] = { 0, 0, 0, 1 };
+ CGContextSetFillColor(context, black);
+ CGContextSetStrokeColor(context, black);
+
+ return context;
+}
+
+static inline CGContextRef scratchContext()
+{
+ static CGContextRef context = createScratchContext();
+ return context;
+}
+
Path::Path()
: m_path(CGPathCreateMutable())
{
@@ -62,7 +89,6 @@ Path& Path::operator=(const Path& other)
return *this;
}
-
static void copyClosingSubpathsApplierFunction(void* info, const CGPathElement* element)
{
CGMutablePathRef path = static_cast<CGMutablePathRef>(info);
@@ -109,6 +135,25 @@ bool Path::contains(const FloatPoint &point, WindRule rule) const
return ret;
}
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+
+ CGContextRef context = scratchContext();
+
+ CGContextSaveGState(context);
+ CGContextBeginPath(context);
+ CGContextAddPath(context, platformPath());
+
+ GraphicsContext gc(context);
+ applier->strokeStyle(&gc);
+
+ bool hitSuccess = CGContextPathContainsPoint(context, point, kCGPathStroke);
+ CGContextRestoreGState(context);
+
+ return hitSuccess;
+}
+
void Path::translate(const FloatSize& size)
{
CGAffineTransform translation = CGAffineTransformMake(1, 0, 0, 1, size.width(), size.height());
@@ -123,6 +168,26 @@ FloatRect Path::boundingRect() const
return CGPathGetBoundingBox(m_path);
}
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ CGContextRef context = scratchContext();
+
+ CGContextSaveGState(context);
+ CGContextBeginPath(context);
+ CGContextAddPath(context, platformPath());
+
+ if (applier) {
+ GraphicsContext graphicsContext(context);
+ applier->strokeStyle(&graphicsContext);
+ }
+
+ CGContextReplacePathWithStrokedPath(context);
+ CGRect box = CGContextIsPathEmpty(context) ? CGRectZero : CGContextGetPathBoundingBox(context);
+ CGContextRestoreGState(context);
+
+ return box;
+}
+
void Path::moveTo(const FloatPoint& point)
{
CGPathMoveToPoint(m_path, 0, point.x(), point.y());
@@ -184,8 +249,8 @@ bool Path::isEmpty() const
static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *element)
{
- CFMutableStringRef string = (CFMutableStringRef)info;
- CFStringRef typeString = CFSTR("");
+ CFMutableStringRef string = static_cast<CFMutableStringRef>(info);
+
CGPoint* points = element->points;
switch (element->type) {
case kCGPathElementMoveToPoint:
@@ -204,7 +269,8 @@ static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *ele
points[2].x, points[2].y);
break;
case kCGPathElementCloseSubpath:
- typeString = CFSTR("X"); break;
+ CFStringAppendFormat(string, 0, CFSTR("Z "));
+ break;
}
}
@@ -241,7 +307,7 @@ struct PathApplierInfo {
PathApplierFunction function;
};
-void CGPathApplierToPathApplier(void *info, const CGPathElement *element)
+static void CGPathApplierToPathApplier(void *info, const CGPathElement *element)
{
PathApplierInfo* pinfo = (PathApplierInfo*)info;
FloatPoint points[3];
@@ -277,7 +343,7 @@ void Path::apply(void* info, PathApplierFunction function) const
CGPathApply(m_path, &pinfo, CGPathApplierToPathApplier);
}
-void Path::transform(const AffineTransform& transform)
+void Path::transform(const TransformationMatrix& transform)
{
CGMutablePathRef path = CGPathCreateMutable();
CGAffineTransform transformCG = transform;
diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp
index e1f7a69..2b9c12f 100644
--- a/WebCore/platform/graphics/cg/PatternCG.cpp
+++ b/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -27,7 +27,7 @@
#include "config.h"
#include "Pattern.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "GraphicsContext.h"
#include <ApplicationServices/ApplicationServices.h>
@@ -50,11 +50,11 @@ static void patternReleaseCallback(void* info)
static_cast<Image*>(info)->deref();
}
-CGPatternRef Pattern::createPlatformPattern(const AffineTransform& transform) const
+CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& transform) const
{
IntRect tileRect = tileImage()->rect();
- AffineTransform patternTransform = transform;
+ TransformationMatrix patternTransform = transform;
patternTransform.scale(1, -1);
patternTransform.translate(0, -tileRect.height());
diff --git a/WebCore/platform/graphics/cg/AffineTransformCG.cpp b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
index 4f0bca0..9b3181a 100644
--- a/WebCore/platform/graphics/cg/AffineTransformCG.cpp
+++ b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp
@@ -24,7 +24,7 @@
*/
#include "config.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#if PLATFORM(CG)
@@ -36,12 +36,12 @@
namespace WebCore {
-AffineTransform::AffineTransform()
+TransformationMatrix::TransformationMatrix()
: m_transform(CGAffineTransformIdentity)
{
}
-AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
{
m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
narrowPrecisionToCGFloat(b),
@@ -51,12 +51,12 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double
narrowPrecisionToCGFloat(ty));
}
-AffineTransform::AffineTransform(const PlatformAffineTransform& t)
+TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& t)
: m_transform(t)
{
}
-void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
+void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
{
m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
narrowPrecisionToCGFloat(b),
@@ -66,147 +66,147 @@ void AffineTransform::setMatrix(double a, double b, double c, double d, double t
narrowPrecisionToCGFloat(ty));
}
-void AffineTransform::map(double x, double y, double *x2, double *y2) const
+void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
{
CGPoint result = CGPointApplyAffineTransform(CGPointMake(narrowPrecisionToCGFloat(x), narrowPrecisionToCGFloat(y)), m_transform);
*x2 = result.x;
*y2 = result.y;
}
-IntRect AffineTransform::mapRect(const IntRect &rect) const
+IntRect TransformationMatrix::mapRect(const IntRect &rect) const
{
return enclosingIntRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
}
-FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
{
return FloatRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
}
-bool AffineTransform::isIdentity() const
+bool TransformationMatrix::isIdentity() const
{
return CGAffineTransformIsIdentity(m_transform);
}
-double AffineTransform::a() const
+double TransformationMatrix::a() const
{
return m_transform.a;
}
-void AffineTransform::setA(double a)
+void TransformationMatrix::setA(double a)
{
m_transform.a = narrowPrecisionToCGFloat(a);
}
-double AffineTransform::b() const
+double TransformationMatrix::b() const
{
return m_transform.b;
}
-void AffineTransform::setB(double b)
+void TransformationMatrix::setB(double b)
{
m_transform.b = narrowPrecisionToCGFloat(b);
}
-double AffineTransform::c() const
+double TransformationMatrix::c() const
{
return m_transform.c;
}
-void AffineTransform::setC(double c)
+void TransformationMatrix::setC(double c)
{
m_transform.c = narrowPrecisionToCGFloat(c);
}
-double AffineTransform::d() const
+double TransformationMatrix::d() const
{
return m_transform.d;
}
-void AffineTransform::setD(double d)
+void TransformationMatrix::setD(double d)
{
m_transform.d = narrowPrecisionToCGFloat(d);
}
-double AffineTransform::e() const
+double TransformationMatrix::e() const
{
return m_transform.tx;
}
-void AffineTransform::setE(double e)
+void TransformationMatrix::setE(double e)
{
m_transform.tx = narrowPrecisionToCGFloat(e);
}
-double AffineTransform::f() const
+double TransformationMatrix::f() const
{
return m_transform.ty;
}
-void AffineTransform::setF(double f)
+void TransformationMatrix::setF(double f)
{
m_transform.ty = narrowPrecisionToCGFloat(f);
}
-void AffineTransform::reset()
+void TransformationMatrix::reset()
{
m_transform = CGAffineTransformIdentity;
}
-AffineTransform &AffineTransform::scale(double sx, double sy)
+TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
{
m_transform = CGAffineTransformScale(m_transform, narrowPrecisionToCGFloat(sx), narrowPrecisionToCGFloat(sy));
return *this;
}
-AffineTransform &AffineTransform::rotate(double d)
+TransformationMatrix &TransformationMatrix::rotate(double d)
{
m_transform = CGAffineTransformRotate(m_transform, narrowPrecisionToCGFloat(deg2rad(d)));
return *this;
}
-AffineTransform &AffineTransform::translate(double tx, double ty)
+TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
{
m_transform = CGAffineTransformTranslate(m_transform, narrowPrecisionToCGFloat(tx), narrowPrecisionToCGFloat(ty));
return *this;
}
-AffineTransform &AffineTransform::shear(double sx, double sy)
+TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
{
CGAffineTransform shear = CGAffineTransformMake(1.0f, narrowPrecisionToCGFloat(sy), narrowPrecisionToCGFloat(sx), 1.0f, 0.0f, 0.0f);
m_transform = CGAffineTransformConcat(shear, m_transform);
return *this;
}
-double AffineTransform::det() const
+double TransformationMatrix::det() const
{
return m_transform.a * m_transform.d - m_transform.b * m_transform.c;
}
-AffineTransform AffineTransform::inverse() const
+TransformationMatrix TransformationMatrix::inverse() const
{
if (isInvertible())
- return AffineTransform(CGAffineTransformInvert(m_transform));
- return AffineTransform();
+ return TransformationMatrix(CGAffineTransformInvert(m_transform));
+ return TransformationMatrix();
}
-AffineTransform::operator PlatformAffineTransform() const
+TransformationMatrix::operator PlatformTransformationMatrix() const
{
return m_transform;
}
-bool AffineTransform::operator== (const AffineTransform &m2) const
+bool TransformationMatrix::operator== (const TransformationMatrix &m2) const
{
return CGAffineTransformEqualToTransform(m_transform, CGAffineTransform(m2));
}
-AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2)
{
m_transform = CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
return *this;
}
-AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2)
{
return CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
}
diff --git a/WebCore/platform/graphics/chromium/ColorChromium.cpp b/WebCore/platform/graphics/chromium/ColorChromium.cpp
new file mode 100644
index 0000000..16ca17d
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/ColorChromium.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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"
+
+namespace WebCore {
+
+Color focusRingColor()
+{
+// FIXME: This should be split up to ColorChromiumWin and ColorChromiumMac.
+#if PLATFORM(DARWIN)
+ // 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.
+ //
+ // TODO: 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;
+#else
+ static Color focusRingColor(229, 151, 0, 255);
+ return focusRingColor;
+#endif
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
new file mode 100644
index 0000000..03583a0
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "FontUtilsChromiumWin.h"
+#include "HashMap.h"
+#include "HashSet.h"
+#include "SimpleFontData.h"
+#include "StringHash.h"
+#include <unicode/uniset.h>
+
+#include <windows.h>
+#include <objidl.h>
+#include <mlang.h>
+
+using std::min;
+
+namespace WebCore
+{
+
+void FontCache::platformInit()
+{
+ // Not needed on Windows.
+}
+
+// FIXME: consider adding to WebKit String class
+static bool charactersAreAllASCII(const String& s)
+{
+ return charactersAreAllASCII(s.characters(), s.length());
+}
+
+// When asked for a CJK font with a native name under a non-CJK locale or
+// asked for a CJK font with a Romanized name under a CJK locale,
+// |GetTextFace| (after |CreateFont*|) returns a 'bogus' value (e.g. Arial).
+// This is not consistent with what MSDN says !!
+// Therefore, before we call |CreateFont*|, we have to map a Romanized name to
+// the corresponding native name under a CJK locale and vice versa
+// under a non-CJK locale.
+// See the corresponding gecko bugs at
+// https://bugzilla.mozilla.org/show_bug.cgi?id=373952
+// https://bugzilla.mozilla.org/show_bug.cgi?id=231426
+static bool LookupAltName(const String& name, String& altName)
+{
+ struct FontCodepage {
+ WCHAR* name;
+ int codePage;
+ };
+
+ struct NamePair {
+ WCHAR* name;
+ FontCodepage altNameCodepage;
+ };
+
+ const int japaneseCodepage = 932;
+ const int simplifiedChineseCodepage = 936;
+ const int koreanCodepage = 949;
+ const int traditionalChineseCodepage = 950;
+
+ // FIXME(jungshik) : This list probably covers 99% of cases.
+ // To cover the remaining 1% and cut down the file size,
+ // consider accessing 'NAME' table of a truetype font
+ // using |GetFontData| and caching the mapping.
+ // In the table below, the ASCII keys are all lower-cased for
+ // case-insensitive matching.
+ static const NamePair namePairs[] = {
+ // MS Pゴシック, MS PGothic
+ {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", {L"MS PGothic", japaneseCodepage}},
+ {L"ms pgothic", {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", japaneseCodepage}},
+ // MS P明朝, MS PMincho
+ {L"\xFF2D\xFF33 \xFF30\x660E\x671D", {L"MS PMincho", japaneseCodepage}},
+ {L"ms pmincho", {L"\xFF2D\xFF33 \xFF30\x660E\x671D", japaneseCodepage}},
+ // MSゴシック, MS Gothic
+ {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", {L"MS Gothic", japaneseCodepage}},
+ {L"ms gothic", {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", japaneseCodepage}},
+ // MS 明朝, MS Mincho
+ {L"\xFF2D\xFF33 \x660E\x671D", {L"MS Mincho", japaneseCodepage}},
+ {L"ms mincho", {L"\xFF2D\xFF33 \x660E\x671D", japaneseCodepage}},
+ // メイリオ, Meiryo
+ {L"\x30E1\x30A4\x30EA\x30AA", {L"Meiryo", japaneseCodepage}},
+ {L"meiryo", {L"\x30E1\x30A4\x30EA\x30AA", japaneseCodepage}},
+ // 바탕, Batang
+ {L"\xBC14\xD0D5", {L"Batang", koreanCodepage}},
+ {L"batang", {L"\xBC14\xD0D5", koreanCodepage}},
+ // 바탕체, Batangche
+ {L"\xBC14\xD0D5\xCCB4", {L"Batangche", koreanCodepage}},
+ {L"batangche", {L"\xBC14\xD0D5\xCCB4", koreanCodepage}},
+ // 굴림, Gulim
+ {L"\xAD74\xB9BC", {L"Gulim", koreanCodepage}},
+ {L"gulim", {L"\xAD74\xB9BC", koreanCodepage}},
+ // 굴림체, Gulimche
+ {L"\xAD74\xB9BC\xCCB4", {L"Gulimche", koreanCodepage}},
+ {L"gulimche", {L"\xAD74\xB9BC\xCCB4", koreanCodepage}},
+ // 돋움, Dotum
+ {L"\xB3CB\xC6C0", {L"Dotum", koreanCodepage}},
+ {L"dotum", {L"\xB3CB\xC6C0", koreanCodepage}},
+ // 돋움체, Dotumche
+ {L"\xB3CB\xC6C0\xCCB4", {L"Dotumche", koreanCodepage}},
+ {L"dotumche", {L"\xB3CB\xC6C0\xCCB4", koreanCodepage}},
+ // 궁서, Gungsuh
+ {L"\xAD81\xC11C", {L"Gungsuh", koreanCodepage}},
+ {L"gungsuh", {L"\xAD81\xC11C", koreanCodepage}},
+ // 궁서체, Gungsuhche
+ {L"\xAD81\xC11C\xCCB4", {L"Gungsuhche", koreanCodepage}},
+ {L"gungsuhche", {L"\xAD81\xC11C\xCCB4", koreanCodepage}},
+ // 맑은 고딕, Malgun Gothic
+ {L"\xB9D1\xC740 \xACE0\xB515", {L"Malgun Gothic", koreanCodepage}},
+ {L"malgun gothic", {L"\xB9D1\xC740 \xACE0\xB515", koreanCodepage}},
+ // 宋体, SimSun
+ {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}},
+ {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}},
+ // 黑体, SimHei
+ {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}},
+ {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}},
+ // 新宋体, NSimSun
+ {L"\x65B0\x5B8B\x4F53", {L"NSimSun", simplifiedChineseCodepage}},
+ {L"nsimsun", {L"\x65B0\x5B8B\x4F53", simplifiedChineseCodepage}},
+ // 微软雅黑, Microsoft Yahei
+ {L"\x5FAE\x8F6F\x96C5\x9ED1", {L"Microsoft Yahei", simplifiedChineseCodepage}},
+ {L"microsoft yahei", {L"\x5FAE\x8F6F\x96C5\x9ED1", simplifiedChineseCodepage}},
+ // 仿宋, FangSong
+ {L"\x4EFF\x5B8B", {L"FangSong", simplifiedChineseCodepage}},
+ {L"fangsong", {L"\x4EFF\x5B8B", simplifiedChineseCodepage}},
+ // 楷体, KaiTi
+ {L"\x6977\x4F53", {L"KaiTi", simplifiedChineseCodepage}},
+ {L"kaiti", {L"\x6977\x4F53", simplifiedChineseCodepage}},
+ // 仿宋_GB2312, FangSong_GB2312
+ {L"\x4EFF\x5B8B_GB2312", {L"FangSong_GB2312", simplifiedChineseCodepage}},
+ {L"fangsong_gb2312", {L"\x4EFF\x5B8B_gb2312", simplifiedChineseCodepage}},
+ // 楷体_GB2312, KaiTi_GB2312
+ {L"\x6977\x4F53", {L"KaiTi_GB2312", simplifiedChineseCodepage}},
+ {L"kaiti_gb2312", {L"\x6977\x4F53_gb2312", simplifiedChineseCodepage}},
+ // 新細明體, PMingLiu
+ {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}},
+ {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}},
+ // 細明體, MingLiu
+ {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}},
+ {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}},
+ // 微軟正黑體, Microsoft JhengHei
+ {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalChineseCodepage}},
+ {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalChineseCodepage}},
+ // 標楷體, DFKai-SB
+ {L"\x6A19\x6977\x9AD4", {L"DFKai-SB", traditionalChineseCodepage}},
+ {L"dfkai-sb", {L"\x6A19\x6977\x9AD4", traditionalChineseCodepage}},
+ // WenQuanYi Zen Hei
+ {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", {L"WenQuanYi Zen Hei", traditionalChineseCodepage}},
+ {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", traditionalChineseCodepage}},
+ // WenQuanYi Zen Hei
+ {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", {L"WenQuanYi Zen Hei", simplifiedChineseCodepage}},
+ {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", simplifiedChineseCodepage}},
+ // AR PL ShanHeiSun Uni,
+ {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069",
+ {L"AR PL ShanHeiSun Uni", traditionalChineseCodepage}},
+ {L"ar pl shanheisun uni",
+ {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", traditionalChineseCodepage}},
+ // AR PL ShanHeiSun Uni,
+ {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069",
+ {L"AR PL ShanHeiSun Uni", simplifiedChineseCodepage}},
+ {L"ar pl shanheisun uni",
+ {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", simplifiedChineseCodepage}},
+ // AR PL ZenKai Uni
+ // Traditional Chinese and Simplified Chinese names are
+ // identical.
+ {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", traditionalChineseCodepage}},
+ {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", traditionalChineseCodepage}},
+ {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", simplifiedChineseCodepage}},
+ {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", simplifiedChineseCodepage}},
+ };
+
+ typedef HashMap<String, const FontCodepage*> NameMap;
+ static NameMap* fontNameMap = 0;
+
+ if (!fontNameMap) {
+ size_t numElements = sizeof(namePairs) / sizeof(NamePair);
+ fontNameMap = new NameMap;
+ for (size_t i = 0; i < numElements; ++i)
+ fontNameMap->set(String(namePairs[i].name), &(namePairs[i].altNameCodepage));
+ }
+
+ bool isAscii = false;
+ String n;
+ // use |lower| only for ASCII names
+ // For non-ASCII names, we don't want to invoke an expensive
+ // and unnecessary |lower|.
+ if (charactersAreAllASCII(name)) {
+ isAscii = true;
+ n = name.lower();
+ } else
+ n = name;
+
+ NameMap::iterator iter = fontNameMap->find(n);
+ if (iter == fontNameMap->end())
+ return false;
+
+ static int systemCp = ::GetACP();
+ int fontCp = iter->second->codePage;
+
+ if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) {
+ altName = String(iter->second->name);
+ return true;
+ }
+
+ return false;
+}
+
+static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winfont, String* winName)
+{
+ int len = min(static_cast<int>(family.length()), LF_FACESIZE - 1);
+ memcpy(winfont->lfFaceName, family.characters(), len * sizeof(WORD));
+ winfont->lfFaceName[len] = '\0';
+
+ HFONT hfont = CreateFontIndirect(winfont);
+ if (!hfont)
+ return 0;
+
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont));
+ WCHAR name[LF_FACESIZE];
+ unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
+ if (resultLength > 0)
+ resultLength--; // ignore the null terminator
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ *winName = String(name, resultLength);
+ return hfont;
+}
+
+// This maps font family names to their repertoires of supported Unicode
+// characters. Because it's family names rather than font faces we use
+// as keys, there might be edge cases where one face of a font family
+// has a different repertoire from another face of the same family.
+typedef HashMap<const wchar_t*, UnicodeSet*> FontCmapCache;
+
+static bool fontContainsCharacter(const FontPlatformData* fontData,
+ const wchar_t* family, UChar32 character)
+{
+ // FIXME: For non-BMP characters, GetFontUnicodeRanges is of
+ // no use. We have to read directly from the cmap table of a font.
+ // Return true for now.
+ if (character > 0xFFFF)
+ return true;
+
+ // This cache is just leaked on shutdown.
+ static FontCmapCache* fontCmapCache = 0;
+ if (!fontCmapCache)
+ fontCmapCache = new FontCmapCache;
+
+ HashMap<const wchar_t*, UnicodeSet*>::iterator it = fontCmapCache->find(family);
+ if (it != fontCmapCache->end())
+ return it->second->contains(character);
+
+ HFONT hfont = fontData->hfont();
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont));
+ int count = GetFontUnicodeRanges(hdc, 0);
+ if (count == 0 && ChromiumBridge::ensureFontLoaded(hfont))
+ count = GetFontUnicodeRanges(hdc, 0);
+ if (count == 0) {
+ ASSERT_NOT_REACHED();
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ return true;
+ }
+
+ static Vector<char, 512> glyphsetBuffer;
+ glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0));
+ GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data());
+ // In addition, refering to the OS/2 table and converting the codepage list
+ // to the coverage map might be faster.
+ count = GetFontUnicodeRanges(hdc, glyphset);
+ ASSERT(count > 0);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ // FIXME: consider doing either of the following two:
+ // 1) port back ICU 4.0's faster look-up code for UnicodeSet
+ // 2) port Mozilla's CompressedCharMap or gfxSparseBitset
+ unsigned i = 0;
+ UnicodeSet* cmap = new UnicodeSet;
+ while (i < glyphset->cRanges) {
+ WCHAR start = glyphset->ranges[i].wcLow;
+ cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1);
+ i++;
+ }
+ cmap->freeze();
+ // We don't lowercase |family| because all of them are under our control
+ // and they're already lowercased.
+ fontCmapCache->set(family, cmap);
+ return cmap->contains(character);
+}
+
+// Given the desired base font, this will create a SimpleFontData for a specific
+// font that can be used to render the given range of characters.
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ // FIXME: Consider passing fontDescription.dominantScript()
+ // to GetFallbackFamily here.
+ FontDescription fontDescription = font.fontDescription();
+ UChar32 c;
+ UScriptCode script;
+ const wchar_t* family = getFallbackFamily(characters, length,
+ fontDescription.genericFamily(), &c, &script);
+ FontPlatformData* data = 0;
+ if (family)
+ data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)), false);
+
+ // Last resort font list : PanUnicode. CJK fonts have a pretty
+ // large repertoire. Eventually, we need to scan all the fonts
+ // on the system to have a Firefox-like coverage.
+ // Make sure that all of them are lowercased.
+ const static wchar_t* const cjkFonts[] = {
+ L"arial unicode ms",
+ L"ms pgothic",
+ L"simsun",
+ L"gulim",
+ L"pmingliu",
+ L"wenquanyi zen hei", // partial CJK Ext. A coverage but more
+ // widely known to Chinese users.
+ L"ar pl shanheisun uni",
+ L"ar pl zenkai uni",
+ L"han nom a", // Complete CJK Ext. A coverage
+ L"code2000", // Complete CJK Ext. A coverage
+ // CJK Ext. B fonts are not listed here because it's of no use
+ // with our current non-BMP character handling because we use
+ // Uniscribe for it and that code path does not go through here.
+ };
+
+ const static wchar_t* const commonFonts[] = {
+ L"tahoma",
+ L"arial unicode ms",
+ L"lucida sans unicode",
+ L"microsoft sans serif",
+ L"palatino linotype",
+ // Four fonts below (and code2000 at the end) are not from MS, but
+ // once installed, cover a very wide range of characters.
+ L"freeserif",
+ L"freesans",
+ L"gentium",
+ L"gentiumalt",
+ L"ms pgothic",
+ L"simsun",
+ L"gulim",
+ L"pmingliu",
+ L"code2000",
+ };
+
+ const wchar_t* const* panUniFonts = 0;
+ int numFonts = 0;
+ if (script == USCRIPT_HAN) {
+ panUniFonts = cjkFonts;
+ numFonts = ARRAYSIZE(cjkFonts);
+ } else {
+ panUniFonts = commonFonts;
+ numFonts = ARRAYSIZE(commonFonts);
+ }
+ // Font returned from GetFallbackFamily may not cover |characters|
+ // because it's based on script to font mapping. This problem is
+ // critical enough for non-Latin scripts (especially Han) to
+ // warrant an additional (real coverage) check with fontCotainsCharacter.
+ int i;
+ for (i = 0; (!data || !fontContainsCharacter(data, family, c)) && i < numFonts; ++i) {
+ family = panUniFonts[i];
+ data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)));
+ }
+ if (i < numFonts) // we found the font that covers this character !
+ return getCachedFontData(data);
+
+ return 0;
+
+}
+
+const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName)
+{
+ // Note that mapping to Courier is removed because
+ // because it's a bitmap font on Windows.
+ // Alias Courier -> Courier New
+ static AtomicString courier("Courier"), courierNew("Courier New");
+ if (equalIgnoringCase(familyName, courier))
+ return courierNew;
+
+ // Alias Times <-> Times New Roman.
+ static AtomicString times("Times"), timesNewRoman("Times New Roman");
+ if (equalIgnoringCase(familyName, times))
+ return timesNewRoman;
+ if (equalIgnoringCase(familyName, timesNewRoman))
+ return times;
+
+ // Alias Helvetica <-> Arial
+ static AtomicString arial("Arial"), helvetica("Helvetica");
+ if (equalIgnoringCase(familyName, helvetica))
+ return arial;
+ if (equalIgnoringCase(familyName, arial))
+ return helvetica;
+
+ // We block bitmap fonts altogether so that we have to
+ // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font)
+ static AtomicString msSans("MS Sans Serif");
+ static AtomicString microsoftSans("Microsoft Sans Serif");
+ if (equalIgnoringCase(familyName, msSans))
+ return microsoftSans;
+
+ // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no
+ // 'Microsoft Sans Serif-equivalent' for Serif.
+ static AtomicString msSerif("MS Serif");
+ if (equalIgnoringCase(familyName, msSerif))
+ return timesNewRoman;
+
+ // FIXME: should we map 'system' to something ('Tahoma') ?
+ return emptyAtom;
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description)
+{
+ FontDescription::GenericFamilyType generic = description.genericFamily();
+ // FIXME: Mapping webkit generic to GenericFamilyType needs to
+ // be more intelligent.
+ // This spot rarely gets reached. GetFontDataForCharacters() gets hit a lot
+ // more often (see FIXME comment there).
+ const wchar_t* family = getFontFamilyForScript(description.dominantScript(), generic);
+
+ if (family)
+ return getCachedFontPlatformData(description, AtomicString(family, wcslen(family)));
+
+ // 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.
+ static AtomicString timesStr("Times New Roman");
+ static AtomicString courierStr("Courier New");
+ static AtomicString arialStr("Arial");
+
+ AtomicString& fontStr = timesStr;
+ if (generic == FontDescription::SansSerifFamily)
+ fontStr = arialStr;
+ else if (generic == FontDescription::MonospaceFamily)
+ fontStr = courierStr;
+
+ return getCachedFontPlatformData(description, fontStr);
+}
+
+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];
+}
+
+// FIXME: This may not be the best place to put this function
+AtomicString FontCache::getGenericFontForScript(UScriptCode script, const FontDescription& description)
+{
+ const wchar_t* scriptFont = getFontFamilyForScript( script, description.genericFamily());
+ return scriptFont ? AtomicString(scriptFont, wcslen(scriptFont)) : emptyAtom;
+}
+
+static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont)
+{
+ // The size here looks unusual. The negative number is intentional.
+ // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be
+ // some kind of artifact of their CG backend, or something.
+ winfont->lfHeight = -fontDescription.computedPixelSize();
+ winfont->lfWidth = 0;
+ winfont->lfEscapement = 0;
+ winfont->lfOrientation = 0;
+ winfont->lfUnderline = false;
+ winfont->lfStrikeOut = false;
+ winfont->lfCharSet = DEFAULT_CHARSET;
+ winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ winfont->lfQuality = ChromiumBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings.
+ winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ winfont->lfItalic = fontDescription.italic();
+ winfont->lfWeight = toGDIFontWeight(fontDescription.weight());
+}
+
+struct 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 = logFont->lfWeight;
+ 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::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = 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(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+
+ ReleaseDC(0, hdc);
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ LOGFONT winfont = {0};
+ FillLogFont(fontDescription, &winfont);
+
+ // Windows will always give us a valid pointer here, even if the face name
+ // is non-existent. We have to double-check and see if the family name was
+ // really used.
+ String winName;
+ HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName);
+ if (!hfont)
+ return 0;
+
+ // FIXME: Do we need to use predefined fonts "guaranteed" to exist
+ // when we're running in layout-test mode?
+ if (!equalIgnoringCase(family, winName)) {
+ // For CJK fonts with both English and native names,
+ // GetTextFace returns a native name under the font's "locale"
+ // and an English name under other locales regardless of
+ // lfFaceName field of LOGFONT. As a result, we need to check
+ // if a font has an alternate name. If there is, we need to
+ // compare it with what's requested in the first place.
+ String altName;
+ if (!LookupAltName(family, altName) ||
+ !equalIgnoringCase(altName, winName)) {
+ DeleteObject(hfont);
+ return 0;
+ }
+ }
+
+ return new FontPlatformData(hfont,
+ fontDescription.computedPixelSize());
+}
+
+}
diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
new file mode 100644
index 0000000..f187c55
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include <fontconfig/fontconfig.h>
+
+#include "AtomicString.h"
+#include "CString.h"
+#include "Font.h"
+#include "FontDescription.h"
+#include "FontPlatformData.h"
+#include "Logging.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+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) {
+ FontPlatformData* fpd =
+ createFontPlatformData(font.fontDescription(), AtomicString((char*) family));
+ ret = new SimpleFontData(*fpd);
+ }
+ FcPatternDestroy(match);
+ }
+
+ FcCharSetDestroy(cset);
+
+ return ret;
+}
+
+const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName)
+{
+ notImplemented();
+
+ // This is just to stop GCC emitting a warning about returning a reference
+ // to a temporary variable
+ static AtomicString a;
+ return a;
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description)
+{
+ static AtomicString arialStr("Arial");
+ return getCachedFontPlatformData(description, arialStr);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName,
+ Vector<unsigned>& traitsMasks)
+{
+ notImplemented();
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription,
+ const AtomicString& family)
+{
+ const char* name = 0;
+ CString s;
+
+ if (family.length() == 0) {
+ static const struct {
+ FontDescription::GenericFamilyType mType;
+ const char* mName;
+ } fontDescriptions[] = {
+ { FontDescription::SerifFamily, "serif" },
+ { FontDescription::SansSerifFamily, "sans-serif" },
+ { FontDescription::MonospaceFamily, "monospace" },
+ { FontDescription::CursiveFamily, "cursive" },
+ { FontDescription::FantasyFamily, "fantasy" }
+ };
+
+ FontDescription::GenericFamilyType type = fontDescription.genericFamily();
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(fontDescriptions); i++) {
+ if (type == fontDescriptions[i].mType) {
+ name = fontDescriptions[i].mName;
+ break;
+ }
+ }
+ // if we fall out of the loop, it's ok for name to still be 0
+ }
+ else { // convert the name to utf8
+ s = family.string().utf8();
+ name = s.data();
+ }
+
+ int style = SkTypeface::kNormal;
+ if (fontDescription.weight() >= FontWeightBold)
+ style |= SkTypeface::kBold;
+ if (fontDescription.italic())
+ style |= SkTypeface::kItalic;
+
+ SkTypeface* tf = SkTypeface::Create(name, static_cast<SkTypeface::Style>(style));
+ if (!tf)
+ return 0;
+
+ FontPlatformData* result =
+ new FontPlatformData(tf,
+ fontDescription.computedSize(),
+ (style & SkTypeface::kBold) && !tf->isBold(),
+ (style & SkTypeface::kItalic) && !tf->isItalic());
+ tf->unref();
+ return result;
+}
+
+AtomicString FontCache::getGenericFontForScript(UScriptCode script,
+ const FontDescription& descript)
+{
+ notImplemented();
+ return AtomicString();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
new file mode 100644
index 0000000..3cf18a6
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "TransformationMatrix.h"
+#include "ChromiumBridge.h"
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+#include "SkiaFontWin.h"
+#include "SkiaUtils.h"
+#include "UniscribeHelperTextRun.h"
+
+#include "skia/ext/platform_canvas_win.h"
+#include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency.
+
+#include <windows.h>
+
+namespace WebCore {
+
+static bool windowsCanHandleTextDrawing(GraphicsContext* context)
+{
+ // Check for non-translation transforms. Sometimes zooms will look better in
+ // Skia, and sometimes better in Windows. The main problem is that zooming
+ // in using Skia will show you the hinted outlines for the smaller size,
+ // which look weird. All else being equal, it's better to use Windows' text
+ // drawing, so we don't check for zooms.
+ const TransformationMatrix& matrix = context->getCTM();
+ if (matrix.b() != 0 || matrix.c() != 0) // Check for skew.
+ return false;
+
+ // Check for stroke effects.
+ if (context->platformContext()->getTextDrawingMode() != cTextFill)
+ return false;
+
+ // Check for shadow effects.
+ if (context->platformContext()->getDrawLooper())
+ return false;
+
+ return true;
+}
+
+// Skia equivalents to Windows text drawing functions. They
+// will get the outlines from Windows and draw then using Skia using the given
+// parameters in the paint arguments. This allows more complex effects and
+// transforms to be drawn than Windows allows.
+//
+// These functions will be significantly slower than Windows GDI, and the text
+// will look different (no ClearType), so use only when necessary.
+//
+// When you call a Skia* text drawing function, various glyph outlines will be
+// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont
+// when the font is destroyed so that the cache does not outlive the font (since
+// the HFONTs are recycled).
+
+// Analog of the Windows GDI function DrawText, except using the given SkPaint
+// attributes for the text. See above for more.
+//
+// Returns true of the text was drawn successfully. False indicates an error
+// from Windows.
+static bool skiaDrawText(HFONT hfont,
+ SkCanvas* canvas,
+ const SkPoint& point,
+ SkPaint* paint,
+ const WORD* glyphs,
+ const int* advances,
+ int numGlyphs)
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont);
+
+ canvas->save();
+ canvas->translate(point.fX, point.fY);
+
+ for (int i = 0; i < numGlyphs; i++) {
+ const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]);
+ if (!path)
+ return false;
+ canvas->drawPath(*path, *paint);
+ canvas->translate(advances[i], 0);
+ }
+
+ canvas->restore();
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ return true;
+}
+
+static bool paintSkiaText(PlatformContextSkia* platformContext,
+ HFONT hfont,
+ int numGlyphs,
+ const WORD* glyphs,
+ const int* advances,
+ const SkPoint& origin)
+{
+ int textMode = platformContext->getTextDrawingMode();
+
+ // Filling (if necessary). This is the common case.
+ SkPaint paint;
+ platformContext->setupPaintForFilling(&paint);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ bool didFill = false;
+ if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) {
+ if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
+ return false;
+ didFill = true;
+ }
+
+ // Stroking on top (if necessary).
+ if ((textMode & WebCore::cTextStroke)
+ && platformContext->getStrokeStyle() != NoStroke
+ && platformContext->getStrokeThickness() > 0) {
+
+ paint.reset();
+ platformContext->setupPaintForStroking(&paint, 0, 0);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ if (didFill) {
+ // If there is a shadow and we filled above, there will already be
+ // a shadow. We don't want to draw it again or it will be too dark
+ // and it will go on top of the fill.
+ //
+ // Note that this isn't strictly correct, since the stroke could be
+ // very thick and the shadow wouldn't account for this. The "right"
+ // thing would be to draw to a new layer and then draw that layer
+ // with a shadow. But this is a lot of extra work for something
+ // that isn't normally an issue.
+ paint.setLooper(0)->safeUnref();
+ }
+
+ if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs))
+ return false;
+ }
+ return true;
+}
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext,
+ const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer,
+ int from,
+ int numGlyphs,
+ const FloatPoint& point) const
+{
+ PlatformGraphicsContext* context = graphicsContext->platformContext();
+
+ // Max buffer length passed to the underlying windows API.
+ const int kMaxBufferLength = 1024;
+ // Default size for the buffer. It should be enough for most of cases.
+ const int kDefaultBufferLength = 256;
+
+ SkColor color = context->fillColor();
+ unsigned char alpha = SkColorGetA(color);
+ // Skip 100% transparent text; no need to draw anything.
+ if (!alpha && context->getStrokeStyle() == NoStroke)
+ return;
+
+ // Set up our graphics context.
+ HDC hdc = context->canvas()->beginPlatformPaint();
+ HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());
+
+ // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
+ // Enforce non-transparent color.
+ color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
+ SetTextColor(hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(hdc, TRANSPARENT);
+
+ // Windows needs the characters and the advances in nice contiguous
+ // buffers, which we build here.
+ Vector<WORD, kDefaultBufferLength> glyphs;
+ Vector<int, kDefaultBufferLength> advances;
+
+ // Compute the coordinate. The 'origin' represents the baseline, so we need
+ // to move it up to the top of the bounding square.
+ int x = static_cast<int>(point.x());
+ int lineTop = static_cast<int>(point.y()) - font->ascent();
+
+ bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext);
+
+ // We draw the glyphs in chunks to avoid having to do a heap allocation for
+ // the arrays of characters and advances. Since ExtTextOut is the
+ // lowest-level text output function on Windows, there should be little
+ // penalty for splitting up the text. On the other hand, the buffer cannot
+ // be bigger than 4094 or the function will fail.
+ int glyphIndex = 0;
+ while (glyphIndex < numGlyphs) {
+ // how many chars will be in this chunk?
+ int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
+
+ glyphs.resize(curLen);
+ advances.resize(curLen);
+
+ int curWidth = 0;
+ for (int i = 0; i < curLen; ++i, ++glyphIndex) {
+ glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
+ advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
+ curWidth += advances[i];
+ }
+
+ bool success = false;
+ for (int executions = 0; executions < 2; ++executions) {
+ if (canUseGDI)
+ success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), curLen, &advances[0]);
+ else {
+ // Skia's text draing origin is the baseline, like WebKit, not
+ // the top, like Windows.
+ SkPoint origin = { x, point.y() };
+ success = paintSkiaText(context, font->platformData().hfont(), numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]), &advances[0], origin);
+ }
+
+ if (!success && executions == 0) {
+ // Ask the browser to load the font for us and retry.
+ ChromiumBridge::ensureFontLoaded(font->platformData().hfont());
+ continue;
+ }
+ break;
+ }
+
+ ASSERT(success);
+
+ x += curWidth;
+ }
+
+ SelectObject(hdc, oldFont);
+ context->canvas()->endPlatformPaint();
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run,
+ const IntPoint& point,
+ int h,
+ int from,
+ int to) const
+{
+ UniscribeHelperTextRun state(run, *this);
+ float left = static_cast<float>(point.x() + state.characterToX(from));
+ float right = static_cast<float>(point.x() + state.characterToX(to));
+
+ // If the text is RTL, left will actually be after right.
+ if (left < right)
+ return FloatRect(left, static_cast<float>(point.y()),
+ right - left, static_cast<float>(h));
+
+ return FloatRect(right, static_cast<float>(point.y()),
+ left - right, static_cast<float>(h));
+}
+
+void Font::drawComplexText(GraphicsContext* graphicsContext,
+ const TextRun& run,
+ const FloatPoint& point,
+ int from,
+ int to) const
+{
+ PlatformGraphicsContext* context = graphicsContext->platformContext();
+ UniscribeHelperTextRun state(run, *this);
+
+ SkColor color = context->fillColor();
+ unsigned char alpha = SkColorGetA(color);
+ // Skip 100% transparent text; no need to draw anything.
+ if (!alpha)
+ return;
+
+ HDC hdc = context->canvas()->beginPlatformPaint();
+
+ // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
+ // Enforce non-transparent color.
+ color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
+ SetTextColor(hdc, skia::SkColorToCOLORREF(color));
+ SetBkMode(hdc, TRANSPARENT);
+
+ // Uniscribe counts the coordinates from the upper left, while WebKit uses
+ // the baseline, so we have to subtract off the ascent.
+ state.draw(hdc, static_cast<int>(point.x()), static_cast<int>(point.y() - ascent()), from, to);
+ context->canvas()->endPlatformPaint();
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ UniscribeHelperTextRun state(run, *this);
+ return static_cast<float>(state.width());
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x,
+ bool includePartialGlyphs) const
+{
+ // Mac code ignores includePartialGlyphs, and they don't know what it's
+ // supposed to do, so we just ignore it as well.
+ UniscribeHelperTextRun state(run, *this);
+ int charIndex = state.xToCharacter(x);
+
+ // XToCharacter will return -1 if the position is before the first
+ // character (we get called like this sometimes).
+ if (charIndex < 0)
+ charIndex = 0;
+ return charIndex;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..8f8df88
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#if PLATFORM(WIN_OS)
+#include "Base64.h"
+#include "ChromiumBridge.h"
+#include "OpenTypeUtilities.h"
+#endif
+
+#include "FontPlatformData.h"
+#include "NotImplemented.h"
+#include "SharedBuffer.h"
+
+#if PLATFORM(WIN_OS)
+#include <objbase.h>
+#include <t2embapi.h>
+#pragma comment(lib, "t2embed")
+#endif
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+#if PLATFORM(WIN_OS)
+ if (m_fontReference) {
+ if (m_name.isNull()) {
+ ULONG status;
+ TTDeleteEmbeddedFont(m_fontReference, 0, &status);
+ } else
+ RemoveFontMemResourceEx(m_fontReference);
+ }
+#endif
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode mode)
+{
+#if PLATFORM(WIN_OS)
+ ASSERT(m_fontReference);
+
+ LOGFONT logFont;
+ if (m_name.isNull())
+ TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
+ else {
+ // m_name comes from createUniqueFontName, which, in turn, gets
+ // it from base64-encoded uuid (128-bit). So, m_name
+ // can never be longer than LF_FACESIZE (32).
+ if (m_name.length() + 1 >= LF_FACESIZE) {
+ ASSERT_NOT_REACHED();
+ return FontPlatformData();
+ }
+ memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(),
+ sizeof(logFont.lfFaceName[0]) * (1 + m_name.length()));
+ }
+
+ // FIXME: almost identical to FillLogFont in FontCacheWin.cpp.
+ // Need to refactor.
+ logFont.lfHeight = -size;
+ logFont.lfWidth = 0;
+ logFont.lfEscapement = 0;
+ logFont.lfOrientation = 0;
+ logFont.lfUnderline = false;
+ logFont.lfStrikeOut = false;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ logFont.lfQuality = ChromiumBridge::layoutTestMode() ?
+ NONANTIALIASED_QUALITY :
+ DEFAULT_QUALITY; // Honor user's desktop settings.
+ logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ logFont.lfItalic = italic;
+ logFont.lfWeight = bold ? 700 : 400;
+
+ HFONT hfont = CreateFontIndirect(&logFont);
+ return FontPlatformData(hfont, size);
+#else
+ notImplemented();
+ return FontPlatformData();
+#endif
+}
+
+#if PLATFORM(WIN_OS)
+// FIXME: EOTStream class and static functions in this #if block are
+// duplicated from platform/graphics/win/FontCustomPlatformData.cpp
+// and need to be shared.
+
+// Streams the concatenation of a header and font data.
+class EOTStream {
+public:
+ EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength)
+ : m_eotHeader(eotHeader)
+ , m_fontData(fontData)
+ , m_overlayDst(overlayDst)
+ , m_overlaySrc(overlaySrc)
+ , m_overlayLength(overlayLength)
+ , m_offset(0)
+ , m_inHeader(true)
+ {
+ }
+
+ size_t read(void* buffer, size_t count);
+
+private:
+ const Vector<UInt8, 512>& m_eotHeader;
+ const SharedBuffer* m_fontData;
+ size_t m_overlayDst;
+ size_t m_overlaySrc;
+ size_t m_overlayLength;
+ size_t m_offset;
+ bool m_inHeader;
+};
+
+size_t EOTStream::read(void* buffer, size_t count)
+{
+ size_t bytesToRead = count;
+ if (m_inHeader) {
+ size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count);
+ memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader);
+ m_offset += bytesFromHeader;
+ bytesToRead -= bytesFromHeader;
+ if (m_offset == m_eotHeader.size()) {
+ m_inHeader = false;
+ m_offset = 0;
+ }
+ }
+ if (bytesToRead && !m_inHeader) {
+ size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead);
+ memcpy(buffer, m_fontData->data() + m_offset, bytesFromData);
+ if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) {
+ size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0);
+ size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst);
+ size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset);
+ memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy);
+ }
+ m_offset += bytesFromData;
+ bytesToRead -= bytesFromData;
+ }
+ return count - bytesToRead;
+}
+
+static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length)
+{
+ return static_cast<EOTStream*>(stream)->read(buffer, length);
+}
+
+// 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));
+ CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data()));
+
+ Vector<char> fontNameVector;
+ base64Encode(fontUuid, fontNameVector);
+ ASSERT(fontNameVector.size() < LF_FACESIZE);
+ return String(fontNameVector.data(), fontNameVector.size());
+}
+#endif
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+#if PLATFORM(WIN_OS)
+ // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's
+ // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the
+ // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name
+ // we avoid namespace collisions.
+
+ String fontName = createUniqueFontName();
+
+ // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data,
+ // so we need to create an EOT header and prepend it to the font data.
+ Vector<UInt8, 512> eotHeader;
+ size_t overlayDst;
+ size_t overlaySrc;
+ size_t overlayLength;
+
+ if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength))
+ return 0;
+
+ HANDLE fontReference;
+ ULONG privStatus;
+ ULONG status;
+ EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength);
+
+ LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0);
+ if (loadEmbeddedFontResult == E_NONE)
+ fontName = String();
+ else {
+ fontReference = renameAndActivateFont(buffer, fontName);
+ if (!fontReference)
+ return 0;
+ }
+
+ return new FontCustomPlatformData(fontReference, fontName);
+#else
+ notImplemented();;
+ return 0;
+#endif
+}
+
+}
diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
new file mode 100644
index 0000000..2f1a597
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ * Copyright (c) 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include <wtf/Noncopyable.h>
+
+#if PLATFORM(WIN_OS)
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
+#include <windows.h>
+#endif
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+#if PLATFORM(WIN_OS)
+ FontCustomPlatformData(HANDLE fontReference, const String& name)
+ : m_fontReference(fontReference)
+ , m_name(name)
+ {}
+#endif
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic,
+ FontRenderingMode = NormalRenderingMode);
+
+#if PLATFORM(WIN_OS)
+ HANDLE m_fontReference;
+ String m_name;
+#endif
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+}
+
+#endif // FontCustomPlatformData_h
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
new file mode 100644
index 0000000..7a3e614
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2007, 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FloatRect.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+#include "SimpleFontData.h"
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkTemplates.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
+ const FloatPoint& point) const {
+ SkCanvas* canvas = gc->platformContext()->canvas();
+ SkPaint paint;
+
+ gc->platformContext()->setupPaintCommon(&paint);
+ font->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->fillColor().rgb());
+
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+
+ const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
+ SkScalar x = SkFloatToScalar(point.x());
+ SkScalar y = SkFloatToScalar(point.y());
+
+ // FIXME: text rendering speed:
+ // Android has code in their WebCore fork to special case when the
+ // GlyphBuffer has no advances other than the defaults. In that case the
+ // text drawing can proceed faster. However, it's unclear when those
+ // patches may be upstreamed to WebKit so we always use the slower path
+ // here.
+ const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
+ SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
+ SkPoint* pos = storage.get();
+
+ for (int i = 0; i < numGlyphs; i++) {
+ pos[i].set(x, y);
+ x += SkFloatToScalar(adv[i].width());
+ y += SkFloatToScalar(adv[i].height());
+ }
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run,
+ const FloatPoint& point, int from, int to) const
+{
+ notImplemented();
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ notImplemented();
+ return 0;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x,
+ bool includePartialGlyphs) const
+{
+ notImplemented();
+ return 0;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run,
+ const IntPoint& point, int h,
+ int from, int to) const
+{
+ notImplemented();
+ return FloatRect();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontPlatformData.h b/WebCore/platform/graphics/chromium/FontPlatformData.h
new file mode 100644
index 0000000..c6f1912
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontPlatformData.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2007, 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#if PLATFORM(WIN_OS)
+#include "FontPlatformDataChromiumWin.h"
+#elif defined(__linux__)
+#include "FontPlatformDataLinux.h"
+#endif
+
+#endif // FontPlatformData_h
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
new file mode 100644
index 0000000..767fe76
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include <windows.h>
+#include <objidl.h>
+#include <mlang.h>
+
+#include "ChromiumBridge.h"
+#include "SkiaFontWin.h"
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_font(hashTableDeletedFontValue())
+ , m_size(-1)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData::FontPlatformData()
+ : m_font(0)
+ , m_size(0)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData::FontPlatformData(HFONT font, float size)
+ : m_font(RefCountedHFONT::create(font))
+ , m_size(size)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : m_font(0)
+ , m_size(size)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& data)
+ : m_font(data.m_font)
+ , m_size(data.m_size)
+ , m_scriptCache(0)
+ , m_scriptFontProperties(0)
+{
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
+{
+ if (this != &data) {
+ m_font = data.m_font;
+ m_size = data.m_size;
+
+ // The following fields will get re-computed if necessary.
+ ScriptFreeCache(&m_scriptCache);
+ m_scriptCache = 0;
+
+ delete m_scriptFontProperties;
+ m_scriptFontProperties = 0;
+ }
+ return *this;
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ ScriptFreeCache(&m_scriptCache);
+ m_scriptCache = 0;
+
+ delete m_scriptFontProperties;
+ m_scriptFontProperties = 0;
+}
+
+FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
+{
+ if (m_hfont != reinterpret_cast<HFONT>(-1)) {
+ SkiaWinOutlineCache::removePathsForFont(m_hfont);
+ DeleteObject(m_hfont);
+ }
+}
+
+FontPlatformData::RefCountedHFONT* FontPlatformData::hashTableDeletedFontValue()
+{
+ static RefPtr<RefCountedHFONT> deletedValue =
+ RefCountedHFONT::create(reinterpret_cast<HFONT>(-1));
+ return deletedValue.get();
+}
+
+SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
+{
+ if (!m_scriptFontProperties) {
+ m_scriptFontProperties = new SCRIPT_FONTPROPERTIES;
+ memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES));
+ m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
+ HRESULT result = ScriptGetFontProperties(0, scriptCache(),
+ m_scriptFontProperties);
+ if (result == E_PENDING) {
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont());
+ HRESULT hr = ScriptGetFontProperties(dc, scriptCache(),
+ m_scriptFontProperties);
+ if (S_OK != hr) {
+ if (ChromiumBridge::ensureFontLoaded(hfont())) {
+ // FIXME: Handle gracefully the error if this call also fails.
+ hr = ScriptGetFontProperties(dc, scriptCache(),
+ m_scriptFontProperties);
+ if (S_OK != hr) {
+ ASSERT_NOT_REACHED();
+ }
+ }
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ }
+ }
+ return m_scriptFontProperties;
+}
+
+}
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
new file mode 100644
index 0000000..ce15a93
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontPlatformDataWin_h
+#define FontPlatformDataWin_h
+
+#include "config.h"
+
+#include "StringImpl.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+#include <usp10.h>
+
+typedef struct HFONT__ *HFONT;
+
+namespace WebCore {
+
+class FontDescription;
+
+class FontPlatformData {
+public:
+ // Used for deleted values in the font cache's hash tables. The hash table
+ // will create us with this structure, and it will compare other values
+ // to this "Deleted" one. It expects the Deleted one to be differentiable
+ // from the NULL one (created with the empty constructor), so we can't just
+ // set everything to NULL.
+ FontPlatformData(WTF::HashTableDeletedValueType);
+ FontPlatformData();
+ FontPlatformData(HFONT, float size);
+ FontPlatformData(float size, bool bold, bool oblique);
+ FontPlatformData(const FontPlatformData&);
+
+ FontPlatformData& operator=(const FontPlatformData&);
+
+ bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); }
+
+ ~FontPlatformData();
+
+ HFONT hfont() const { return m_font ? m_font->hfont() : 0; }
+ float size() const { return m_size; }
+
+ unsigned hash() const
+ {
+ return m_font ? m_font->hash() : NULL;
+ }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font && m_size == other.m_size;
+ }
+
+ SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
+ SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
+
+private:
+ // We refcount the internal HFONT so that FontPlatformData can be
+ // efficiently copied. WebKit depends on being able to copy it, and we
+ // don't really want to re-create the HFONT.
+ class RefCountedHFONT : public RefCounted<RefCountedHFONT> {
+ public:
+ static PassRefPtr<RefCountedHFONT> create(HFONT hfont)
+ {
+ return adoptRef(new RefCountedHFONT(hfont));
+ }
+
+ ~RefCountedHFONT();
+
+ HFONT hfont() const { return m_hfont; }
+ unsigned hash() const
+ {
+ return StringImpl::computeHash(reinterpret_cast<const UChar*>(&m_hfont), sizeof(HFONT) / sizeof(UChar));
+ }
+
+ bool operator==(const RefCountedHFONT& other) const
+ {
+ return m_hfont == other.m_hfont;
+ }
+
+ private:
+ // The create() function assumes there is already a refcount of one
+ // so it can do adoptRef.
+ RefCountedHFONT(HFONT hfont) : m_hfont(hfont)
+ {
+ }
+
+ HFONT m_hfont;
+ };
+
+ static RefCountedHFONT* hashTableDeletedFontValue();
+
+ RefPtr<RefCountedHFONT> m_font;
+ float m_size; // Point size of the font in pixels.
+
+ mutable SCRIPT_CACHE m_scriptCache;
+ mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
+};
+
+} // WebCore
+
+#endif // FontPlatformDataWin_h
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
new file mode 100644
index 0000000..86f96ee
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "StringImpl.h"
+#include "NotImplemented.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+
+namespace WebCore {
+
+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_typeface->safeRef();
+}
+
+FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic)
+ : m_typeface(tf)
+ , m_textSize(textSize)
+ , m_fakeBold(fakeBold)
+ , m_fakeItalic(fakeItalic)
+{
+ m_typeface->safeRef();
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
+ : m_typeface(src.m_typeface)
+ , m_textSize(textSize)
+ , m_fakeBold(src.m_fakeBold)
+ , m_fakeItalic(src.m_fakeItalic)
+{
+ m_typeface->safeRef();
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ m_typeface->safeUnref();
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
+{
+ SkRefCnt_SafeAssign(m_typeface, src.m_typeface);
+
+ m_textSize = src.m_textSize;
+ m_fakeBold = src.m_fakeBold;
+ m_fakeItalic = src.m_fakeItalic;
+
+ return *this;
+}
+
+void FontPlatformData::setupPaint(SkPaint* paint) const
+{
+ const float ts = m_textSize > 0 ? m_textSize : 12;
+
+ paint->setAntiAlias(false);
+ paint->setSubpixelText(false);
+ 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);
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& a) const
+{
+ // If either of the typeface pointers are invalid (either NULL or the
+ // special deleted value) then we test for pointer equality. Otherwise, we
+ // call SkTypeface::Equal on the valid pointers.
+ bool typefacesEqual;
+ if (m_typeface == hashTableDeletedFontValue()
+ || a.m_typeface == hashTableDeletedFontValue()
+ || !m_typeface
+ || !a.m_typeface)
+ typefacesEqual = m_typeface == a.m_typeface;
+ else
+ typefacesEqual = SkTypeface::Equal(m_typeface, a.m_typeface);
+
+ return typefacesEqual
+ && m_textSize == a.m_textSize
+ && m_fakeBold == a.m_fakeBold
+ && m_fakeItalic == a.m_fakeItalic;
+}
+
+unsigned FontPlatformData::hash() const
+{
+ unsigned h = SkTypeface::UniqueID(m_typeface);
+ h ^= 0x01010101 * ((static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic));
+
+ // This memcpy is to avoid a reinterpret_cast that breaks strict-aliasing
+ // rules. Memcpy is generally optimized enough so that performance doesn't
+ // matter here.
+ uint32_t textSizeBytes;
+ memcpy(&textSizeBytes, &m_textSize, sizeof(uint32_t));
+ h ^= textSizeBytes;
+
+ return h;
+}
+
+bool FontPlatformData::isFixedPitch() const
+{
+ notImplemented();
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
new file mode 100644
index 0000000..ec7d837
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontPlatformDataLinux_h
+#define FontPlatformDataLinux_h
+
+#include "StringImpl.h"
+#include <wtf/RefPtr.h>
+
+class SkPaint;
+class SkTypeface;
+
+namespace WebCore {
+
+class FontDescription;
+
+// -----------------------------------------------------------------------------
+// FontPlatformData is the handle which WebKit has on a specific face. A face
+// is the tuple of (font, size, ...etc). Here we are just wrapping a Skia
+// SkTypeface pointer and dealing with the reference counting etc.
+// -----------------------------------------------------------------------------
+class FontPlatformData {
+public:
+ // Used for deleted values in the font cache's hash tables. The hash table
+ // will create us with this structure, and it will compare other values
+ // to this "Deleted" one. It expects the Deleted one to be differentiable
+ // from the NULL one (created with the empty constructor), so we can't just
+ // set everything to NULL.
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_typeface(hashTableDeletedFontValue())
+ , m_textSize(0)
+ , m_fakeBold(false)
+ , m_fakeItalic(false)
+ { }
+
+ FontPlatformData()
+ : m_typeface(0)
+ , m_textSize(0)
+ , m_fakeBold(false)
+ , m_fakeItalic(false)
+ { }
+
+ FontPlatformData(float textSize, bool fakeBold, bool fakeItalic)
+ : m_typeface(0)
+ , m_textSize(textSize)
+ , m_fakeBold(fakeBold)
+ , m_fakeItalic(fakeItalic)
+ { }
+
+ FontPlatformData(const FontPlatformData&);
+ FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic);
+ FontPlatformData(const FontPlatformData& src, float textSize);
+ ~FontPlatformData();
+
+ // -------------------------------------------------------------------------
+ // Return true iff this font is monospaced (i.e. every glyph has an equal x
+ // advance)
+ // -------------------------------------------------------------------------
+ bool isFixedPitch() const;
+
+ // -------------------------------------------------------------------------
+ // Setup a Skia painting context to use this font.
+ // -------------------------------------------------------------------------
+ void setupPaint(SkPaint*) const;
+
+ unsigned hash() const;
+ float size() const { return m_textSize; }
+
+ bool operator==(const FontPlatformData&) const;
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); }
+
+private:
+ // FIXME: Could SkAutoUnref be used here?
+ SkTypeface* m_typeface;
+ float m_textSize;
+ bool m_fakeBold;
+ bool m_fakeItalic;
+
+ SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); }
+};
+
+} // namespace WebCore
+
+#endif // ifdef FontPlatformData_h
diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp
new file mode 100644
index 0000000..ed326c8
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontUtilsChromiumWin.h"
+
+#include <limits>
+
+#include "PlatformString.h"
+#include "StringHash.h"
+#include "UniscribeHelper.h"
+#include <unicode/locid.h>
+#include <unicode/uchar.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+namespace {
+
+// A simple mapping from UScriptCode to family name. This is a sparse array,
+// which works well since the range of UScriptCode values is small.
+typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT];
+
+void initializeScriptFontMap(ScriptToFontMap& scriptFontMap)
+{
+ struct FontMap {
+ UScriptCode script;
+ const UChar* family;
+ };
+
+ const static FontMap fontMap[] = {
+ {USCRIPT_LATIN, L"times new roman"},
+ {USCRIPT_GREEK, L"times new roman"},
+ {USCRIPT_CYRILLIC, L"times new roman"},
+ {USCRIPT_SIMPLIFIED_HAN, L"simsun"},
+ {USCRIPT_HIRAGANA, L"ms pgothic"},
+ {USCRIPT_KATAKANA, L"ms pgothic"},
+ {USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"},
+ {USCRIPT_HANGUL, L"gulim"},
+ {USCRIPT_THAI, L"tahoma"},
+ {USCRIPT_HEBREW, L"david"},
+ {USCRIPT_ARABIC, L"tahoma"},
+ {USCRIPT_DEVANAGARI, L"mangal"},
+ {USCRIPT_BENGALI, L"vrinda"},
+ {USCRIPT_GURMUKHI, L"raavi"},
+ {USCRIPT_GUJARATI, L"shruti"},
+ {USCRIPT_ORIYA, L"kalinga"},
+ {USCRIPT_TAMIL, L"latha"},
+ {USCRIPT_TELUGU, L"gautami"},
+ {USCRIPT_KANNADA, L"tunga"},
+ {USCRIPT_MALAYALAM, L"kartika"},
+ {USCRIPT_LAO, L"dokchampa"},
+ {USCRIPT_TIBETAN, L"microsoft himalaya"},
+ {USCRIPT_GEORGIAN, L"sylfaen"},
+ {USCRIPT_ARMENIAN, L"sylfaen"},
+ {USCRIPT_ETHIOPIC, L"nyala"},
+ {USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"},
+ {USCRIPT_CHEROKEE, L"plantagenet cherokee"},
+ {USCRIPT_YI, L"microsoft yi balti"},
+ {USCRIPT_SINHALA, L"iskoola pota"},
+ {USCRIPT_SYRIAC, L"estrangelo edessa"},
+ {USCRIPT_KHMER, L"daunpenh"},
+ {USCRIPT_THAANA, L"mv boli"},
+ {USCRIPT_MONGOLIAN, L"mongolian balti"},
+ {USCRIPT_MYANMAR, L"padauk"},
+ // For USCRIPT_COMMON, we map blocks to scripts when
+ // that makes sense.
+ };
+
+ for (int i = 0; i < sizeof(fontMap) / sizeof(fontMap[0]); ++i)
+ scriptFontMap[fontMap[i].script] = fontMap[i].family;
+
+ // Initialize the locale-dependent mapping.
+ // Since Chrome synchronizes the ICU default locale with its UI locale,
+ // this ICU locale tells the current UI locale of Chrome.
+ Locale locale = Locale::getDefault();
+ const UChar* localeFamily = 0;
+ if (locale == Locale::getJapanese())
+ localeFamily = scriptFontMap[USCRIPT_HIRAGANA];
+ else if (locale == Locale::getKorean())
+ localeFamily = scriptFontMap[USCRIPT_HANGUL];
+ else {
+ // Use Simplified Chinese font for all other locales including
+ // Traditional Chinese because Simsun (SC font) has a wider
+ // coverage (covering both SC and TC) than PMingLiu (TC font).
+ // Note that |fontMap| does not have a separate entry for
+ // USCRIPT_TRADITIONAL_HAN for that reason.
+ // This also speeds up the TC version of Chrome when rendering SC
+ // pages.
+ localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN];
+ }
+ if (localeFamily)
+ scriptFontMap[USCRIPT_HAN] = localeFamily;
+}
+
+const int kUndefinedAscent = std::numeric_limits<int>::min();
+
+// Given an HFONT, return the ascent. If GetTextMetrics fails,
+// kUndefinedAscent is returned, instead.
+int getAscent(HFONT hfont)
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, hfont);
+ TEXTMETRIC tm;
+ BOOL gotMetrics = GetTextMetrics(dc, &tm);
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ return gotMetrics ? tm.tmAscent : kUndefinedAscent;
+}
+
+struct FontData {
+ FontData()
+ : hfont(0)
+ , ascent(kUndefinedAscent)
+ , scriptCache(0)
+ {
+ }
+
+ HFONT hfont;
+ int ascent;
+ mutable SCRIPT_CACHE scriptCache;
+};
+
+// Again, using hash_map does not earn us much here. page_cycler_test intl2
+// gave us a 'better' result with map than with hash_map even though they're
+// well-within 1-sigma of each other so that the difference is not significant.
+// On the other hand, some pages in intl2 seem to take longer to load with map
+// in the 1st pass. Need to experiment further.
+typedef HashMap<String, FontData> FontDataCache;
+
+} // namespace
+
+// FIXME: this is font fallback code version 0.1
+// - Cover all the scripts
+// - Get the default font for each script/generic family from the
+// preference instead of hardcoding in the source.
+// (at least, read values from the registry for IE font settings).
+// - Support generic families (from FontDescription)
+// - If the default font for a script is not available,
+// try some more fonts known to support it. Finally, we can
+// use EnumFontFamilies or similar APIs to come up with a list of
+// fonts supporting the script and cache the result.
+// - Consider using UnicodeSet (or UnicodeMap) converted from
+// GLYPHSET (BMP) or directly read from truetype cmap tables to
+// keep track of which character is supported by which font
+// - Update script_font_cache in response to WM_FONTCHANGE
+
+const UChar* getFontFamilyForScript(UScriptCode script,
+ FontDescription::GenericFamilyType generic)
+{
+ static ScriptToFontMap scriptFontMap;
+ static bool initialized = false;
+ if (!initialized) {
+ initializeScriptFontMap(scriptFontMap);
+ initialized = true;
+ }
+ if (script == USCRIPT_INVALID_CODE)
+ return 0;
+ ASSERT(script < USCRIPT_CODE_LIMIT);
+ return scriptFontMap[script];
+}
+
+// FIXME:
+// - Handle 'Inherited', 'Common' and 'Unknown'
+// (see http://www.unicode.org/reports/tr24/#Usage_Model )
+// For 'Inherited' and 'Common', perhaps we need to
+// accept another parameter indicating the previous family
+// and just return it.
+// - All the characters (or characters up to the point a single
+// font can cover) need to be taken into account
+const UChar* getFallbackFamily(const UChar* characters,
+ int length,
+ FontDescription::GenericFamilyType generic,
+ UChar32* charChecked,
+ UScriptCode* scriptChecked)
+{
+ ASSERT(characters && characters[0] && length > 0);
+ UScriptCode script = USCRIPT_COMMON;
+
+ // Sometimes characters common to script (e.g. space) is at
+ // the beginning of a string so that we need to skip them
+ // to get a font required to render the string.
+ int i = 0;
+ UChar32 ucs4 = 0;
+ while (i < length && script == USCRIPT_COMMON || script == USCRIPT_INVALID_CODE) {
+ U16_NEXT(characters, i, length, ucs4);
+ UErrorCode err = U_ZERO_ERROR;
+ script = uscript_getScript(ucs4, &err);
+ // silently ignore the error
+ }
+
+ // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for
+ // Han (determined in a locale-dependent way above). Full-width ASCII
+ // characters are rather widely used in Japanese and Chinese documents and
+ // they're fully covered by Chinese, Japanese and Korean fonts.
+ if (0xFF00 < ucs4 && ucs4 < 0xFF5F)
+ script = USCRIPT_HAN;
+
+ // There are a lot of characters in USCRIPT_COMMON that can be covered
+ // by fonts for scripts closely related to them. See
+ // http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:]
+ // FIXME: make this more efficient with a wider coverage
+ if (script == USCRIPT_COMMON || script == USCRIPT_INHERITED) {
+ UBlockCode block = ublock_getCode(ucs4);
+ switch (block) {
+ case UBLOCK_BASIC_LATIN:
+ script = USCRIPT_LATIN;
+ break;
+ case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
+ script = USCRIPT_HAN;
+ break;
+ case UBLOCK_HIRAGANA:
+ case UBLOCK_KATAKANA:
+ script = USCRIPT_HIRAGANA;
+ break;
+ case UBLOCK_ARABIC:
+ script = USCRIPT_ARABIC;
+ break;
+ case UBLOCK_GREEK:
+ script = USCRIPT_GREEK;
+ break;
+ case UBLOCK_DEVANAGARI:
+ // For Danda and Double Danda (U+0964, U+0965), use a Devanagari
+ // font for now although they're used by other scripts as well.
+ // Without a context, we can't do any better.
+ script = USCRIPT_DEVANAGARI;
+ break;
+ case UBLOCK_ARMENIAN:
+ script = USCRIPT_ARMENIAN;
+ break;
+ case UBLOCK_GEORGIAN:
+ script = USCRIPT_GEORGIAN;
+ break;
+ case UBLOCK_KANNADA:
+ script = USCRIPT_KANNADA;
+ break;
+ }
+ }
+
+ // Another lame work-around to cover non-BMP characters.
+ const UChar* family = getFontFamilyForScript(script, generic);
+ if (!family) {
+ int plane = ucs4 >> 16;
+ switch (plane) {
+ case 1:
+ family = L"code2001";
+ break;
+ case 2:
+ family = L"simsun-extb";
+ break;
+ default:
+ family = L"lucida sans unicode";
+ }
+ }
+
+ if (charChecked)
+ *charChecked = ucs4;
+ if (scriptChecked)
+ *scriptChecked = script;
+ return family;
+}
+
+// Be aware that this is not thread-safe.
+bool getDerivedFontData(const UChar* family,
+ int style,
+ LOGFONT* logfont,
+ int* ascent,
+ HFONT* hfont,
+ SCRIPT_CACHE** scriptCache)
+{
+ ASSERT(logfont);
+ ASSERT(family);
+ ASSERT(*family);
+
+ // It does not matter that we leak font data when we exit.
+ static FontDataCache fontDataCache;
+
+ // FIXME: This comes up pretty high in the profile so that
+ // we need to measure whether using SHA256 (after coercing all the
+ // fields to char*) is faster than String::format.
+ String fontKey = String::format("%1d:%d:%ls", style, logfont->lfHeight, family);
+ FontDataCache::iterator iter = fontDataCache.find(fontKey);
+ FontData* derived;
+ if (iter == fontDataCache.end()) {
+ ASSERT(wcslen(family) < LF_FACESIZE);
+ wcscpy_s(logfont->lfFaceName, LF_FACESIZE, family);
+ // FIXME: CreateFontIndirect always comes up with
+ // a font even if there's no font matching the name. Need to
+ // check it against what we actually want (as is done in
+ // FontCacheWin.cpp)
+ pair<FontDataCache::iterator, bool> entry = fontDataCache.add(fontKey, FontData());
+ derived = &entry.first->second;
+ derived->hfont = CreateFontIndirect(logfont);
+ // GetAscent may return kUndefinedAscent, but we still want to
+ // cache it so that we won't have to call CreateFontIndirect once
+ // more for HFONT next time.
+ derived->ascent = getAscent(derived->hfont);
+ } else {
+ derived = &iter->second;
+ // Last time, GetAscent failed so that only HFONT was
+ // cached. Try once more assuming that TryPreloadFont
+ // was called by a caller between calls.
+ if (kUndefinedAscent == derived->ascent)
+ derived->ascent = getAscent(derived->hfont);
+ }
+ *hfont = derived->hfont;
+ *ascent = derived->ascent;
+ *scriptCache = &(derived->scriptCache);
+ return *ascent != kUndefinedAscent;
+}
+
+int getStyleFromLogfont(const LOGFONT* logfont)
+{
+ // FIXME: consider defining UNDEFINED or INVALID for style and
+ // returning it when logfont is 0
+ if (!logfont) {
+ ASSERT_NOT_REACHED();
+ return FontStyleNormal;
+ }
+ return (logfont->lfItalic ? FontStyleItalic : FontStyleNormal) |
+ (logfont->lfUnderline ? FontStyleUnderlined : FontStyleNormal) |
+ (logfont->lfWeight >= 700 ? FontStyleBold : FontStyleNormal);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h
new file mode 100644
index 0000000..6a964c4
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// A collection of utilities for font handling.
+
+// FIXME: Move all methods to the files that have their callsites and remove this file.
+// *Utils files are not very WebKit-ty.
+
+#ifndef FontUtilsWin_h
+#define FontUtilsWin_h
+
+#include <usp10.h>
+#include <wchar.h>
+#include <windows.h>
+
+#include "FontDescription.h"
+#include <unicode/uscript.h>
+
+namespace WebCore {
+
+// Return a font family that supports a script and belongs to |generic| font
+// family. It can return NULL and a caller has to implement its own fallback.
+const UChar* getFontFamilyForScript(UScriptCode, FontDescription::GenericFamilyType);
+
+// Return a font family that can render |characters| based on
+// what script characters belong to. When char_checked is non-NULL,
+// it's filled with the character used to determine the script.
+// When script_checked is non-NULL, the script used to determine
+// the family is returned.
+// FIXME: This function needs a total overhaul.
+const UChar* getFallbackFamily(const UChar* characters, int length,
+ FontDescription::GenericFamilyType,
+ UChar32* charChecked,
+ UScriptCode* scriptChecked);
+
+// Derive a new HFONT by replacing lfFaceName of LOGFONT with |family|,
+// calculate the ascent for the derived HFONT, and initialize SCRIPT_CACHE
+// in FontData.
+// |style| is only used for cache key generation. |style| is
+// bit-wise OR of BOLD(1), UNDERLINED(2) and ITALIC(4) and
+// should match what's contained in LOGFONT. It should be calculated
+// by calling GetStyleFromLogFont.
+// Returns false if the font is not accessible, in which case |ascent| field
+// of |fontdata| is set to kUndefinedAscent.
+// Be aware that this is not thread-safe.
+// FIXME: Instead of having three out params, we'd better have one
+// (|*FontData|), but somehow it mysteriously messes up the layout for
+// certain complex script pages (e.g. hi.wikipedia.org) and also crashes
+// at the start-up if recently visited page list includes pages with complex
+// scripts in their title. Moreover, somehow the very first-pass of
+// intl2 page-cycler test is noticeably slower with one out param than
+// the current version although the subsequent 9 passes take about the
+// same time.
+bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**);
+
+enum {
+ FontStyleNormal = 0,
+ FontStyleBold = 1,
+ FontStyleItalic = 2,
+ FontStyleUnderlined = 4
+};
+
+// Derive style (bit-wise OR of FONT_STYLE_BOLD, FONT_STYLE_UNDERLINED, and
+// FONT_STYLE_ITALIC) from LOGFONT. Returns 0 if |*logfont| is NULL.
+int getStyleFromLogfont(const LOGFONT*);
+
+} // namespace WebCore
+
+#endif // FontUtilsWin_h
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
new file mode 100644
index 0000000..4c5cf7b
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2008, 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include <windows.h>
+#include <vector>
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "GlyphPageTreeNode.h"
+#include "SimpleFontData.h"
+#include "UniscribeHelperTextRun.h"
+#include "WindowsVersion.h"
+
+namespace WebCore {
+
+// Fills one page of font data pointers with 0 to indicate that there
+// are no glyphs for the characters.
+static void fillEmptyGlyphs(GlyphPage* page)
+{
+ for (int i = 0; i < GlyphPage::size; ++i)
+ page->setGlyphDataForIndex(i, 0, 0);
+}
+
+// Lazily initializes space glyph
+static Glyph initSpaceGlyph(HDC dc, Glyph* spaceGlyph)
+{
+ if (*spaceGlyph)
+ return *spaceGlyph;
+
+ static wchar_t space = ' ';
+ GetGlyphIndices(dc, &space, 1, spaceGlyph, 0);
+ return *spaceGlyph;
+}
+
+// Fills |length| glyphs starting at |offset| in a |page| in the Basic
+// Multilingual Plane (<= U+FFFF). The input buffer size should be the
+// same as |length|. We can use the standard Windows GDI functions here.
+// Returns true if any glyphs were found.
+static bool fillBMPGlyphs(unsigned offset,
+ unsigned length,
+ UChar* buffer,
+ GlyphPage* page,
+ const SimpleFontData* fontData,
+ bool recurse)
+{
+ HDC dc = GetDC((HWND)0);
+ HGDIOBJ oldFont = SelectObject(dc, fontData->m_font.hfont());
+
+ TEXTMETRIC tm = {0};
+ if (!GetTextMetrics(dc, &tm)) {
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ if (recurse) {
+ if (ChromiumBridge::ensureFontLoaded(fontData->m_font.hfont()))
+ return fillBMPGlyphs(offset, length, buffer, page, fontData, false);
+ else {
+ fillEmptyGlyphs(page);
+ 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.
+ // See http://crbug.com/6401
+ ASSERT_NOT_REACHED();
+ fillEmptyGlyphs(page);
+ return false;
+ }
+ }
+
+ // FIXME: GetGlyphIndices() sets each item of localGlyphBuffer[]
+ // with the one of the values listed below.
+ // * With the GGI_MARK_NONEXISTING_GLYPHS flag
+ // + If the font has a glyph available for the character,
+ // localGlyphBuffer[i] > 0x0.
+ // + If the font does not have glyphs available for the character,
+ // localGlyphBuffer[i] = 0x1F (TrueType Collection?) or
+ // 0xFFFF (OpenType?).
+ // * Without the GGI_MARK_NONEXISTING_GLYPHS flag
+ // + If the font has a glyph available for the character,
+ // localGlyphBuffer[i] > 0x0.
+ // + If the font does not have glyphs available for the character,
+ // localGlyphBuffer[i] = 0x80.
+ // (Windows automatically assigns the glyph for a box character to
+ // prevent ExtTextOut() from returning errors.)
+ // To avoid from hurting the rendering performance, this code just
+ // tells WebKit whether or not the all glyph indices for the given
+ // characters are 0x80 (i.e. a possibly-invalid glyph) and let it
+ // use alternative fonts for the characters.
+ // Although this may cause a problem, it seems to work fine as far as I
+ // have tested. (Obviously, I need more tests.)
+ WORD localGlyphBuffer[GlyphPage::size];
+
+ // FIXME: I find some Chinese characters can not be correctly displayed
+ // when call GetGlyphIndices without flag GGI_MARK_NONEXISTING_GLYPHS,
+ // because the corresponding glyph index is set as 0x20 when current font
+ // does not have glyphs available for the character. According a blog post
+ // http://blogs.msdn.com/michkap/archive/2006/06/28/649791.aspx
+ // I think we should switch to the way about calling GetGlyphIndices with
+ // flag GGI_MARK_NONEXISTING_GLYPHS, it should be OK according the
+ // description of MSDN.
+ // Also according to Jungshik and Hironori's suggestion and modification
+ // we treat turetype and raster Font as different way when windows version
+ // is less than Vista.
+ GetGlyphIndices(dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS);
+
+ // Copy the output to the GlyphPage
+ bool haveGlyphs = false;
+ int invalidGlyph = 0xFFFF;
+ if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE))
+ invalidGlyph = 0x1F;
+
+ Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled.
+
+ for (unsigned i = 0; i < length; i++) {
+ UChar c = buffer[i];
+ Glyph glyph = localGlyphBuffer[i];
+ const SimpleFontData* glyphFontData = fontData;
+ // When this character should be a space, we ignore whatever the font
+ // says and use a space. Otherwise, if fonts don't map one of these
+ // space or zero width glyphs, we will get a box.
+ if (Font::treatAsSpace(c))
+ // Hard code the glyph indices for characters that should be
+ // treated like spaces.
+ glyph = initSpaceGlyph(dc, &spaceGlyph);
+ else if (Font::treatAsZeroWidthSpace(c) || c == 0x200B) {
+ // FIXME: change Font::treatAsZeroWidthSpace to use
+ // u_hasBinaryProperty, per jungshik's comment here:
+ // https://bugs.webkit.org/show_bug.cgi?id=20237#c6.
+ // Then the additional OR above won't be necessary.
+ glyph = initSpaceGlyph(dc, &spaceGlyph);
+ glyphFontData = fontData->zeroWidthFontData();
+ } else if (glyph == invalidGlyph) {
+ // WebKit expects both the glyph index and FontData
+ // pointer to be 0 if the glyph is not present
+ glyph = 0;
+ glyphFontData = 0;
+ } else {
+ if (SimpleFontData::isCJKCodePoint(c))
+ glyphFontData = fontData->cjkWidthFontData();
+ haveGlyphs = true;
+ }
+ page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData);
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+ return haveGlyphs;
+}
+
+// For non-BMP characters, each is two words (UTF-16) and the input buffer
+// size is 2 * |length|. Since GDI doesn't know how to handle non-BMP
+// characters, we must use Uniscribe to tell us the glyph indices.
+//
+// We don't want to call this in the case of "regular" characters since some
+// fonts may not have the correct combining rules for accents. See the notes
+// at the bottom of ScriptGetCMap. We can't use ScriptGetCMap, though, since
+// it doesn't seem to support UTF-16, despite what this blog post says:
+// http://blogs.msdn.com/michkap/archive/2006/06/29/650680.aspx
+//
+// So we fire up the full Uniscribe doohicky, give it our string, and it will
+// correctly handle the UTF-16 for us. The hard part is taking this and getting
+// the glyph indices back out that correspond to the correct input characters,
+// since they may be missing.
+//
+// Returns true if any glyphs were found.
+static bool fillNonBMPGlyphs(unsigned offset,
+ unsigned length,
+ UChar* buffer,
+ GlyphPage* page,
+ const SimpleFontData* fontData)
+{
+ bool haveGlyphs = false;
+
+ UniscribeHelperTextRun state(buffer, length * 2, false,
+ fontData->m_font.hfont(),
+ fontData->m_font.scriptCache(),
+ fontData->m_font.scriptFontProperties());
+ state.setInhibitLigate(true);
+ state.init();
+
+ for (unsigned i = 0; i < length; i++) {
+ // Each character in this input buffer is a surrogate pair, which
+ // consists of two UChars. So, the offset for its i-th character is
+ // (i * 2).
+ WORD glyph = state.firstGlyphForCharacter(i * 2);
+ if (glyph) {
+ haveGlyphs = true;
+ page->setGlyphDataForIndex(offset + i, glyph, fontData);
+ } else
+ // Clear both glyph and fontData fields.
+ page->setGlyphDataForIndex(offset + i, 0, 0);
+ }
+ return haveGlyphs;
+}
+
+// We're supposed to return true if there are any glyphs in the range
+// specified by |offset| and |length| in our font,
+// false if there are none.
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer,
+ unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // We have to handle BMP and non-BMP characters differently.
+ // FIXME: Add assertions to make sure that buffer is entirely in BMP
+ // or entirely in non-BMP.
+ if (bufferLength == length)
+ return fillBMPGlyphs(offset, length, characterBuffer, this, fontData, true);
+
+ if (bufferLength == 2 * length) {
+ // A non-BMP input buffer will be twice as long as output glyph buffer
+ // because each character in the non-BMP input buffer will be
+ // represented by a surrogate pair (two UChar's).
+ return fillNonBMPGlyphs(offset, length, characterBuffer, this, fontData);
+ }
+
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp
new file mode 100644
index 0000000..6024d43
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2008, 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "Font.h"
+#include "SimpleFontData.h"
+
+#include "SkTemplates.h"
+#include "SkPaint.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) {
+ SkDebugf("%s last char is high-surrogate", __FUNCTION__);
+ return false;
+ }
+
+ SkPaint paint;
+ fontData->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length);
+ uint16_t* glyphs = glyphStorage.get();
+ // textToGlyphs takes a byte count, not a glyph count so we multiply by two.
+ unsigned count = paint.textToGlyphs(buffer, bufferLength * 2, glyphs);
+ if (count != length) {
+ SkDebugf("%s count != length\n", __FUNCTION__);
+ return false;
+ }
+
+ unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero
+ for (unsigned i = 0; i < length; i++) {
+ setGlyphDataForIndex(offset + i, glyphs[i], glyphs[i] ? fontData : NULL);
+ allGlyphs |= glyphs[i];
+ }
+
+ return allGlyphs != 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp
new file mode 100644
index 0000000..a5a6e1f
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008, 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+Icon::Icon(const PlatformIcon& icon)
+ : m_icon(icon)
+{
+}
+
+Icon::~Icon()
+{
+}
+
+PassRefPtr<Icon> Icon::createIconForFile(const String&)
+{
+ notImplemented();
+ return 0;
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&)
+{
+ notImplemented();
+ return 0;
+}
+
+void Icon::paint(GraphicsContext*, const IntRect&)
+{
+ notImplemented();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp
new file mode 100644
index 0000000..93e36ba
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "PassRefPtr.h"
+
+// FIXME: These are temporary stubs, we need real implementations which
+// may come in the form of IconChromium.cpp. The Windows Chromium
+// implementation is currently in IconWin.cpp.
+
+namespace WebCore {
+
+PassRefPtr<Icon> Icon::createIconForFile(const String&)
+{
+ return 0;
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&)
+{
+ return 0;
+}
+
+Icon::~Icon()
+{
+}
+
+void Icon::paint(GraphicsContext*, const IntRect&)
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp
new file mode 100644
index 0000000..b419e6f
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "GraphicsContext.h"
+#include "PlatformContextSkia.h"
+#include "PlatformString.h"
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+Icon::Icon(const PlatformIcon& icon)
+ : m_icon(icon)
+{
+}
+
+Icon::~Icon()
+{
+ if (m_icon)
+ DestroyIcon(m_icon);
+}
+
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
+{
+ SHFILEINFO sfi;
+ memset(&sfi, 0, sizeof(sfi));
+
+ String tmpFilename = filename;
+ if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON))
+ return 0;
+
+ return adoptRef(new Icon(sfi.hIcon));
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ // FIXME: support multiple files.
+ // http://code.google.com/p/chromium/issues/detail?id=4092
+ if (!filenames.size())
+ return 0;
+
+ return createIconForFile(filenames[0]);
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ HDC hdc = context->platformContext()->canvas()->beginPlatformPaint();
+ DrawIconEx(hdc, rect.x(), rect.y(), m_icon, rect.width(), rect.height(), 0, 0, DI_NORMAL);
+ context->platformContext()->canvas()->endPlatformPaint();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ImageBufferData.h b/WebCore/platform/graphics/chromium/ImageBufferData.h
new file mode 100644
index 0000000..504b893
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/ImageBufferData.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+#include "PlatformContextSkia.h"
+
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ skia::PlatformCanvas m_canvas;
+ PlatformContextSkia m_platformContext;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/WebCore/platform/graphics/chromium/ImageChromiumMac.mm b/WebCore/platform/graphics/chromium/ImageChromiumMac.mm
new file mode 100644
index 0000000..073a409
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/ImageChromiumMac.mm
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// A wrapper around Uniscribe that provides a reasonable API.
+
+#include "config.h"
+#include "BitmapImage.h"
+
+#include "ChromiumBridge.h"
+#include "Image.h"
+
+namespace WebCore {
+
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ return ChromiumBridge::loadPlatformImageResource(name);
+}
+
+// FIXME: These are temporary stubs, we need real implementations which
+// may come in the form of ImageChromium.cpp. The Windows Chromium
+// implementation is currently in ImageSkia.cpp.
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
new file mode 100644
index 0000000..959147a
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayerPrivateChromium_h
+#define MediaPlayerPrivateChromium_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+
+namespace WebCore {
+
+class MediaPlayerPrivate : public Noncopyable {
+public:
+ MediaPlayerPrivate(MediaPlayer*);
+ ~MediaPlayerPrivate();
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+
+ void load(const String& url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+ void setEndTime(float);
+
+ void setRate(float);
+ void setVolume(float);
+
+ 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 setRect(const IntRect&);
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ static void getSupportedTypes(HashSet<String>&);
+ static bool isAvailable();
+
+ // Public methods to be called by WebMediaPlayer
+ FrameView* frameView();
+ void networkStateChanged();
+ void readyStateChanged();
+ void timeChanged();
+ void volumeChanged();
+ void repaint();
+
+private:
+ MediaPlayer* m_player;
+ void* m_data;
+};
+
+} // namespace WebCore
+
+#endif
+
+#endif // MediaPlayerPrivateChromium_h
diff --git a/WebCore/platform/graphics/chromium/PlatformIcon.h b/WebCore/platform/graphics/chromium/PlatformIcon.h
new file mode 100644
index 0000000..51613b8
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/PlatformIcon.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PlatformIcon_h
+#define PlatformIcon_h
+
+typedef struct HICON__* HICON;
+
+namespace WebCore {
+
+typedef HICON PlatformIcon;
+
+} // namespace WebCore
+
+#endif // PlatformIcon_h
diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
new file mode 100644
index 0000000..06e997f
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <objidl.h>
+#include <mlang.h>
+
+namespace WebCore {
+
+static inline float scaleEmToUnits(float x, int unitsPerEm)
+{
+ return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x;
+}
+
+void SimpleFontData::platformInit()
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_font.hfont());
+
+ TEXTMETRIC textMetric = {0};
+ if (!GetTextMetrics(dc, &textMetric)) {
+ if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) {
+ // Retry GetTextMetrics.
+ // FIXME: Handle gracefully the error if this call also fails.
+ // See http://crbug.com/6401.
+ if (!GetTextMetrics(dc, &textMetric))
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ m_avgCharWidth = textMetric.tmAveCharWidth;
+ m_maxCharWidth = textMetric.tmMaxCharWidth;
+
+ m_ascent = textMetric.tmAscent;
+ m_descent = textMetric.tmDescent;
+ m_lineGap = textMetric.tmExternalLeading;
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.
+
+ OUTLINETEXTMETRIC outlineTextMetric;
+ if (GetOutlineTextMetrics(dc, sizeof(outlineTextMetric), &outlineTextMetric) > 0) {
+ // This is a TrueType font. We might be able to get an accurate xHeight.
+ GLYPHMETRICS glyphMetrics = {0};
+ MAT2 identityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
+ DWORD len = GetGlyphOutlineW(dc, 'x', GGO_METRICS, &glyphMetrics, 0, 0, &identityMatrix);
+ if (len != GDI_ERROR && glyphMetrics.gmBlackBoxY > 0)
+ m_xHeight = static_cast<float>(glyphMetrics.gmBlackBoxY);
+ }
+
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+}
+
+void SimpleFontData::platformDestroy()
+{
+ // We don't hash this on Win32, so it's effectively owned by us.
+ delete m_smallCapsFontData;
+ m_smallCapsFontData = 0;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ LOGFONT winFont;
+ GetObject(m_font.hfont(), sizeof(LOGFONT), &winFont);
+ float smallCapsSize = 0.70f * fontDescription.computedSize();
+ // Unlike WebKit trunk, we don't multiply the size by 32. That seems
+ // to be some kind of artifact of their CG backend, or something.
+ winFont.lfHeight = -lroundf(smallCapsSize);
+ HFONT hfont = CreateFontIndirect(&winFont);
+ m_smallCapsFontData =
+ new SimpleFontData(FontPlatformData(hfont, smallCapsSize));
+ }
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // This used to be implemented with IMLangFontLink2, but since that code has
+ // been disabled, this would always return false anyway.
+ return false;
+}
+
+void SimpleFontData::determinePitch()
+{
+ // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_font.hfont());
+
+ // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
+ // is *not* fixed pitch. Unbelievable but true.
+ TEXTMETRIC textMetric = {0};
+ if (!GetTextMetrics(dc, &textMetric)) {
+ if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) {
+ // Retry GetTextMetrics.
+ // FIXME: Handle gracefully the error if this call also fails.
+ // See http://crbug.com/6401.
+ if (!GetTextMetrics(dc, &textMetric))
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+ m_treatAsFixedPitch = ((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_font.hfont());
+
+ int width = 0;
+ if (!GetCharWidthI(dc, glyph, 1, 0, &width)) {
+ // Ask the browser to preload the font and retry.
+ if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) {
+ // 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();
+ }
+ }
+
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ return static_cast<float>(width);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp
new file mode 100644
index 0000000..8200175
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include "Logging.h"
+#include "NotImplemented.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkTime.h"
+
+namespace WebCore {
+
+// Smallcaps versions of fonts are 70% the size of the normal font.
+static const float smallCapsFraction = 0.7f;
+
+void SimpleFontData::platformInit()
+{
+ SkPaint paint;
+ SkPaint::FontMetrics metrics;
+
+ m_font.setupPaint(&paint);
+ paint.getFontMetrics(&metrics);
+
+ // Beware those who step here: This code is designed to match Win32 font
+ // metrics *exactly*.
+ if (metrics.fVDMXMetricsValid) {
+ m_ascent = metrics.fVDMXAscent;
+ m_descent = metrics.fVDMXDescent;
+ } else {
+ m_ascent = SkScalarRound(-metrics.fAscent);
+ m_descent = SkScalarRound(metrics.fHeight) - m_ascent;
+ }
+
+ if (metrics.fXHeight)
+ m_xHeight = metrics.fXHeight;
+ else {
+ // hack taken from the Windows port
+ m_xHeight = static_cast<float>(m_ascent) * 0.56;
+ }
+
+ m_lineGap = SkScalarRound(metrics.fLeading);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is
+ // calculated for us, but we need to calculate m_maxCharWidth and
+ // m_avgCharWidth in order for text entry widgets to be sized correctly.
+
+ m_maxCharWidth = SkScalarRound(metrics.fXRange * SkScalarRound(m_font.size()));
+
+ if (metrics.fAvgCharWidth)
+ m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth);
+ else {
+ m_avgCharWidth = m_xHeight;
+
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+
+ if (glyphPageZero) {
+ static const UChar32 x_char = 'x';
+ const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(x_char).glyph;
+
+ if (xGlyph)
+ m_avgCharWidth = widthForGlyph(xGlyph);
+ }
+ }
+}
+
+void SimpleFontData::platformDestroy()
+{
+ delete m_smallCapsFontData;
+ m_smallCapsFontData = 0;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ const float smallCapsSize = lroundf(fontDescription.computedSize() * smallCapsFraction);
+ m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, smallCapsSize));
+ }
+
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ SkPaint paint;
+ static const unsigned maxBufferCount = 64;
+ uint16_t glyphs[maxBufferCount];
+
+ m_font.setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ while (length > 0) {
+ int n = SkMin32(length, SK_ARRAY_COUNT(glyphs));
+
+ // textToGlyphs takes a byte count so we double the character count.
+ int count = paint.textToGlyphs(characters, n * 2, glyphs);
+ for (int i = 0; i < count; i++) {
+ if (0 == glyphs[i])
+ return false; // missing glyph
+ }
+
+ characters += n;
+ length -= n;
+ }
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = platformData().isFixedPitch();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ SkASSERT(sizeof(glyph) == 2); // compile-time assert
+
+ SkPaint paint;
+
+ m_font.setupPaint(&paint);
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ SkScalar width = paint.measureText(&glyph, 2);
+
+ return SkScalarToFloat(width);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp
new file mode 100644
index 0000000..798ee32
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ThemeHelperChromiumWin.h"
+
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+ThemeHelperWin::ThemeHelperWin(GraphicsContext* context, const IntRect& rect)
+ : m_orgContext(context)
+ , m_orgMatrix(context->getCTM())
+ , m_orgRect(rect)
+{
+ if (m_orgMatrix.b() != 0 || m_orgMatrix.c() != 0) { // Check for skew.
+ // Complicated effects, make a copy and draw the bitmap there.
+ m_type = COPY;
+ m_rect.setSize(rect.size());
+
+ m_newBuffer.set(ImageBuffer::create(rect.size(), false).release());
+
+ // Theme drawing messes with the transparency.
+ // FIXME: Ideally, we would leave this transparent, but I was
+ // having problems with button drawing, so we fill with white. Buttons
+ // looked good with transparent here and no fixing up of the alpha
+ // later, but text areas didn't. This makes text areas look good but
+ // gives buttons a white halo. Is there a way to fix this? I think
+ // buttons actually have antialised edges which is just not possible
+ // to handle on a transparent background given that it messes with the
+ // alpha channel.
+ FloatRect newContextRect(0, 0, rect.width(), rect.height());
+ GraphicsContext* newContext = m_newBuffer->context();
+ newContext->setFillColor(Color::white);
+ newContext->fillRect(newContextRect);
+
+ return;
+ }
+
+ if (m_orgMatrix.a() != 1.0 || m_orgMatrix.d() != 1.0) { // Check for scale.
+ // Only a scaling is applied.
+ m_type = SCALE;
+
+ // Save the transformed coordinates to draw.
+ m_rect = m_orgMatrix.mapRect(rect);
+
+ m_orgContext->save();
+ m_orgContext->concatCTM(m_orgContext->getCTM().inverse());
+ return;
+ }
+
+ // Nothing interesting.
+ m_rect = rect;
+ m_type = ORIGINAL;
+}
+
+ThemeHelperWin::~ThemeHelperWin()
+{
+ switch (m_type) {
+ case SCALE:
+ m_orgContext->restore();
+ break;
+ case COPY: {
+ // Copy the duplicate bitmap with our control to the original canvas.
+ FloatRect destRect(m_orgRect);
+ m_newBuffer->context()->platformContext()->canvas()->
+ getTopPlatformDevice().fixupAlphaBeforeCompositing();
+ m_orgContext->drawImage(m_newBuffer->image(), destRect);
+ break;
+ }
+ case ORIGINAL:
+ break;
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h
new file mode 100644
index 0000000..1771fb4
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ThemeHelperWin_h
+#define ThemeHelperWin_h
+
+#include "TransformationMatrix.h"
+#include "ImageBuffer.h"
+#include "IntRect.h"
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntRect;
+
+// Helps drawing theme elements like buttons and scroll bars. This will handle
+// translations and scalings that Windows might not, by either making Windows
+// draw the appropriate sized control, or by rendering it into an off-screen
+// context and transforming it ourselves.
+class ThemeHelperWin {
+ enum Type {
+ // Use the original canvas with no changes. This is the normal mode.
+ ORIGINAL,
+
+ // Use the original canvas but scale the rectangle of the control so
+ // that it will be the correct size, undoing any scale already on the
+ // canvas. This will have the effect of just drawing the control bigger
+ // or smaller and not actually expanding or contracting the pixels in
+ // it. This usually looks better.
+ SCALE,
+
+ // Make a copy of the control and then transform it ourselves after
+ // Windows draws it. This allows us to get complex effects.
+ COPY,
+ };
+
+public:
+ // Prepares drawing a control with the given rect to the given context.
+ ThemeHelperWin(GraphicsContext* context, const IntRect& rect);
+ ~ThemeHelperWin();
+
+ // Returns the context to draw the control into, which may be the original
+ // or the copy, depending on the mode.
+ GraphicsContext* context()
+ {
+ return m_newBuffer.get() ? m_newBuffer->context() : m_orgContext;
+ }
+
+ // Returns the rectangle in which to draw into the canvas() by Windows.
+ const IntRect& rect() { return m_rect; }
+
+private:
+ Type m_type;
+
+ // The original canvas to wrote to. Not owned by this class.
+ GraphicsContext* m_orgContext;
+ TransformationMatrix m_orgMatrix;
+ IntRect m_orgRect;
+
+ // When m_type == COPY, this will be a new surface owned by this class that
+ // represents the copy.
+ OwnPtr<ImageBuffer> m_newBuffer;
+
+ // The control rectangle in the coordinate space of canvas().
+ IntRect m_rect;
+};
+
+} // namespace WebCore
+
+#endif // ThemeHelperWin_h
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
new file mode 100644
index 0000000..caeb959
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp
@@ -0,0 +1,902 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "UniscribeHelper.h"
+
+#include <windows.h>
+
+#include "FontUtilsChromiumWin.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+// This function is used to see where word spacing should be applied inside
+// runs. Note that this must match Font::treatAsSpace so we all agree where
+// and how much space this is, so we don't want to do more general Unicode
+// "is this a word break" thing.
+static bool treatAsSpace(UChar c)
+{
+ return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0;
+}
+
+// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid
+// and blank glyphs. Just because ScriptShape succeeds does not mean
+// that a text run is rendered correctly. Some characters may be rendered
+// with default/invalid/blank glyphs. Therefore, we need to check if the glyph
+// array returned by ScriptShape contains any of those glyphs to make
+// sure that the text run is rendered successfully.
+static bool containsMissingGlyphs(WORD *glyphs,
+ int length,
+ SCRIPT_FONTPROPERTIES* properties)
+{
+ for (int i = 0; i < length; ++i) {
+ if (glyphs[i] == properties->wgDefault
+ || (glyphs[i] == properties->wgInvalid
+ && glyphs[i] != properties->wgBlank))
+ return true;
+ }
+
+ return false;
+}
+
+// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque
+// handle and we can't directly query it to make a new HFONT sharing
+// its characteristics (height, style, etc) except for family name.
+// This function uses GetObject to convert HFONT back to LOGFONT,
+// resets the fields of LOGFONT and calculates style to use later
+// for the creation of a font identical to HFONT other than family name.
+static void setLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style)
+{
+ ASSERT(hfont && logfont);
+ if (!hfont || !logfont)
+ return;
+
+ GetObject(hfont, sizeof(LOGFONT), logfont);
+ // We reset these fields to values appropriate for CreateFontIndirect.
+ // while keeping lfHeight, which is the most important value in creating
+ // a new font similar to hfont.
+ logfont->lfWidth = 0;
+ logfont->lfEscapement = 0;
+ logfont->lfOrientation = 0;
+ logfont->lfCharSet = DEFAULT_CHARSET;
+ logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ logfont->lfQuality = DEFAULT_QUALITY; // Honor user's desktop settings.
+ logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ if (style)
+ *style = getStyleFromLogfont(logfont);
+}
+
+UniscribeHelper::UniscribeHelper(const UChar* input,
+ int inputLength,
+ bool isRtl,
+ HFONT hfont,
+ SCRIPT_CACHE* scriptCache,
+ SCRIPT_FONTPROPERTIES* fontProperties)
+ : m_input(input)
+ , m_inputLength(inputLength)
+ , m_isRtl(isRtl)
+ , m_hfont(hfont)
+ , m_scriptCache(scriptCache)
+ , m_fontProperties(fontProperties)
+ , m_directionalOverride(false)
+ , m_inhibitLigate(false)
+ , m_letterSpacing(0)
+ , m_spaceWidth(0)
+ , m_wordSpacing(0)
+ , m_ascent(0)
+{
+ m_logfont.lfFaceName[0] = 0;
+}
+
+UniscribeHelper::~UniscribeHelper()
+{
+}
+
+void UniscribeHelper::initWithOptionalLengthProtection(bool lengthProtection)
+{
+ // We cap the input length and just don't do anything. We'll allocate a lot
+ // of things of the size of the number of characters, so the allocated
+ // memory will be several times the input length. Plus shaping such a large
+ // buffer may be a form of denial of service. No legitimate text should be
+ // this long. It also appears that Uniscribe flatly rejects very long
+ // strings, so we don't lose anything by doing this.
+ //
+ // The input length protection may be disabled by the unit tests to cause
+ // an error condition.
+ static const int kMaxInputLength = 65535;
+ if (m_inputLength == 0 || (lengthProtection && m_inputLength > kMaxInputLength))
+ return;
+
+ fillRuns();
+ fillShapes();
+ fillScreenOrder();
+}
+
+int UniscribeHelper::width() const
+{
+ int width = 0;
+ for (int itemIndex = 0; itemIndex < static_cast<int>(m_runs.size()); itemIndex++)
+ width += advanceForItem(itemIndex);
+ return width;
+}
+
+void UniscribeHelper::justify(int additionalSpace)
+{
+ // Count the total number of glyphs we have so we know how big to make the
+ // buffers below.
+ int totalGlyphs = 0;
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ int runIndex = m_screenOrder[run];
+ totalGlyphs += static_cast<int>(m_shapes[runIndex].glyphLength());
+ }
+ if (totalGlyphs == 0)
+ return; // Nothing to do.
+
+ // We make one big buffer in screen order of all the glyphs we are drawing
+ // across runs so that the justification function will adjust evenly across
+ // all glyphs.
+ Vector<SCRIPT_VISATTR, 64> visualAttributes;
+ visualAttributes.resize(totalGlyphs);
+ Vector<int, 64> advances;
+ advances.resize(totalGlyphs);
+ Vector<int, 64> justify;
+ justify.resize(totalGlyphs);
+
+ // Build the packed input.
+ int destIndex = 0;
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ int runIndex = m_screenOrder[run];
+ const Shaping& shaping = m_shapes[runIndex];
+
+ for (int i = 0; i < shaping.glyphLength(); i++, destIndex++) {
+ memcpy(&visualAttributes[destIndex], &shaping.m_visualAttributes[i],
+ sizeof(SCRIPT_VISATTR));
+ advances[destIndex] = shaping.m_advance[i];
+ }
+ }
+
+ // The documentation for Scriptjustify is wrong, the parameter is the space
+ // to add and not the width of the column you want.
+ const int minKashida = 1; // How do we decide what this should be?
+ ScriptJustify(&visualAttributes[0], &advances[0], totalGlyphs,
+ additionalSpace, minKashida, &justify[0]);
+
+ // Now we have to unpack the justification amounts back into the runs so
+ // the glyph indices match.
+ int globalGlyphIndex = 0;
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ int runIndex = m_screenOrder[run];
+ Shaping& shaping = m_shapes[runIndex];
+
+ shaping.m_justify.resize(shaping.glyphLength());
+ for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++)
+ shaping.m_justify[i] = justify[globalGlyphIndex];
+ }
+}
+
+int UniscribeHelper::characterToX(int offset) const
+{
+ HRESULT hr;
+ ASSERT(offset <= m_inputLength);
+
+ // Our algorithm is to traverse the items in screen order from left to
+ // right, adding in each item's screen width until we find the item with
+ // the requested character in it.
+ int width = 0;
+ for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
+ // Compute the length of this run.
+ int itemIndex = m_screenOrder[screenIndex];
+ const SCRIPT_ITEM& item = m_runs[itemIndex];
+ const Shaping& shaping = m_shapes[itemIndex];
+ int itemLength = shaping.charLength();
+
+ if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) {
+ // Character offset is in this run.
+ int charLength = offset - item.iCharPos;
+
+ int curX = 0;
+ hr = ScriptCPtoX(charLength, FALSE, itemLength,
+ shaping.glyphLength(),
+ &shaping.m_logs[0], &shaping.m_visualAttributes[0],
+ shaping.effectiveAdvances(), &item.a, &curX);
+ if (FAILED(hr))
+ return 0;
+
+ width += curX + shaping.m_prePadding;
+ ASSERT(width >= 0);
+ return width;
+ }
+
+ // Move to the next item.
+ width += advanceForItem(itemIndex);
+ }
+ ASSERT(width >= 0);
+ return width;
+}
+
+int UniscribeHelper::xToCharacter(int x) const
+{
+ // We iterate in screen order until we find the item with the given pixel
+ // position in it. When we find that guy, we ask Uniscribe for the
+ // character index.
+ HRESULT hr;
+ for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
+ int itemIndex = m_screenOrder[screenIndex];
+ int itemAdvance = advanceForItem(itemIndex);
+
+ // Note that the run may be empty if shaping failed, so we want to skip
+ // over it.
+ const Shaping& shaping = m_shapes[itemIndex];
+ int itemLength = shaping.charLength();
+ if (x <= itemAdvance && itemLength > 0) {
+ // The requested offset is within this item.
+ const SCRIPT_ITEM& item = m_runs[itemIndex];
+
+ // Account for the leading space we've added to this run that
+ // Uniscribe doesn't know about.
+ x -= shaping.m_prePadding;
+
+ int charX = 0;
+ int trailing;
+ hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(),
+ &shaping.m_logs[0], &shaping.m_visualAttributes[0],
+ shaping.effectiveAdvances(), &item.a, &charX,
+ &trailing);
+
+ // The character offset is within the item. We need to add the
+ // item's offset to transform it into the space of the TextRun
+ return charX + item.iCharPos;
+ }
+
+ // The offset is beyond this item, account for its length and move on.
+ x -= itemAdvance;
+ }
+
+ // Error condition, we don't know what to do if we don't have that X
+ // position in any of our items.
+ return 0;
+}
+
+void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to)
+{
+ HGDIOBJ oldFont = 0;
+ int curX = x;
+ bool firstRun = true;
+
+ for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
+ int itemIndex = m_screenOrder[screenIndex];
+ const SCRIPT_ITEM& item = m_runs[itemIndex];
+ const Shaping& shaping = m_shapes[itemIndex];
+
+ // Character offsets within this run. THESE MAY NOT BE IN RANGE and may
+ // be negative, etc. The code below handles this.
+ int fromChar = from - item.iCharPos;
+ int toChar = to - item.iCharPos;
+
+ // See if we need to draw any characters in this item.
+ if (shaping.charLength() == 0 ||
+ fromChar >= shaping.charLength() || toChar <= 0) {
+ // No chars in this item to display.
+ curX += advanceForItem(itemIndex);
+ continue;
+ }
+
+ // Compute the starting glyph within this span. |from| and |to| are
+ // global offsets that may intersect arbitrarily with our local run.
+ int fromGlyph, afterGlyph;
+ if (item.a.fRTL) {
+ // To compute the first glyph when going RTL, we use |to|.
+ if (toChar >= shaping.charLength())
+ // The end of the text is after (to the left) of us.
+ fromGlyph = 0;
+ else {
+ // Since |to| is exclusive, the first character we draw on the
+ // left is actually the one right before (to the right) of
+ // |to|.
+ fromGlyph = shaping.m_logs[toChar - 1];
+ }
+
+ // The last glyph is actually the first character in the range.
+ if (fromChar <= 0) {
+ // The first character to draw is before (to the right) of this
+ // span, so draw all the way to the end.
+ afterGlyph = shaping.glyphLength();
+ } else {
+ // We want to draw everything up until the character to the
+ // right of |from|. To the right is - 1, so we look that up
+ // (remember our character could be more than one glyph, so we
+ // can't look up our glyph and add one).
+ afterGlyph = shaping.m_logs[fromChar - 1];
+ }
+ } else {
+ // Easy case, everybody agrees about directions. We only need to
+ // handle boundary conditions to get a range inclusive at the
+ // beginning, and exclusive at the ending. We have to do some
+ // computation to see the glyph one past the end.
+ fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar];
+ if (toChar >= shaping.charLength())
+ afterGlyph = shaping.glyphLength();
+ else
+ afterGlyph = shaping.m_logs[toChar];
+ }
+
+ // Account for the characters that were skipped in this run. When
+ // WebKit asks us to draw a subset of the run, it actually tells us
+ // to draw at the X offset of the beginning of the run, since it
+ // doesn't know the internal position of any of our characters.
+ const int* effectiveAdvances = shaping.effectiveAdvances();
+ int innerOffset = 0;
+ for (int i = 0; i < fromGlyph; i++)
+ innerOffset += effectiveAdvances[i];
+
+ // Actually draw the glyphs we found.
+ int glyphCount = afterGlyph - fromGlyph;
+ if (fromGlyph >= 0 && glyphCount > 0) {
+ // Account for the preceeding space we need to add to this run. We
+ // don't need to count for the following space because that will be
+ // counted in advanceForItem below when we move to the next run.
+ innerOffset += shaping.m_prePadding;
+
+ // Pass 0 in when there is no justification.
+ const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph];
+
+ if (firstRun) {
+ oldFont = SelectObject(dc, shaping.m_hfont);
+ firstRun = false;
+ } else
+ SelectObject(dc, shaping.m_hfont);
+
+ // Fonts with different ascents can be used to render different
+ // runs. 'Across-runs' y-coordinate correction needs to be
+ // adjusted for each font.
+ HRESULT hr = S_FALSE;
+ for (int executions = 0; executions < 2; ++executions) {
+ hr = ScriptTextOut(dc, shaping.m_scriptCache,
+ curX + innerOffset,
+ y - shaping.m_ascentOffset,
+ 0, 0, &item.a, 0, 0,
+ &shaping.m_glyphs[fromGlyph],
+ glyphCount,
+ &shaping.m_advance[fromGlyph],
+ justify,
+ &shaping.m_offsets[fromGlyph]);
+ if (S_OK != hr && 0 == executions) {
+ // If this ScriptTextOut is called from the renderer it
+ // might fail because the sandbox is preventing it from
+ // opening the font files. If we are running in the
+ // renderer, TryToPreloadFont is overridden to ask the
+ // browser to preload the font for us so we can access it.
+ tryToPreloadFont(shaping.m_hfont);
+ continue;
+ }
+ break;
+ }
+
+ ASSERT(S_OK == hr);
+ }
+
+ curX += advanceForItem(itemIndex);
+ }
+
+ if (oldFont)
+ SelectObject(dc, oldFont);
+}
+
+WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const
+{
+ // Find the run for the given character.
+ for (int i = 0; i < static_cast<int>(m_runs.size()); i++) {
+ int firstChar = m_runs[i].iCharPos;
+ const Shaping& shaping = m_shapes[i];
+ int localOffset = charOffset - firstChar;
+ if (localOffset >= 0 && localOffset < shaping.charLength()) {
+ // The character is in this run, return the first glyph for it
+ // (should generally be the only glyph). It seems Uniscribe gives
+ // glyph 0 for empty, which is what we want to return in the
+ // "missing" case.
+ size_t glyphIndex = shaping.m_logs[localOffset];
+ if (glyphIndex >= shaping.m_glyphs.size()) {
+ // The glyph should be in this run, but the run has too few
+ // actual characters. This can happen when shaping the run
+ // fails, in which case, we should have no data in the logs at
+ // all.
+ ASSERT(shaping.m_glyphs.size() == 0);
+ return 0;
+ }
+ return shaping.m_glyphs[glyphIndex];
+ }
+ }
+
+ return 0;
+}
+
+void UniscribeHelper::fillRuns()
+{
+ HRESULT hr;
+ m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS);
+
+ SCRIPT_STATE inputState;
+ inputState.uBidiLevel = m_isRtl;
+ inputState.fOverrideDirection = m_directionalOverride;
+ inputState.fInhibitSymSwap = false;
+ inputState.fCharShape = false; // Not implemented in Uniscribe
+ inputState.fDigitSubstitute = false; // Do we want this for Arabic?
+ inputState.fInhibitLigate = m_inhibitLigate;
+ inputState.fDisplayZWG = false; // Don't draw control characters.
+ inputState.fArabicNumContext = m_isRtl; // Do we want this for Arabic?
+ inputState.fGcpClusters = false;
+ inputState.fReserved = 0;
+ inputState.fEngineReserved = 0;
+ // The psControl argument to ScriptItemize should be non-0 for RTL text,
+ // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a
+ // SCRIPT_CONTROL that is set to all zeros. Zero as a locale ID means the
+ // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx
+ static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage :16;
+ 0, // fContextDigits :1;
+ 0, // fInvertPreBoundDir :1;
+ 0, // fInvertPostBoundDir :1;
+ 0, // fLinkStringBefore :1;
+ 0, // fLinkStringAfter :1;
+ 0, // fNeutralOverride :1;
+ 0, // fNumericOverride :1;
+ 0, // fLegacyBidiClass :1;
+ 0, // fMergeNeutralItems :1;
+ 0};// fReserved :7;
+ // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState)
+ // here would be appropriate if we wanted to set the language ID, and get
+ // local digit substitution behavior. For now, don't do it.
+
+ while (true) {
+ int numberOfItems = 0;
+
+ // Ideally, we would have a way to know the runs before and after this
+ // one, and put them into the control parameter of ScriptItemize. This
+ // would allow us to shape characters properly that cross style
+ // boundaries (WebKit bug 6148).
+ //
+ // We tell ScriptItemize that the output list of items is one smaller
+ // than it actually is. According to Mozilla bug 366643, if there is
+ // not enough room in the array on pre-SP2 systems, ScriptItemize will
+ // write one past the end of the buffer.
+ //
+ // ScriptItemize is very strange. It will often require a much larger
+ // ITEM buffer internally than it will give us as output. For example,
+ // it will say a 16-item buffer is not big enough, and will write
+ // interesting numbers into all those items. But when we give it a 32
+ // item buffer and it succeeds, it only has one item output.
+ //
+ // It seems to be doing at least two passes, the first where it puts a
+ // lot of intermediate data into our items, and the second where it
+ // collates them.
+ hr = ScriptItemize(m_input, m_inputLength,
+ static_cast<int>(m_runs.size()) - 1, &inputControl,
+ &inputState,
+ &m_runs[0], &numberOfItems);
+ if (SUCCEEDED(hr)) {
+ m_runs.resize(numberOfItems);
+ break;
+ }
+ if (hr != E_OUTOFMEMORY) {
+ // Some kind of unexpected error.
+ m_runs.resize(0);
+ break;
+ }
+ // There was not enough items for it to write into, expand.
+ m_runs.resize(m_runs.size() * 2);
+ }
+}
+
+bool UniscribeHelper::shape(const UChar* input,
+ int itemLength,
+ int numGlyphs,
+ SCRIPT_ITEM& run,
+ Shaping& shaping)
+{
+ HFONT hfont = m_hfont;
+ SCRIPT_CACHE* scriptCache = m_scriptCache;
+ SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties;
+ int ascent = m_ascent;
+ HDC tempDC = 0;
+ HGDIOBJ oldFont = 0;
+ HRESULT hr;
+ bool lastFallbackTried = false;
+ bool result;
+
+ int generatedGlyphs = 0;
+
+ // In case HFONT passed in ctor cannot render this run, we have to scan
+ // other fonts from the beginning of the font list.
+ resetFontIndex();
+
+ // Compute shapes.
+ while (true) {
+ shaping.m_logs.resize(itemLength);
+ shaping.m_glyphs.resize(numGlyphs);
+ shaping.m_visualAttributes.resize(numGlyphs);
+
+#ifdef PURIFY
+ // http://code.google.com/p/chromium/issues/detail?id=5309
+ // Purify isn't able to track the assignments that ScriptShape makes to
+ // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it
+ // writes, will be considered un-initialized data.
+ //
+ // This hack avoid the false-positive UMRs by marking the buffer as
+ // initialized.
+ //
+ // FIXME: A better solution would be to use Purify's API and mark only
+ // the populated range as initialized:
+ //
+ // PurifyMarkAsInitialized(
+ // &shaping.m_glyphs[0],
+ // sizeof(shaping.m_glyphs[0] * generatedGlyphs);
+
+ ZeroMemory(&shaping.m_glyphs[0],
+ sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size());
+#endif
+
+ // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true
+ // here. Is that what we want? It will display control characters.
+ hr = ScriptShape(tempDC, scriptCache, input, itemLength,
+ numGlyphs, &run.a,
+ &shaping.m_glyphs[0], &shaping.m_logs[0],
+ &shaping.m_visualAttributes[0], &generatedGlyphs);
+ if (hr == E_PENDING) {
+ // Allocate the DC.
+ tempDC = GetDC(0);
+ oldFont = SelectObject(tempDC, hfont);
+ continue;
+ } else if (hr == E_OUTOFMEMORY) {
+ numGlyphs *= 2;
+ continue;
+ } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties)))
+ break;
+
+ // The current font can't render this run. clear DC and try
+ // next font.
+ if (tempDC) {
+ SelectObject(tempDC, oldFont);
+ ReleaseDC(0, tempDC);
+ tempDC = 0;
+ }
+
+ if (nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) {
+ // The primary font does not support this run. Try next font.
+ // In case of web page rendering, they come from fonts specified in
+ // CSS stylesheets.
+ continue;
+ } else if (!lastFallbackTried) {
+ lastFallbackTried = true;
+
+ // Generate a last fallback font based on the script of
+ // a character to draw while inheriting size and styles
+ // from the primary font
+ if (!m_logfont.lfFaceName[0])
+ setLogFontAndStyle(m_hfont, &m_logfont, &m_style);
+
+ // TODO(jungshik): generic type should come from webkit for
+ // UniscribeHelperTextRun (a derived class used in webkit).
+ const UChar *family = getFallbackFamily(input, itemLength,
+ FontDescription::StandardFamily, 0, 0);
+ bool fontOk = getDerivedFontData(family, m_style, &m_logfont,
+ &ascent, &hfont, &scriptCache);
+
+ if (!fontOk) {
+ // If this GetDerivedFontData is called from the renderer it
+ // might fail because the sandbox is preventing it from opening
+ // the font files. If we are running in the renderer,
+ // TryToPreloadFont is overridden to ask the browser to preload
+ // the font for us so we can access it.
+ tryToPreloadFont(hfont);
+
+ // Try again.
+ fontOk = getDerivedFontData(family, m_style, &m_logfont,
+ &ascent, &hfont, &scriptCache);
+ ASSERT(fontOk);
+ }
+
+ // TODO(jungshik) : Currently GetDerivedHFont always returns a
+ // a valid HFONT, but in the future, I may change it to return 0.
+ ASSERT(hfont);
+
+ // We don't need a font_properties for the last resort fallback font
+ // because we don't have anything more to try and are forced to
+ // accept empty glyph boxes. If we tried a series of fonts as
+ // 'last-resort fallback', we'd need it, but currently, we don't.
+ continue;
+ } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) {
+ run.a.eScript = SCRIPT_UNDEFINED;
+ continue;
+ } else if (FAILED(hr)) {
+ // Error shaping.
+ generatedGlyphs = 0;
+ result = false;
+ goto cleanup;
+ }
+ }
+
+ // Sets Windows font data for this run to those corresponding to
+ // a font supporting this run. we don't need to store font_properties
+ // because it's not used elsewhere.
+ shaping.m_hfont = hfont;
+ shaping.m_scriptCache = scriptCache;
+
+ // The ascent of a font for this run can be different from
+ // that of the primary font so that we need to keep track of
+ // the difference per run and take that into account when calling
+ // ScriptTextOut in |draw|. Otherwise, different runs rendered by
+ // different fonts would not be aligned vertically.
+ shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0;
+ result = true;
+
+ cleanup:
+ shaping.m_glyphs.resize(generatedGlyphs);
+ shaping.m_visualAttributes.resize(generatedGlyphs);
+ shaping.m_advance.resize(generatedGlyphs);
+ shaping.m_offsets.resize(generatedGlyphs);
+ if (tempDC) {
+ SelectObject(tempDC, oldFont);
+ ReleaseDC(0, tempDC);
+ }
+ // On failure, our logs don't mean anything, so zero those out.
+ if (!result)
+ shaping.m_logs.clear();
+
+ return result;
+}
+
+void UniscribeHelper::fillShapes()
+{
+ m_shapes.resize(m_runs.size());
+ for (size_t i = 0; i < m_runs.size(); i++) {
+ int startItem = m_runs[i].iCharPos;
+ int itemLength = m_inputLength - startItem;
+ if (i < m_runs.size() - 1)
+ itemLength = m_runs[i + 1].iCharPos - startItem;
+
+ int numGlyphs;
+ if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) {
+ // We'll start our buffer sizes with the current stack space
+ // available in our buffers if the current input fits. As long as
+ // it doesn't expand past that we'll save a lot of time mallocing.
+ numGlyphs = UNISCRIBE_HELPER_STACK_CHARS;
+ } else {
+ // When the input doesn't fit, give up with the stack since it will
+ // almost surely not be enough room (unless the input actually
+ // shrinks, which is unlikely) and just start with the length
+ // recommended by the Uniscribe documentation as a "usually fits"
+ // size.
+ numGlyphs = itemLength * 3 / 2 + 16;
+ }
+
+ // Convert a string to a glyph string trying the primary font, fonts in
+ // the fallback list and then script-specific last resort font.
+ Shaping& shaping = m_shapes[i];
+ if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping))
+ continue;
+
+ // Compute placements. Note that offsets is documented incorrectly
+ // and is actually an array.
+
+ // DC that we lazily create if Uniscribe commands us to.
+ // (this does not happen often because scriptCache is already
+ // updated when calling ScriptShape).
+ HDC tempDC = 0;
+ HGDIOBJ oldFont = 0;
+ HRESULT hr;
+ while (true) {
+ shaping.m_prePadding = 0;
+ hr = ScriptPlace(tempDC, shaping.m_scriptCache,
+ &shaping.m_glyphs[0],
+ static_cast<int>(shaping.m_glyphs.size()),
+ &shaping.m_visualAttributes[0], &m_runs[i].a,
+ &shaping.m_advance[0], &shaping.m_offsets[0],
+ &shaping.m_abc);
+ if (hr != E_PENDING)
+ break;
+
+ // Allocate the DC and run the loop again.
+ tempDC = GetDC(0);
+ oldFont = SelectObject(tempDC, shaping.m_hfont);
+ }
+
+ if (FAILED(hr)) {
+ // Some error we don't know how to handle. Nuke all of our data
+ // since we can't deal with partially valid data later.
+ m_runs.clear();
+ m_shapes.clear();
+ m_screenOrder.clear();
+ }
+
+ if (tempDC) {
+ SelectObject(tempDC, oldFont);
+ ReleaseDC(0, tempDC);
+ }
+ }
+
+ adjustSpaceAdvances();
+
+ if (m_letterSpacing != 0 || m_wordSpacing != 0)
+ applySpacing();
+}
+
+void UniscribeHelper::fillScreenOrder()
+{
+ m_screenOrder.resize(m_runs.size());
+
+ // We assume that the input has only one text direction in it.
+ // TODO(brettw) are we sure we want to keep this restriction?
+ if (m_isRtl) {
+ for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
+ m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i;
+ } else {
+ for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++)
+ m_screenOrder[i] = i;
+ }
+}
+
+void UniscribeHelper::adjustSpaceAdvances()
+{
+ if (m_spaceWidth == 0)
+ return;
+
+ int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing;
+
+ // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem.
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ Shaping& shaping = m_shapes[run];
+
+ for (int i = 0; i < shaping.charLength(); i++) {
+ if (!treatAsSpace(m_input[m_runs[run].iCharPos + i]))
+ continue;
+
+ int glyphIndex = shaping.m_logs[i];
+ int currentAdvance = shaping.m_advance[glyphIndex];
+ // Don't give zero-width spaces a width.
+ if (!currentAdvance)
+ continue;
+
+ // currentAdvance does not include additional letter-spacing, but
+ // space_width does. Here we find out how off we are from the
+ // correct width for the space not including letter-spacing, then
+ // just subtract that diff.
+ int diff = currentAdvance - spaceWidthWithoutLetterSpacing;
+ // The shaping can consist of a run of text, so only subtract the
+ // difference in the width of the glyph.
+ shaping.m_advance[glyphIndex] -= diff;
+ shaping.m_abc.abcB -= diff;
+ }
+ }
+}
+
+void UniscribeHelper::applySpacing()
+{
+ for (size_t run = 0; run < m_runs.size(); run++) {
+ Shaping& shaping = m_shapes[run];
+ bool isRtl = m_runs[run].a.fRTL;
+
+ if (m_letterSpacing != 0) {
+ // RTL text gets padded to the left of each character. We increment
+ // the run's advance to make this happen. This will be balanced out
+ // by NOT adding additional advance to the last glyph in the run.
+ if (isRtl)
+ shaping.m_prePadding += m_letterSpacing;
+
+ // Go through all the glyphs in this run and increase the "advance"
+ // to account for letter spacing. We adjust letter spacing only on
+ // cluster boundaries.
+ //
+ // This works for most scripts, but may have problems with some
+ // indic scripts. This behavior is better than Firefox or IE for
+ // Hebrew.
+ for (int i = 0; i < shaping.glyphLength(); i++) {
+ if (shaping.m_visualAttributes[i].fClusterStart) {
+ // Ick, we need to assign the extra space so that the glyph
+ // comes first, then is followed by the space. This is
+ // opposite for RTL.
+ if (isRtl) {
+ if (i != shaping.glyphLength() - 1) {
+ // All but the last character just get the spacing
+ // applied to their advance. The last character
+ // doesn't get anything,
+ shaping.m_advance[i] += m_letterSpacing;
+ shaping.m_abc.abcB += m_letterSpacing;
+ }
+ } else {
+ // LTR case is easier, we just add to the advance.
+ shaping.m_advance[i] += m_letterSpacing;
+ shaping.m_abc.abcB += m_letterSpacing;
+ }
+ }
+ }
+ }
+
+ // Go through all the characters to find whitespace and insert the
+ // extra wordspacing amount for the glyphs they correspond to.
+ if (m_wordSpacing != 0) {
+ for (int i = 0; i < shaping.charLength(); i++) {
+ if (!treatAsSpace(m_input[m_runs[run].iCharPos + i]))
+ continue;
+
+ // The char in question is a word separator...
+ int glyphIndex = shaping.m_logs[i];
+
+ // Spaces will not have a glyph in Uniscribe, it will just add
+ // additional advance to the character to the left of the
+ // space. The space's corresponding glyph will be the character
+ // following it in reading order.
+ if (isRtl) {
+ // In RTL, the glyph to the left of the space is the same
+ // as the first glyph of the following character, so we can
+ // just increment it.
+ shaping.m_advance[glyphIndex] += m_wordSpacing;
+ shaping.m_abc.abcB += m_wordSpacing;
+ } else {
+ // LTR is actually more complex here, we apply it to the
+ // previous character if there is one, otherwise we have to
+ // apply it to the leading space of the run.
+ if (glyphIndex == 0)
+ shaping.m_prePadding += m_wordSpacing;
+ else {
+ shaping.m_advance[glyphIndex - 1] += m_wordSpacing;
+ shaping.m_abc.abcB += m_wordSpacing;
+ }
+ }
+ }
+ } // m_wordSpacing != 0
+
+ // Loop for next run...
+ }
+}
+
+// The advance is the ABC width of the run
+int UniscribeHelper::advanceForItem(int itemIndex) const
+{
+ int accum = 0;
+ const Shaping& shaping = m_shapes[itemIndex];
+
+ if (shaping.m_justify.size() == 0) {
+ // Easy case with no justification, the width is just the ABC width of
+ // the run. (The ABC width is the sum of the advances).
+ return shaping.m_abc.abcA + shaping.m_abc.abcB +
+ shaping.m_abc.abcC + shaping.m_prePadding;
+ }
+
+ // With justification, we use the justified amounts instead. The
+ // justification array contains both the advance and the extra space
+ // added for justification, so is the width we want.
+ int justification = 0;
+ for (size_t i = 0; i < shaping.m_justify.size(); i++)
+ justification += shaping.m_justify[i];
+
+ return shaping.m_prePadding + justification;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.h b/WebCore/platform/graphics/chromium/UniscribeHelper.h
new file mode 100644
index 0000000..d291105
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/UniscribeHelper.h
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// A wrapper around Uniscribe that provides a reasonable API.
+
+#ifndef UniscribeHelper_h
+#define UniscribeHelper_h
+
+#include <windows.h>
+#include <usp10.h>
+#include <map>
+
+#include <unicode/uchar.h>
+#include <wtf/Vector.h>
+
+class UniscribeTest_TooBig_Test; // A gunit test for UniscribeHelper.
+
+namespace WebCore {
+
+#define UNISCRIBE_HELPER_STACK_RUNS 8
+#define UNISCRIBE_HELPER_STACK_CHARS 32
+
+// This object should be safe to create & destroy frequently, as long as the
+// caller preserves the script_cache when possible (this data may be slow to
+// compute).
+//
+// This object is "kind of large" (~1K) because it reserves a lot of space for
+// working with to avoid expensive heap operations. Therefore, not only should
+// you not worry about creating and destroying it, you should try to not keep
+// them around.
+class UniscribeHelper {
+public:
+ // Initializes this Uniscribe run with the text pointed to by |run| with
+ // |length|. The input is NOT null terminated.
+ //
+ // The is_rtl flag should be set if the input script is RTL. It is assumed
+ // that the caller has already divided up the input text (using ICU, for
+ // example) into runs of the same direction of script. This avoids
+ // disagreements between the caller and Uniscribe later (see FillItems).
+ //
+ // A script cache should be provided by the caller that is initialized to
+ // NULL. When the caller is done with the cache (it may be stored between
+ // runs as long as it is used consistently with the same HFONT), it should
+ // call ScriptFreeCache().
+ UniscribeHelper(const UChar* input,
+ int inputLength,
+ bool isRtl,
+ HFONT,
+ SCRIPT_CACHE*,
+ SCRIPT_FONTPROPERTIES*);
+
+ virtual ~UniscribeHelper();
+
+ // Sets Uniscribe's directional override flag. False by default.
+ bool directionalOverride() const
+ {
+ return m_directionalOverride;
+ }
+ void setDirectionalOverride(bool override)
+ {
+ m_directionalOverride = override;
+ }
+
+ // Set's Uniscribe's no-ligate override flag. False by default.
+ bool inhibitLigate() const
+ {
+ return m_inhibitLigate;
+ }
+ void setInhibitLigate(bool inhibit)
+ {
+ m_inhibitLigate = inhibit;
+ }
+
+ // Set letter spacing. We will try to insert this much space between
+ // graphemes (one or more glyphs perceived as a single unit by ordinary
+ // users of a script). Positive values increase letter spacing, negative
+ // values decrease it. 0 by default.
+ int letterSpacing() const
+ {
+ return m_letterSpacing;
+ }
+ void setLetterSpacing(int letterSpacing)
+ {
+ m_letterSpacing = letterSpacing;
+ }
+
+ // Set the width of a standard space character. We use this to normalize
+ // space widths. Windows will make spaces after Hindi characters larger than
+ // other spaces. A space_width of 0 means to use the default space width.
+ //
+ // Must be set before Init() is called.
+ int spaceWidth() const
+ {
+ return m_spaceWidth;
+ }
+ void setSpaceWidth(int spaceWidth)
+ {
+ m_spaceWidth = spaceWidth;
+ }
+
+ // Set word spacing. We will try to insert this much extra space between
+ // each word in the input (beyond whatever whitespace character separates
+ // words). Positive values lead to increased letter spacing, negative values
+ // decrease it. 0 by default.
+ //
+ // Must be set before Init() is called.
+ int wordSpacing() const
+ {
+ return m_wordSpacing;
+ }
+ void setWordSpacing(int wordSpacing)
+ {
+ m_wordSpacing = wordSpacing;
+ }
+
+ void setAscent(int ascent)
+ {
+ m_ascent = ascent;
+ }
+
+ // You must call this after setting any options but before doing any
+ // other calls like asking for widths or drawing.
+ void init()
+ {
+ initWithOptionalLengthProtection(true);
+ }
+
+ // Returns the total width in pixels of the text run.
+ int width() const;
+
+ // Call to justify the text, with the amount of space that should be ADDED
+ // to get the desired width that the column should be justified to.
+ // Normally, spaces are inserted, but for Arabic there will be kashidas
+ // (extra strokes) inserted instead.
+ //
+ // This function MUST be called AFTER Init().
+ void justify(int additionalSpace);
+
+ // Computes the given character offset into a pixel offset of the beginning
+ // of that character.
+ int characterToX(int offset) const;
+
+ // Converts the given pixel X position into a logical character offset into
+ // the run. For positions appearing before the first character, this will
+ // return -1.
+ int xToCharacter(int x) const;
+
+ // Draws the given characters to (x, y) in the given DC. The font will be
+ // handled by this function, but the font color and other attributes should
+ // be pre-set.
+ //
+ // The y position is the upper left corner, NOT the baseline.
+ void draw(HDC, int x, int y, int from, int to);
+
+ // Returns the first glyph assigned to the character at the given offset.
+ // This function is used to retrieve glyph information when Uniscribe is
+ // being used to generate glyphs for non-complex, non-BMP (above U+FFFF)
+ // characters. These characters are not otherwise special and have no
+ // complex shaping rules, so we don't otherwise need Uniscribe, except
+ // Uniscribe is the only way to get glyphs for non-BMP characters.
+ //
+ // Returns 0 if there is no glyph for the given character.
+ WORD firstGlyphForCharacter(int charOffset) const;
+
+protected:
+ // Backend for init. The flag allows the unit test to specify whether we
+ // should fail early for very long strings like normal, or try to pass the
+ // long string to Uniscribe. The latter provides a way to force failure of
+ // shaping.
+ void initWithOptionalLengthProtection(bool lengthProtection);
+
+ // Tries to preload the font when the it is not accessible.
+ // This is the default implementation and it does not do anything.
+ virtual void tryToPreloadFont(HFONT) {}
+
+private:
+ friend class UniscribeTest_TooBig_Test;
+
+ // An array corresponding to each item in runs_ containing information
+ // on each of the glyphs that were generated. Like runs_, this is in
+ // reading order. However, for rtl text, the characters within each
+ // item will be reversed.
+ struct Shaping {
+ Shaping()
+ : m_prePadding(0)
+ , m_hfont(NULL)
+ , m_scriptCache(NULL)
+ , m_ascentOffset(0) {
+ m_abc.abcA = 0;
+ m_abc.abcB = 0;
+ m_abc.abcC = 0;
+ }
+
+ // Returns the number of glyphs (which will be drawn to the screen)
+ // in this run.
+ int glyphLength() const
+ {
+ return static_cast<int>(m_glyphs.size());
+ }
+
+ // Returns the number of characters (that we started with) in this run.
+ int charLength() const
+ {
+ return static_cast<int>(m_logs.size());
+ }
+
+ // Returns the advance array that should be used when measuring glyphs.
+ // The returned pointer will indicate an array with glyph_length()
+ // elements and the advance that should be used for each one. This is
+ // either the real advance, or the justified advances if there is one,
+ // and is the array we want to use for measurement.
+ const int* effectiveAdvances() const
+ {
+ if (m_advance.size() == 0)
+ return 0;
+ if (m_justify.size() == 0)
+ return &m_advance[0];
+ return &m_justify[0];
+ }
+
+ // This is the advance amount of space that we have added to the
+ // beginning of the run. It is like the ABC's |A| advance but one that
+ // we create and must handle internally whenever computing with pixel
+ // offsets.
+ int m_prePadding;
+
+ // Glyph indices in the font used to display this item. These indices
+ // are in screen order.
+ Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_glyphs;
+
+ // For each input character, this tells us the first glyph index it
+ // generated. This is the only array with size of the input chars.
+ //
+ // All offsets are from the beginning of this run. Multiple characters
+ // can generate one glyph, in which case there will be adjacent
+ // duplicates in this list. One character can also generate multiple
+ // glyphs, in which case there will be skipped indices in this list.
+ Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_logs;
+
+ // Flags and such for each glyph.
+ Vector<SCRIPT_VISATTR, UNISCRIBE_HELPER_STACK_CHARS> m_visualAttributes;
+
+ // Horizontal advances for each glyph listed above, this is basically
+ // how wide each glyph is.
+ Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_advance;
+
+ // This contains glyph offsets, from the nominal position of a glyph.
+ // It is used to adjust the positions of multiple combining characters
+ // around/above/below base characters in a context-sensitive manner so
+ // that they don't bump against each other and the base character.
+ Vector<GOFFSET, UNISCRIBE_HELPER_STACK_CHARS> m_offsets;
+
+ // Filled by a call to Justify, this is empty for nonjustified text.
+ // If nonempty, this contains the array of justify characters for each
+ // character as returned by ScriptJustify.
+ //
+ // This is the same as the advance array, but with extra space added
+ // for some characters. The difference between a glyph's |justify|
+ // width and it's |advance| width is the extra space added.
+ Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_justify;
+
+ // Sizing information for this run. This treats the entire run as a
+ // character with a preceeding advance, width, and ending advance. The
+ // B width is the sum of the |advance| array, and the A and C widths
+ // are any extra spacing applied to each end.
+ //
+ // It is unclear from the documentation what this actually means. From
+ // experimentation, it seems that the sum of the character advances is
+ // always the sum of the ABC values, and I'm not sure what you're
+ // supposed to do with the ABC values.
+ ABC m_abc;
+
+ // Pointers to windows font data used to render this run.
+ HFONT m_hfont;
+ SCRIPT_CACHE* m_scriptCache;
+
+ // Ascent offset between the ascent of the primary font
+ // and that of the fallback font. The offset needs to be applied,
+ // when drawing a string, to align multiple runs rendered with
+ // different fonts.
+ int m_ascentOffset;
+ };
+
+ // Computes the runs_ array from the text run.
+ void fillRuns();
+
+ // Computes the shapes_ array given an runs_ array already filled in.
+ void fillShapes();
+
+ // Fills in the screen_order_ array (see below).
+ void fillScreenOrder();
+
+ // Called to update the glyph positions based on the current spacing
+ // options that are set.
+ void applySpacing();
+
+ // Normalizes all advances for spaces to the same width. This keeps windows
+ // from making spaces after Hindi characters larger, which is then
+ // inconsistent with our meaure of the width since WebKit doesn't include
+ // spaces in text-runs sent to uniscribe unless white-space:pre.
+ void adjustSpaceAdvances();
+
+ // Returns the total width of a single item.
+ int advanceForItem(int) const;
+
+ // Shapes a run (pointed to by |input|) using |hfont| first.
+ // Tries a series of fonts specified retrieved with NextWinFontData
+ // and finally a font covering characters in |*input|. A string pointed
+ // by |input| comes from ScriptItemize and is supposed to contain
+ // characters belonging to a single script aside from characters common to
+ // all scripts (e.g. space).
+ bool shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, Shaping&);
+
+ // Gets Windows font data for the next best font to try in the list
+ // of fonts. When there's no more font available, returns false
+ // without touching any of out params. Need to call ResetFontIndex
+ // to start scanning of the font list from the beginning.
+ virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent)
+ {
+ return false;
+ }
+
+ // Resets the font index to the first in the list of fonts to try after the
+ // primaryFont turns out not to work. With fontIndex reset,
+ // NextWinFontData scans fallback fonts from the beginning.
+ virtual void resetFontIndex() {}
+
+ // The input data for this run of Uniscribe. See the constructor.
+ const UChar* m_input;
+ const int m_inputLength;
+ const bool m_isRtl;
+
+ // Windows font data for the primary font. In a sense, m_logfont and m_style
+ // are redundant because m_hfont contains all the information. However,
+ // invoking GetObject, everytime we need the height and the style, is rather
+ // expensive so that we cache them. Would it be better to add getter and
+ // (virtual) setter for the height and the style of the primary font,
+ // instead of m_logfont? Then, a derived class ctor can set m_ascent,
+ // m_height and m_style if they're known. Getters for them would have to
+ // 'infer' their values from m_hfont ONLY when they're not set.
+ HFONT m_hfont;
+ SCRIPT_CACHE* m_scriptCache;
+ SCRIPT_FONTPROPERTIES* m_fontProperties;
+ int m_ascent;
+ LOGFONT m_logfont;
+ int m_style;
+
+ // Options, see the getters/setters above.
+ bool m_directionalOverride;
+ bool m_inhibitLigate;
+ int m_letterSpacing;
+ int m_spaceWidth;
+ int m_wordSpacing;
+
+ // Uniscribe breaks the text into Runs. These are one length of text that is
+ // in one script and one direction. This array is in reading order.
+ Vector<SCRIPT_ITEM, UNISCRIBE_HELPER_STACK_RUNS> m_runs;
+
+ Vector<Shaping, UNISCRIBE_HELPER_STACK_RUNS> m_shapes;
+
+ // This is a mapping between reading order and screen order for the items.
+ // Uniscribe's items array are in reading order. For right-to-left text,
+ // or mixed (although WebKit's |TextRun| should really be only one
+ // direction), this makes it very difficult to compute character offsets
+ // and positions. This list is in screen order from left to right, and
+ // gives the index into the |m_runs| and |m_shapes| arrays of each
+ // subsequent item.
+ Vector<int, UNISCRIBE_HELPER_STACK_RUNS> m_screenOrder;
+};
+
+} // namespace WebCore
+
+#endif // UniscribeHelper_h
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp
new file mode 100644
index 0000000..f801c13
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "UniscribeHelperTextRun.h"
+
+#include "ChromiumBridge.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run,
+ const Font& font)
+ : UniscribeHelper(run.characters(), run.length(), run.rtl(),
+ font.primaryFont()->platformData().hfont(),
+ font.primaryFont()->platformData().scriptCache(),
+ font.primaryFont()->platformData().scriptFontProperties())
+ , m_font(&font)
+ , m_fontIndex(0)
+{
+ setDirectionalOverride(run.directionalOverride());
+ setLetterSpacing(font.letterSpacing());
+ setSpaceWidth(font.spaceWidth());
+ setWordSpacing(font.wordSpacing());
+ setAscent(font.primaryFont()->ascent());
+
+ init();
+
+ // Padding is the amount to add to make justification happen. This
+ // should be done after Init() so all the runs are already measured.
+ if (run.padding() > 0)
+ justify(run.padding());
+}
+
+UniscribeHelperTextRun::UniscribeHelperTextRun(
+ const wchar_t* input,
+ int inputLength,
+ bool isRtl,
+ HFONT hfont,
+ SCRIPT_CACHE* scriptCache,
+ SCRIPT_FONTPROPERTIES* fontProperties)
+ : UniscribeHelper(input, inputLength, isRtl, hfont,
+ scriptCache, fontProperties)
+ , m_font(0)
+ , m_fontIndex(-1)
+{
+}
+
+void UniscribeHelperTextRun::tryToPreloadFont(HFONT font)
+{
+ // Ask the browser to get the font metrics for this font.
+ // That will preload the font and it should now be accessible
+ // from the renderer.
+ ChromiumBridge::ensureFontLoaded(font);
+}
+
+bool UniscribeHelperTextRun::nextWinFontData(
+ HFONT* hfont,
+ SCRIPT_CACHE** scriptCache,
+ SCRIPT_FONTPROPERTIES** fontProperties,
+ int* ascent)
+{
+ // This check is necessary because NextWinFontData can be called again
+ // after we already ran out of fonts. fontDataAt behaves in a strange
+ // manner when the difference between param passed and # of fonts stored in
+ // WebKit::Font is larger than one. We can avoid this check by setting
+ // font_index_ to # of elements in hfonts_ when we run out of font. In that
+ // case, we'd have to go through a couple of more checks before returning
+ // false.
+ if (m_fontIndex == -1 || !m_font)
+ return false;
+
+ // If the font data for a fallback font requested is not yet retrieved, add
+ // them to our vectors. Note that '>' rather than '>=' is used to test that
+ // condition. primaryFont is not stored in hfonts_, and friends so that
+ // indices for fontDataAt and our vectors for font data are 1 off from each
+ // other. That is, when fully populated, hfonts_ and friends have one font
+ // fewer than what's contained in font_.
+ if (static_cast<size_t>(++m_fontIndex) > m_hfonts.size()) {
+ const FontData *fontData = m_font->fontDataAt(m_fontIndex);
+ if (!fontData) {
+ // Ran out of fonts.
+ m_fontIndex = -1;
+ return false;
+ }
+
+ // FIXME: this won't work for SegmentedFontData
+ // http://crbug.com/6425
+ const SimpleFontData* simpleFontData =
+ fontData->fontDataForCharacter(' ');
+
+ m_hfonts.append(simpleFontData->platformData().hfont());
+ m_scriptCaches.append(simpleFontData->platformData().scriptCache());
+ m_fontProperties.append(simpleFontData->platformData().scriptFontProperties());
+ m_ascents.append(simpleFontData->ascent());
+ }
+
+ *hfont = m_hfonts[m_fontIndex - 1];
+ *scriptCache = m_scriptCaches[m_fontIndex - 1];
+ *fontProperties = m_fontProperties[m_fontIndex - 1];
+ *ascent = m_ascents[m_fontIndex - 1];
+ return true;
+}
+
+void UniscribeHelperTextRun::resetFontIndex()
+{
+ m_fontIndex = 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h
new file mode 100644
index 0000000..b5c54a0
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2006, 2007, 2008, 2009, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UniscribeHelperTextRun_h
+#define UniscribeHelperTextRun_h
+
+#include "UniscribeHelper.h"
+
+namespace WebCore {
+
+class Font;
+class TextRun;
+
+// Wrapper around the Uniscribe helper that automatically sets it up with the
+// WebKit types we supply.
+class UniscribeHelperTextRun : public UniscribeHelper {
+public:
+ // Regular constructor used for WebCore text run processing.
+ UniscribeHelperTextRun(const TextRun&, const Font&);
+
+ // Constructor with the same interface as the gfx::UniscribeState. Using
+ // this constructor will not give you font fallback, but it will provide
+ // the ability to load fonts that may not be in the OS cache
+ // ("TryToPreloadFont") if the caller does not have a TextRun/Font.
+ UniscribeHelperTextRun(const wchar_t* input,
+ int inputLength,
+ bool isRtl,
+ HFONT hfont,
+ SCRIPT_CACHE*,
+ SCRIPT_FONTPROPERTIES*);
+
+protected:
+ virtual void tryToPreloadFont(HFONT);
+
+private:
+ // This function retrieves the Windows font data (HFONT, etc) for the next
+ // WebKit font in the list. If the font data corresponding to font_index_
+ // has been obtained before, returns the values stored in our internal
+ // vectors (hfonts_, etc). Otherwise, it gets next SimpleFontData from
+ // WebKit and adds them to in hfonts_ and friends so that font data can be
+ // returned quickly next time they're requested.
+ virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent);
+ virtual void resetFontIndex();
+
+ // Reference to WebKit::Font that contains all the information about fonts
+ // we can use to render this input run of text. It is used in
+ // NextWinFontData to retrieve Windows font data for a series of
+ // non-primary fonts.
+ //
+ // This pointer can be NULL for no font fallback handling.
+ const Font* m_font;
+
+ // It's rare that many fonts are listed in stylesheets.
+ // Four would be large enough in most cases.
+ const static size_t kNumberOfFonts = 4;
+
+ // These vectors are used to store Windows font data for non-primary fonts.
+ Vector<HFONT, kNumberOfFonts> m_hfonts;
+ Vector<SCRIPT_CACHE*, kNumberOfFonts> m_scriptCaches;
+ Vector<SCRIPT_FONTPROPERTIES*, kNumberOfFonts> m_fontProperties;
+ Vector<int, kNumberOfFonts> m_ascents;
+
+ // Index of the fallback font we're currently using for NextWinFontData.
+ int m_fontIndex;
+};
+
+} // namespace WebCore
+
+#endif // UniscribeHelperTextRun_h
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
index 1ca3e95..d076cb6 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
@@ -63,6 +63,7 @@ void SimpleFontData::platformInit()
void SimpleFontData::platformDestroy()
{
delete m_smallCapsFontData;
+ m_smallCapsFontData = 0;
if (isCustomFont())
return;
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
index 8621865..db8dd3b 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
@@ -80,6 +80,7 @@ void SimpleFontData::platformDestroy()
}
delete m_smallCapsFontData;
+ m_smallCapsFontData = 0;
}
SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
@@ -97,25 +98,27 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con
{
bool result = true;
- PangoCoverage* requested = pango_coverage_from_bytes((guchar*)characters, length);
- PangoCoverage* available = pango_font_get_coverage(m_font.m_font, pango_language_get_default());
- pango_coverage_max(requested, available);
+ PangoCoverage* coverage = pango_font_get_coverage(m_font.m_font, pango_language_get_default());
for (int i = 0; i < length; i++) {
- if (PANGO_COVERAGE_NONE == pango_coverage_get(requested, i)) {
+ if (PANGO_COVERAGE_NONE == pango_coverage_get(coverage, characters[i])) {
result = false;
break;
}
}
- pango_coverage_unref(requested);
- pango_coverage_unref(available);
+ pango_coverage_unref(coverage);
return result;
}
void SimpleFontData::determinePitch()
{
+ if (isCustomFont()) {
+ m_treatAsFixedPitch = false;
+ return;
+ }
+
m_treatAsFixedPitch = m_font.isFixedPitch();
}
diff --git a/WebCore/platform/graphics/mac/ColorMac.h b/WebCore/platform/graphics/mac/ColorMac.h
index 3be9094..830e9d9 100644
--- a/WebCore/platform/graphics/mac/ColorMac.h
+++ b/WebCore/platform/graphics/mac/ColorMac.h
@@ -39,6 +39,7 @@ class NSColor;
namespace WebCore {
+ // These functions assume NSColors are in DeviceRGB colorspace
Color colorFromNSColor(NSColor *);
NSColor* nsColor(const Color&);
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm
index 96fdc39..9b0f770 100644
--- a/WebCore/platform/graphics/mac/ColorMac.mm
+++ b/WebCore/platform/graphics/mac/ColorMac.mm
@@ -28,6 +28,7 @@
#import "ColorMac.h"
#import <wtf/Assertions.h>
+#import <wtf/StdLibExtras.h>
#import <wtf/RetainPtr.h>
@interface WebCoreControlTintObserver : NSObject
@@ -59,37 +60,30 @@ NSColor* nsColor(const Color& color)
switch (c) {
case 0: {
// Need this to avoid returning nil because cachedRGBAValues will default to 0.
- static RetainPtr<NSColor> clearColor = [NSColor clearColor];
+ 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: {
- static RetainPtr<NSColor> blackColor = [NSColor blackColor];
+ 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: {
- static RetainPtr<NSColor> whiteColor = [NSColor whiteColor];
+ 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[cacheSize];
+ static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize];
for (int i = 0; i != cacheSize; ++i)
if (cachedRGBAValues[i] == c)
return cachedColors[i].get();
-#ifdef COLORMATCH_EVERYTHING
- NSColor* result = [NSColor colorWithCalibratedRed:color.red() / 255.0f
- green:color.green() / 255.0f
- blue:color.blue() / 255.0f
- alpha:color.alpha() /255.0f];
-#else
NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f
green:color.green() / 255.0f
blue:color.blue() / 255.0f
alpha:color.alpha() /255.0f];
-#endif
static int cursor;
cachedRGBAValues[cursor] = c;
@@ -158,12 +152,8 @@ void setUsesTestModeFocusRingColor(bool newValue)
+ (void)controlTintDidChange
{
-#ifdef COLORMATCH_EVERYTHING
-#error Not yet implemented.
-#else
NSColor* color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
WebCore::systemFocusRingColor = WebCore::makeRGBAFromNSColor(color);
-#endif
}
@end
diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/CoreTextController.cpp
index 171a7ec..49e83c4 100644
--- a/WebCore/platform/graphics/mac/CoreTextController.cpp
+++ b/WebCore/platform/graphics/mac/CoreTextController.cpp
@@ -369,9 +369,9 @@ void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsig
static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
static const void* ltrOptionValues[] = { kCFBooleanFalse };
static const void* rtlOptionValues[] = { kCFBooleanTrue };
- static RetainPtr<CFDictionaryRef> ltrTypesetterOptions(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
- static RetainPtr<CFDictionaryRef> rtlTypesetterOptions(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
- typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions.get() : rtlTypesetterOptions.get()));
+ static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
} else
typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get()));
diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm
index e7cda66..26d84cc 100644
--- a/WebCore/platform/graphics/mac/FontCacheMac.mm
+++ b/WebCore/platform/graphics/mac/FontCacheMac.mm
@@ -35,6 +35,7 @@
#import "FontPlatformData.h"
#import "WebCoreSystemInterface.h"
#import "WebFontCache.h"
+#include <wtf/StdLibExtras.h>
#ifdef BUILDING_ON_TIGER
typedef int NSInteger;
@@ -44,7 +45,7 @@ namespace WebCore {
static void fontCacheATSNotificationCallback(ATSFontNotificationInfoRef, void*)
{
- FontCache::invalidate();
+ fontCache()->invalidate();
}
void FontCache::platformInit()
@@ -139,10 +140,10 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
const FontFamily* currFamily = &font.fontDescription().family();
while (currFamily && !platformData) {
if (currFamily->family().length()) {
- static String matchWords[3] = { String("Arabic"), String("Pashto"), String("Urdu") };
- static AtomicString geezaStr("Geeza Pro");
+ static String* matchWords[3] = { new String("Arabic"), new String("Pashto"), new String("Urdu") };
+ DEFINE_STATIC_LOCAL(AtomicString, geezaStr, ("Geeza Pro"));
for (int j = 0; j < 3 && !platformData; ++j)
- if (currFamily->family().contains(matchWords[j], false))
+ if (currFamily->family().contains(*matchWords[j], false))
platformData = getCachedFontPlatformData(font.fontDescription(), geezaStr);
}
currFamily = currFamily->next();
@@ -153,8 +154,8 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
{
- static AtomicString timesStr("Times");
- static AtomicString lucidaGrandeStr("Lucida Grande");
+ DEFINE_STATIC_LOCAL(AtomicString, timesStr, ("Times"));
+ DEFINE_STATIC_LOCAL(AtomicString, lucidaGrandeStr, ("Lucida Grande"));
// 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.
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
index 1fb144c..9aa4997 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
@@ -68,7 +68,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
CGFontRef cgFontRef = CGFontCreateWithPlatformFont(&fontRef);
#ifndef BUILDING_ON_TIGER
// Workaround for <rdar://problem/5675504>.
- if (!CGFontGetNumberOfGlyphs(cgFontRef)) {
+ if (cgFontRef && !CGFontGetNumberOfGlyphs(cgFontRef)) {
CFRelease(cgFontRef);
cgFontRef = 0;
}
diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm
index 9a45c5a..52493e7 100644
--- a/WebCore/platform/graphics/mac/FontMacATSUI.mm
+++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm
@@ -154,8 +154,7 @@ static void initializeATSUStyle(const SimpleFontData* fontData)
fontData->m_ATSUStyleInitialized = true;
}
-static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector iCurrentOperation, ATSULineRef iLineRef, URefCon iRefCon,
- void *iOperationCallbackParameterPtr, ATSULayoutOperationCallbackStatus *oCallbackStatus)
+static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef iLineRef, URefCon iRefCon, void*, ATSULayoutOperationCallbackStatus* oCallbackStatus)
{
ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon);
OSStatus status;
@@ -592,7 +591,7 @@ float Font::floatWidthForComplexText(const TextRun& run) const
MIN(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x));
}
-int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool /*includePartialGlyphs*/) const
{
OwnArrayPtr<UChar> charactersWithOverride;
TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride);
diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
index 15e573d..7cd9ab6 100644
--- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
+++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
@@ -34,7 +34,7 @@ FontPlatformData::FontPlatformData(NSFont *f, bool b , bool o)
CFRetain(f);
m_size = f ? [f pointSize] : 0.0f;
#ifndef BUILDING_ON_TIGER
- m_cgFont = CTFontCopyGraphicsFont(toCTFontRef(f), 0);
+ m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(f), 0));
m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(f), 0);
#else
m_cgFont = wkGetCGFontFromNSFont(f);
@@ -86,7 +86,7 @@ void FontPlatformData::setFont(NSFont *font)
m_font = font;
m_size = font ? [font pointSize] : 0.0f;
#ifndef BUILDING_ON_TIGER
- m_cgFont = CTFontCopyGraphicsFont(toCTFontRef(font), 0);
+ m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(font), 0));
m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(font), 0);
#else
m_cgFont = wkGetCGFontFromNSFont(font);
diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
index 3f9176c..ae829e2 100644
--- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm
+++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -27,6 +27,7 @@
#import "GraphicsContext.h"
#import "../cg/GraphicsContextPlatformPrivateCG.h"
+#import <wtf/StdLibExtras.h>
#import "WebCoreSystemInterface.h"
@@ -80,53 +81,42 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op)
[pool drain];
}
#endif
-
+
+static NSColor* createPatternColor(NSString* name, NSColor* defaultColor, bool& usingDot)
+{
+ NSImage *image = [NSImage imageNamed:name];
+ ASSERT(image); // if image is not available, we want to know
+ NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil);
+ if (color)
+ usingDot = true;
+ else
+ color = defaultColor;
+ return color;
+}
+
void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar)
{
if (paintingDisabled())
return;
- // Constants for spelling pattern color
- static RetainPtr<NSColor> spellingPatternColor = nil;
- static bool usingDotForSpelling = false;
-
- // Constants for grammar pattern color
- static RetainPtr<NSColor> grammarPatternColor = nil;
- static bool usingDotForGrammar = false;
-
// These are the same for misspelling or bad grammar
int patternHeight = cMisspellingLineThickness;
int patternWidth = cMisspellingLinePatternWidth;
- // Initialize pattern color if needed
- if (!grammar && !spellingPatternColor) {
- NSImage *image = [NSImage imageNamed:@"SpellingDot"];
- ASSERT(image); // if image is not available, we want to know
- NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil);
- if (color)
- usingDotForSpelling = true;
- else
- color = [NSColor redColor];
- spellingPatternColor = color;
- }
-
- if (grammar && !grammarPatternColor) {
- NSImage *image = [NSImage imageNamed:@"GrammarDot"];
- ASSERT(image); // if image is not available, we want to know
- NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil);
- if (color)
- usingDotForGrammar = true;
- else
- color = [NSColor greenColor];
- grammarPatternColor = color;
- }
-
bool usingDot;
NSColor *patternColor;
if (grammar) {
+ // Constants for grammar pattern color
+ static bool usingDotForGrammar = false;
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar)));
+
usingDot = usingDotForGrammar;
patternColor = grammarPatternColor.get();
} else {
+ // Constants for spelling pattern color
+ static bool usingDotForSpelling = false;
+ DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling)));
+
usingDot = usingDotForSpelling;
patternColor = spellingPatternColor.get();
}
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index 0ec56d6..a33c8d2 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -29,14 +29,19 @@
#import "MediaPlayerPrivateQTKit.h"
+#ifdef BUILDING_ON_TIGER
+#import "AutodrainedPool.h"
+#endif
+
#import "BlockExceptions.h"
+#import "FrameView.h"
#import "GraphicsContext.h"
#import "KURL.h"
-#import "FrameView.h"
#import "SoftLinking.h"
#import "WebCoreSystemInterface.h"
#import <QTKit/QTKit.h>
#import <objc/objc-runtime.h>
+#import <wtf/UnusedParam.h>
#if DRAW_FRAME_RATE
#import "Font.h"
@@ -239,7 +244,7 @@ void MediaPlayerPrivate::createQTMovie(const String& url)
object:m_qtMovie.get()];
}
-static void mainThreadSetNeedsDisplay(id self, SEL _cmd)
+static void mainThreadSetNeedsDisplay(id self, SEL)
{
id movieView = [self superview];
ASSERT(!movieView || [movieView isKindOfClass:[QTMovieView class]]);
@@ -772,6 +777,10 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
context->scale(FloatSize(1.0f, -1.0f));
context->setImageInterpolationQuality(InterpolationLow);
IntRect paintRect(IntPoint(0, 0), IntSize(r.width(), r.height()));
+
+#ifdef BUILDING_ON_TIGER
+ AutodrainedPool pool;
+#endif
NSGraphicsContext* newContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context->platformContext() flipped:NO];
// draw the current video frame
@@ -969,48 +978,54 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
m_callback->repaint();
}
-- (void)loadStateChanged:(NSNotification *)notification
+- (void)loadStateChanged:(NSNotification *)unusedNotification
{
+ UNUSED_PARAM(unusedNotification);
if (m_delayCallbacks)
[self performSelector:_cmd withObject:nil afterDelay:0];
else
m_callback->loadStateChanged();
}
-- (void)rateChanged:(NSNotification *)notification
+- (void)rateChanged:(NSNotification *)unusedNotification
{
+ UNUSED_PARAM(unusedNotification);
if (m_delayCallbacks)
[self performSelector:_cmd withObject:nil afterDelay:0];
else
m_callback->rateChanged();
}
-- (void)sizeChanged:(NSNotification *)notification
+- (void)sizeChanged:(NSNotification *)unusedNotification
{
+ UNUSED_PARAM(unusedNotification);
if (m_delayCallbacks)
[self performSelector:_cmd withObject:nil afterDelay:0];
else
m_callback->sizeChanged();
}
-- (void)timeChanged:(NSNotification *)notification
+- (void)timeChanged:(NSNotification *)unusedNotification
{
+ UNUSED_PARAM(unusedNotification);
if (m_delayCallbacks)
[self performSelector:_cmd withObject:nil afterDelay:0];
else
m_callback->timeChanged();
}
-- (void)didEnd:(NSNotification *)notification
+- (void)didEnd:(NSNotification *)unusedNotification
{
+ UNUSED_PARAM(unusedNotification);
if (m_delayCallbacks)
[self performSelector:_cmd withObject:nil afterDelay:0];
else
m_callback->didEnd();
}
-- (void)newImageAvailable:(NSNotification *)notification
+- (void)newImageAvailable:(NSNotification *)unusedNotification
{
+ UNUSED_PARAM(unusedNotification);
[self repaint];
}
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index 4ee5933..30dbf97 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -42,6 +42,7 @@
#import <float.h>
#import <unicode/uchar.h>
#import <wtf/Assertions.h>
+#import <wtf/StdLibExtras.h>
#import <wtf/RetainPtr.h>
@interface NSFont (WebAppKitSecretAPI)
@@ -54,7 +55,7 @@ const float smallCapsFontSizeMultiplier = 0.7f;
const float contextDPI = 72.0f;
static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (contextDPI / (contextDPI * unitsPerEm)); }
-bool initFontData(SimpleFontData* fontData)
+static bool initFontData(SimpleFontData* fontData)
{
if (!fontData->m_font.cgFont())
return false;
@@ -92,9 +93,7 @@ bool initFontData(SimpleFontData* fontData)
static NSString *webFallbackFontFamily(void)
{
- static RetainPtr<NSString> webFallbackFontFamily = nil;
- if (!webFallbackFontFamily)
- webFallbackFontFamily = [[NSFont systemFontOfSize:16.0f] familyName];
+ DEFINE_STATIC_LOCAL(RetainPtr<NSString>, webFallbackFontFamily, ([[NSFont systemFontOfSize:16.0f] familyName]));
return webFallbackFontFamily.get();
}
@@ -315,7 +314,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes
smallCapsFont.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(smallCapsFontTraits & NSBoldFontMask);
smallCapsFont.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(smallCapsFontTraits & NSItalicFontMask);
- m_smallCapsFontData = FontCache::getCachedFontData(&smallCapsFont);
+ m_smallCapsFontData = fontCache()->getCachedFontData(&smallCapsFont);
}
END_BLOCK_OBJC_EXCEPTIONS;
}
@@ -325,7 +324,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes
bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
{
- NSString *string = [[NSString alloc] initWithCharactersNoCopy:(UniChar*)characters length:length freeWhenDone:NO];
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO];
NSCharacterSet *set = [[m_font.font() coveredCharacterSet] invertedSet];
bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound;
[string release];
diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp
index be31d96..114f073 100644
--- a/WebCore/platform/graphics/qt/FontCacheQt.cpp
+++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -21,18 +22,31 @@
*/
#include "config.h"
#include "FontCache.h"
+
#include "FontDescription.h"
+#include "FontPlatformData.h"
#include "Font.h"
+#include <wtf/StdLibExtras.h>
namespace WebCore {
+FontCache* fontCache()
+{
+ DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ());
+ return &globalFontCache;
+}
+
+FontCache::FontCache()
+{
+}
+
void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
{
}
-FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName)
+FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName)
{
- return 0;
+ return new FontPlatformData(description);
}
SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*)
@@ -45,6 +59,10 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&)
return 0;
}
+void FontCache::releaseFontData(const WebCore::SimpleFontData*)
+{
+}
+
void FontCache::addClient(FontSelector*)
{
}
diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp
index 8fc3ea0..a19464e 100644
--- a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp
@@ -25,19 +25,25 @@
#include "FontPlatformData.h"
#include "SharedBuffer.h"
#include <QFontDatabase>
+#include <QStringList>
namespace WebCore {
FontCustomPlatformData::~FontCustomPlatformData()
{
- QFontDatabase::removeApplicationFont(handle);
+ QFontDatabase::removeApplicationFont(m_handle);
}
FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
{
- FontPlatformData result;
- result.handle = handle;
- return result;
+ QFont font;
+ font.setFamily(QFontDatabase::applicationFontFamilies(m_handle)[0]);
+ font.setPixelSize(size);
+ if (bold)
+ font.setWeight(QFont::Bold);
+ font.setItalic(italic);
+
+ return FontPlatformData(font, bold);
}
FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
@@ -47,8 +53,11 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
int id = QFontDatabase::addApplicationFontFromData(QByteArray(buffer->data(), buffer->size()));
if (id == -1)
return 0;
+
+ Q_ASSERT(QFontDatabase::applicationFontFamilies(id).size() > 0);
+
FontCustomPlatformData *data = new FontCustomPlatformData;
- data->handle = id;
+ data->m_handle = id;
return data;
}
diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/WebCore/platform/graphics/qt/FontCustomPlatformData.h
index da5159d..4305b87 100644
--- a/WebCore/platform/graphics/qt/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.h
@@ -33,7 +33,8 @@ class FontPlatformData;
struct FontCustomPlatformData : Noncopyable {
~FontCustomPlatformData();
- int handle; // for use with QFontDatabase::addApplicationFont/removeApplicationFont
+ // for use with QFontDatabase::addApplicationFont/removeApplicationFont
+ int m_handle;
FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
};
diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp
new file mode 100644
index 0000000..22ae205
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ 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.
+
+ Replacement of the stock FontFallbackList as Qt is going to find us a
+ replacement font, will do caching and the other stuff we implement in
+ WebKit.
+*/
+
+#include "config.h"
+#include "FontFallbackList.h"
+
+#include "Font.h"
+#include "SegmentedFontData.h"
+
+#include <QDebug>
+
+namespace WebCore {
+
+FontFallbackList::FontFallbackList()
+ : 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_familyIndex = 0;
+ m_pitch = UnknownPitch;
+ m_loadingCustomFonts = false;
+ m_fontSelector = fontSelector;
+ m_generation = 0;
+}
+
+void FontFallbackList::releaseFontData()
+{
+}
+
+void FontFallbackList::determinePitch(const WebCore::Font* font) const
+{
+ const FontData* fontData = primaryFont(font);
+ if (!fontData->isSegmented())
+ m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch();
+ else {
+ const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
+ unsigned numRanges = segmentedFontData->numRanges();
+ if (numRanges == 1)
+ m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch();
+ else
+ m_pitch = VariablePitch;
+ }
+}
+
+const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigned index) const
+{
+ if (index != 0)
+ return 0;
+
+ // Use the FontSelector to get a WebCore font and then fallback to Qt
+ const FontDescription& description = _font->fontDescription();
+ const FontFamily* family = &description.family();
+ while (family) {
+ if (m_fontSelector) {
+ FontData* data = m_fontSelector->getFontData(description, family->family());
+ if (data) {
+ if (data->isLoading())
+ m_loadingCustomFonts = true;
+ return data;
+ }
+ }
+ family = family->next();
+ }
+
+ return new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing());
+}
+
+const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const
+{
+ return primaryFont(font);
+}
+
+void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData& platformData)
+{
+ m_familyIndex = cAllFamiliesScanned;
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h
index e4363be..5e97678 100644
--- a/WebCore/platform/graphics/qt/FontPlatformData.h
+++ b/WebCore/platform/graphics/qt/FontPlatformData.h
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -22,14 +23,29 @@
#ifndef FontPlatformData_h
#define FontPlatformData_h
+#include "FontDescription.h"
+
+#include <QFont>
+
namespace WebCore {
class FontPlatformData
{
public:
- // this is only used for custom loaded fonts and represents the id handle passed to
- // QFontDatabase::addApplicationFont/removeApplicationFont
- int handle;
+#if ENABLE(SVG_FONTS)
+ FontPlatformData(float size, bool bold, bool oblique);
+#endif
+ FontPlatformData();
+ FontPlatformData(const FontDescription&, int wordSpacing = 0, int letterSpacing = 0);
+ FontPlatformData(const QFont&, bool bold);
+
+ QFont font() const { return m_font; }
+ float size() const { return m_size; }
+
+ float m_size;
+ bool m_bold;
+ bool m_oblique;
+ QFont m_font;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
new file mode 100644
index 0000000..ea51fe8
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ 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"
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(const FontDescription& description, int wordSpacing, int letterSpacing)
+ : m_size(0.0f)
+ , m_bold(false)
+ , m_oblique(false)
+{
+ QString familyName;
+ const FontFamily* family = &description.family();
+ while (family) {
+ familyName += family->family();
+ family = family->next();
+ if (family)
+ familyName += QLatin1Char(',');
+ }
+
+ 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);
+
+ bool smallCaps = description.smallCaps();
+ m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase);
+ m_font.setWordSpacing(wordSpacing);
+ m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing);
+ m_size = m_font.pointSize();
+}
+
+FontPlatformData::FontPlatformData(const QFont& font, bool bold)
+ : m_size(font.pointSize())
+ , m_bold(bold)
+ , m_oblique(false)
+ , m_font(font)
+{
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : m_size(size)
+ , m_bold(bold)
+ , m_oblique(oblique)
+{
+}
+
+FontPlatformData::FontPlatformData()
+ : m_size(0.0f)
+ , m_bold(false)
+ , m_oblique(false)
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index e2ef605..deeea99 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -20,6 +21,7 @@
#include "config.h"
#include "Font.h"
#include "FontDescription.h"
+#include "FontFallbackList.h"
#include "FontSelector.h"
#include "GraphicsContext.h"
@@ -31,66 +33,9 @@
#include <qdebug.h>
#include <limits.h>
-namespace WebCore {
#if QT_VERSION >= 0x040400
-
-Font::Font()
- : m_letterSpacing(0)
- , m_wordSpacing(0)
- , m_font()
- , m_scFont()
-{
- QFontMetrics metrics(m_font);
- m_spaceWidth = metrics.width(QLatin1Char(' '));
-}
-
-Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing)
- : m_fontDescription(description)
- , m_letterSpacing(letterSpacing)
- , m_wordSpacing(wordSpacing)
-{
- const FontFamily* family = &description.family();
- QString familyName;
- while (family) {
- familyName += family->family();
- family = family->next();
- if (family)
- familyName += QLatin1Char(',');
- }
-
- 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);
-
- bool smallCaps = description.smallCaps();
- m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase);
-
- QFontMetrics metrics = QFontMetrics(m_font);
- m_spaceWidth = metrics.width(QLatin1Char(' '));
-
- if (wordSpacing)
- m_font.setWordSpacing(wordSpacing);
- if (letterSpacing)
- m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing);
-}
-
-void Font::setWordSpacing(short s)
-{
- m_font.setWordSpacing(s);
- m_wordSpacing = s;
-}
-void Font::setLetterSpacing(short s)
-{
- m_font.setLetterSpacing(QFont::AbsoluteSpacing, s);
- m_letterSpacing = s;
-}
-
+namespace WebCore {
static QString qstring(const TextRun& run)
{
@@ -121,10 +66,11 @@ static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
return line;
}
-void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
+void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
{
if (to < 0)
to = run.length();
+
QPainter *p = ctx->platformContext();
Color color = ctx->fillColor();
p->setPen(QColor(color));
@@ -138,14 +84,14 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint&
bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor);
if (from > 0 || to < run.length()) {
- QTextLayout layout(string, m_font);
+ QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
float x1 = line.cursorToX(from);
float x2 = line.cursorToX(to);
if (x2 < x1)
qSwap(x1, x2);
- QFontMetrics fm(m_font);
+ QFontMetrics fm(font());
int ascent = fm.ascent();
QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height());
@@ -179,7 +125,7 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint&
return;
}
- p->setFont(m_font);
+ p->setFont(font());
QPointF pt(point.x(), point.y());
int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
@@ -194,12 +140,12 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint&
p->drawText(pt, string, flags, run.padding());
}
-int Font::width(const TextRun& run) const
+float Font::floatWidthForComplexText(const TextRun& run) const
{
if (!run.length())
return 0;
QString string = qstring(run);
- QTextLayout layout(string, m_font);
+ QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
int w = int(line.naturalTextWidth());
// WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
@@ -209,30 +155,18 @@ int Font::width(const TextRun& run) const
return w + run.padding();
}
-float Font::floatWidth(const TextRun& run) const
-{
- return width(run);
-}
-
-float Font::floatWidth(const TextRun& run, int /*extraCharsAvailable*/, int& charsConsumed, String& glyphName) const
-{
- charsConsumed = run.length();
- glyphName = "";
- return width(run);
-}
-
-int Font::offsetForPosition(const TextRun& run, int position, bool /*includePartialGlyphs*/) const
+int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const
{
QString string = qstring(run);
- QTextLayout layout(string, m_font);
+ QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
return line.xToCursor(position);
}
-FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const
{
QString string = qstring(run);
- QTextLayout layout(string, m_font);
+ QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
float x1 = line.cursorToX(from);
@@ -243,464 +177,12 @@ FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, int
return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
}
-#else
-
-
-struct TextRunComponent {
- TextRunComponent() : font(0) {}
- TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false);
- TextRunComponent(int spaces, bool rtl, const QFont *font, int offset);
-
- inline bool isSpace() const { return spaces != 0; }
-
- QString string;
- const QFont *font;
- int width;
- int offset;
- int spaces;
-};
-
-TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc)
- : string(reinterpret_cast<const QChar*>(start), length)
- , font(f)
- , offset(o)
- , spaces(0)
-{
- if (sc)
- string = string.toUpper();
- string.prepend(rtl ? QChar(0x202e) : QChar(0x202d));
- width = QFontMetrics(*font).width(string);
-}
-
-TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o)
- : string(s, QLatin1Char(' '))
- , font(f)
- , offset(o)
- , spaces(s)
-{
- string.prepend(rtl ? QChar(0x202e) : QChar(0x202d));
- width = spaces * QFontMetrics(*font).width(QLatin1Char(' '));
-}
-
-
-Font::Font()
- : m_letterSpacing(0)
- , m_wordSpacing(0)
- , m_font()
- , m_scFont()
-{
- QFontMetrics metrics(m_font);
- m_spaceWidth = metrics.width(QLatin1Char(' '));
- qreal pointsize = m_font.pointSizeF();
- if (pointsize > 0)
- m_scFont.setPointSizeF(pointsize*0.7);
- else
- m_scFont.setPixelSize(qRound(m_font.pixelSize()*.7));
-}
-
-Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing)
- : m_fontDescription(description)
- , m_letterSpacing(letterSpacing)
- , m_wordSpacing(wordSpacing)
-{
- const FontFamily* family = &description.family();
- QString familyName;
- while (family) {
- familyName += family->family();
- family = family->next();
- if (family)
- familyName += QLatin1Char(',');
- }
-
- 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);
-
- QFontMetrics metrics = QFontMetrics(m_font);
- m_spaceWidth = metrics.width(QLatin1Char(' '));
- m_scFont = m_font;
- m_scFont.setPixelSize(qRound(description.computedSize()*.7));
-}
-
-void Font::setWordSpacing(short s)
-{
- m_wordSpacing = s;
-}
-void Font::setLetterSpacing(short s)
-{
- m_letterSpacing = s;
-}
-
-static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run)
-{
-// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length());
- int letterSpacing = font.letterSpacing();
- int wordSpacing = font.wordSpacing();
- bool smallCaps = font.fontDescription().smallCaps();
- 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;
- const QFont *f = &font.font();
- if (letterSpacing || smallCaps) {
- // 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, run.rtl(), &font.font(), offset));
- offset += add + letterSpacing + components->last().width;
- start = 1;
-// qDebug() << "space at 0" << offset;
- } 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())
- ch = QChar::surrogateToUcs4(ch, run[i-1]);
- if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing)
- continue;
- if (Font::treatAsSpace(run[i])) {
- int add = 0;
-// qDebug() << " treatAsSpace:" << i << start;
- if (i - start > 0) {
- components->append(TextRunComponent(run.characters() + start, i - start,
- run.rtl(),
- f, offset, f == &font.scFont()));
- offset += components->last().width + letterSpacing;
-// qDebug() << " appending(1) " << components->last().string << components->last().width;
- }
- if (numSpaces) {
- add = padding/numSpaces;
- padding -= add;
- --numSpaces;
- }
- components->append(TextRunComponent(1, run.rtl(), &font.font(), offset));
- offset += wordSpacing + add + components->last().width + letterSpacing;
- start = i + 1;
- continue;
- } else if (!letterSpacing) {
-// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) <<
-// QFontInfo(*f).pointSizeF();
- if (QChar::category(ch) == QChar::Letter_Lowercase) {
- if (f == &font.scFont())
- continue;
- } else {
- if (f == &font.font())
- continue;
- }
- }
- if (i - start > 0) {
- components->append(TextRunComponent(run.characters() + start, i - start,
- run.rtl(),
- f, offset, f == &font.scFont()));
- offset += components->last().width + letterSpacing;
-// qDebug() << " appending(2) " << components->last().string << components->last().width;
- }
- if (smallCaps)
- f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font());
- start = i;
- }
- if (run.length() - start > 0) {
- components->append(TextRunComponent(run.characters() + start, run.length() - start,
- run.rtl(),
- f, offset, f == &font.scFont()));
- offset += components->last().width;
-// qDebug() << " appending(3) " << components->last().string << components->last().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.rtl(),
- f, offset));
- offset += components->last().width;
- }
- int add = 0;
- if (numSpaces) {
- add = padding/numSpaces;
- padding -= add;
- --numSpaces;
- }
- components->append(TextRunComponent(1, run.rtl(), &font.font(), offset));
- offset += add + components->last().width;
- if (i)
- offset += wordSpacing;
- start = i + 1;
- }
- }
- if (run.length() - start > 0) {
- components->append(TextRunComponent(run.characters() + start, run.length() - start,
- run.rtl(),
- f, offset));
- offset += components->last().width;
- }
- }
- return offset;
-}
-
-void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
-{
- if (to < 0)
- to = run.length();
- QPainter *p = ctx->platformContext();
- Color color = ctx->fillColor();
- p->setPen(QColor(color));
-
- Vector<TextRunComponent, 1024> components;
- int w = generateComponents(&components, *this, run);
-
- if (from > 0 || to < run.length()) {
- FloatRect clip = selectionRectForText(run,
- IntPoint(qRound(point.x()), qRound(point.y())),
- QFontMetrics(m_font).height(), from, to);
- QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height());
- p->save();
- p->setClipRect(rect.toRect());
- }
-
- if (run.rtl()) {
- for (int i = 0; i < components.size(); ++i) {
- if (!components.at(i).isSpace()) {
- p->setFont(*components.at(i).font);
- QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y());
- p->drawText(pt, components.at(i).string);
- }
- }
- } else {
- for (int i = 0; i < components.size(); ++i) {
- if (!components.at(i).isSpace()) {
- p->setFont(*components.at(i).font);
- QPointF pt(point.x() + components.at(i).offset, point.y());
- p->drawText(pt, components.at(i).string);
- }
- }
- }
- if (from > 0 || to < run.length())
- p->restore();
-}
-
-int Font::width(const TextRun& run) const
-{
- Vector<TextRunComponent, 1024> components;
- int w = generateComponents(&components, *this, run);
-
-// qDebug() << " width=" << w;
- return w;
-}
-
-float Font::floatWidth(const TextRun& run) const
-{
- return width(run);
-}
-
-float Font::floatWidth(const TextRun& run, int /*extraCharsAvailable*/, int& charsConsumed, String& glyphName) const
+QFont Font::font() const
{
- charsConsumed = run.length();
- glyphName = "";
- return width(run);
+ return primaryFont()->getQtFont();
}
-int Font::offsetForPosition(const TextRun& run, int position, bool includePartialGlyphs) const
-{
- Vector<TextRunComponent, 1024> components;
- int w = generateComponents(&components, *this, run);
-
- int offset = 0;
- if (run.rtl()) {
- for (int i = 0; i < components.size(); ++i) {
- int xe = w - components.at(i).offset;
- int xs = xe - components.at(i).width;
- if (position >= xs) {
- QTextLayout layout(components.at(i).string, *components.at(i).font);
- layout.beginLayout();
- QTextLine l = layout.createLine();
- if (!l.isValid())
- return offset;
-
- l.setLineWidth(INT_MAX/256);
- layout.endLayout();
-
- if (position - xs >= l.width())
- return offset;
- int cursor = l.xToCursor(position - xs);
- if (cursor > 1)
- --cursor;
- return offset + cursor;
- } else {
- offset += components.at(i).string.length() - 1;
- }
- }
- } else {
- for (int i = 0; i < components.size(); ++i) {
- int xs = components.at(i).offset;
- int xe = xs + components.at(i).width;
- if (position <= xe) {
- QTextLayout layout(components.at(i).string, *components.at(i).font);
- layout.beginLayout();
- QTextLine l = layout.createLine();
- if (!l.isValid())
- return offset;
-
- l.setLineWidth(INT_MAX/256);
- layout.endLayout();
-
- if (position - xs >= l.width())
- return offset + components.at(i).string.length() - 1;
- int cursor = l.xToCursor(position - xs);
- if (cursor > 1)
- --cursor;
- return offset + cursor;
- } else {
- offset += components.at(i).string.length() - 1;
- }
- }
- }
- return run.length();
}
-static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor)
-{
- int start = 0;
- for (int i = 0; i < components.size(); ++i) {
- if (start + components.at(i).string.length() - 1 < cursor) {
- start += components.at(i).string.length() - 1;
- continue;
- }
- int xs = components.at(i).offset;
- if (rtl)
- xs = width - xs - components.at(i).width;
- QTextLayout layout(components.at(i).string, *components.at(i).font);
- layout.beginLayout();
- QTextLine l = layout.createLine();
- if (!l.isValid())
- return 0;
-
- l.setLineWidth(INT_MAX/256);
- layout.endLayout();
-
- return xs + l.cursorToX(cursor - start + 1);
- }
- return width;
-}
-
-FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt,
- int h, int from, int to) const
-{
- Vector<TextRunComponent, 1024> components;
- int w = generateComponents(&components, *this, run);
-
- if (from == 0 && to == run.length())
- return FloatRect(pt.x(), pt.y(), w, h);
-
- float x1 = cursorToX(components, w, run.rtl(), from);
- float x2 = cursorToX(components, w, run.rtl(), to);
- if (x2 < x1)
- qSwap(x1, x2);
-
- return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
-}
#endif
-
-Font::~Font()
-{
-}
-
-Font::Font(const Font& other)
- : m_fontDescription(other.m_fontDescription)
- , m_letterSpacing(other.m_letterSpacing)
- , m_wordSpacing(other.m_wordSpacing)
- , m_font(other.m_font)
- , m_scFont(other.m_scFont)
- , m_spaceWidth(other.m_spaceWidth)
-{
-}
-
-Font& Font::operator=(const Font& other)
-{
- m_fontDescription = other.m_fontDescription;
- m_letterSpacing = other.m_letterSpacing;
- m_wordSpacing = other.m_wordSpacing;
- m_font = other.m_font;
- m_scFont = other.m_scFont;
- m_spaceWidth = other.m_spaceWidth;
- return *this;
-}
-
-bool Font::operator==(const Font& other) const
-{
- return m_fontDescription == other.m_fontDescription
- && m_letterSpacing == other.m_letterSpacing
- && m_wordSpacing == other.m_wordSpacing
- && m_font == other.m_font
- && m_scFont == other.m_scFont
- && m_spaceWidth == other.m_spaceWidth;
-}
-
-void Font::update(PassRefPtr<FontSelector>) const
-{
- // don't think we need this
-}
-
-
-bool Font::isFixedPitch() const
-{
- return QFontInfo(m_font).fixedPitch();
-}
-
-// Metrics that we query the FontFallbackList for.
-int Font::ascent() const
-{
- return QFontMetrics(m_font).ascent();
-}
-
-int Font::descent() const
-{
- return QFontMetrics(m_font).descent();
-}
-
-int Font::lineSpacing() const
-{
- return QFontMetrics(m_font).lineSpacing();
-}
-
-int Font::lineGap() const
-{
- return QFontMetrics(m_font).leading();
-}
-
-float Font::xHeight() const
-{
- return QFontMetrics(m_font).xHeight();
-}
-
-unsigned Font::unitsPerEm() const
-{
- return 1; // FIXME!
-}
-
-int Font::spaceWidth() const
-{
- return m_spaceWidth;
-}
-
-}
diff --git a/WebCore/platform/graphics/qt/FontQt43.cpp b/WebCore/platform/graphics/qt/FontQt43.cpp
new file mode 100644
index 0000000..137b7c9
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontQt43.cpp
@@ -0,0 +1,356 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ 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 "Font.h"
+#include "FontDescription.h"
+#include "FontFallbackList.h"
+#include "FontSelector.h"
+
+#include "GraphicsContext.h"
+#include <QTextLayout>
+#include <QPainter>
+#include <QFontMetrics>
+#include <QFontInfo>
+#include <qalgorithms.h>
+#include <qdebug.h>
+
+#include <limits.h>
+
+#if QT_VERSION < 0x040400
+
+namespace WebCore {
+
+struct TextRunComponent {
+ TextRunComponent() : font(0) {}
+ TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false);
+ TextRunComponent(int spaces, bool rtl, const QFont *font, int offset);
+
+ inline bool isSpace() const { return spaces != 0; }
+
+ QString string;
+ const QFont *font;
+ int width;
+ int offset;
+ int spaces;
+};
+
+TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc)
+ : string(reinterpret_cast<const QChar*>(start), length)
+ , font(f)
+ , offset(o)
+ , spaces(0)
+{
+ if (sc)
+ string = string.toUpper();
+ string.prepend(rtl ? QChar(0x202e) : QChar(0x202d));
+ width = QFontMetrics(*font).width(string);
+}
+
+TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o)
+ : string(s, QLatin1Char(' '))
+ , font(f)
+ , offset(o)
+ , spaces(s)
+{
+ string.prepend(rtl ? QChar(0x202e) : QChar(0x202d));
+ width = spaces * QFontMetrics(*font).width(QLatin1Char(' '));
+}
+
+
+static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run)
+{
+// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length());
+ int letterSpacing = font.letterSpacing();
+ int wordSpacing = font.wordSpacing();
+ bool smallCaps = font.fontDescription().smallCaps();
+ 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;
+ const QFont *f = &font.font();
+ if (letterSpacing || smallCaps) {
+ // 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, run.rtl(), &font.font(), offset));
+ offset += add + letterSpacing + components->last().width;
+ start = 1;
+// qDebug() << "space at 0" << offset;
+ } 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())
+ ch = QChar::surrogateToUcs4(ch, run[i-1]);
+ if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing)
+ continue;
+ if (Font::treatAsSpace(run[i])) {
+ int add = 0;
+// qDebug() << " treatAsSpace:" << i << start;
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run.rtl(),
+ f, offset, f == &font.scFont()));
+ offset += components->last().width + letterSpacing;
+// qDebug() << " appending(1) " << components->last().string << components->last().width;
+ }
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, run.rtl(), &font.font(), offset));
+ offset += wordSpacing + add + components->last().width + letterSpacing;
+ start = i + 1;
+ continue;
+ } else if (!letterSpacing) {
+// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) <<
+// QFontInfo(*f).pointSizeF();
+ if (QChar::category(ch) == QChar::Letter_Lowercase) {
+ if (f == &font.scFont())
+ continue;
+ } else {
+ if (f == &font.font())
+ continue;
+ }
+ }
+ if (i - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, i - start,
+ run.rtl(),
+ f, offset, f == &font.scFont()));
+ offset += components->last().width + letterSpacing;
+// qDebug() << " appending(2) " << components->last().string << components->last().width;
+ }
+ if (smallCaps)
+ f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font());
+ start = i;
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run.rtl(),
+ f, offset, f == &font.scFont()));
+ offset += components->last().width;
+// qDebug() << " appending(3) " << components->last().string << components->last().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.rtl(),
+ f, offset));
+ offset += components->last().width;
+ }
+ int add = 0;
+ if (numSpaces) {
+ add = padding/numSpaces;
+ padding -= add;
+ --numSpaces;
+ }
+ components->append(TextRunComponent(1, run.rtl(), &font.font(), offset));
+ offset += add + components->last().width;
+ if (i)
+ offset += wordSpacing;
+ start = i + 1;
+ }
+ }
+ if (run.length() - start > 0) {
+ components->append(TextRunComponent(run.characters() + start, run.length() - start,
+ run.rtl(),
+ f, offset));
+ offset += components->last().width;
+ }
+ }
+ return offset;
+}
+
+void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ if (to < 0)
+ to = run.length();
+
+ QPainter *p = ctx->platformContext();
+ Color color = ctx->fillColor();
+ p->setPen(QColor(color));
+
+ Vector<TextRunComponent, 1024> components;
+ int w = generateComponents(&components, *this, run);
+
+ if (from > 0 || to < run.length()) {
+ FloatRect clip = selectionRectForComplexText(run,
+ IntPoint(qRound(point.x()), qRound(point.y())),
+ QFontMetrics(font()).height(), from, to);
+ QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height());
+ p->save();
+ p->setClipRect(rect.toRect());
+ }
+
+ if (run.rtl()) {
+ for (int i = 0; i < components.size(); ++i) {
+ if (!components.at(i).isSpace()) {
+ p->setFont(*components.at(i).font);
+ QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y());
+ p->drawText(pt, components.at(i).string);
+ }
+ }
+ } else {
+ for (int i = 0; i < components.size(); ++i) {
+ if (!components.at(i).isSpace()) {
+ p->setFont(*components.at(i).font);
+ QPointF pt(point.x() + components.at(i).offset, point.y());
+ p->drawText(pt, components.at(i).string);
+ }
+ }
+ }
+ if (from > 0 || to < run.length())
+ p->restore();
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ Vector<TextRunComponent, 1024> components;
+ int w = generateComponents(&components, *this, run);
+
+ return w;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const
+{
+ Vector<TextRunComponent, 1024> components;
+ int w = generateComponents(&components, *this, run);
+
+ int offset = 0;
+ if (run.rtl()) {
+ for (int i = 0; i < components.size(); ++i) {
+ int xe = w - components.at(i).offset;
+ int xs = xe - components.at(i).width;
+ if (position >= xs) {
+ QTextLayout layout(components.at(i).string, *components.at(i).font);
+ layout.beginLayout();
+ QTextLine l = layout.createLine();
+ if (!l.isValid())
+ return offset;
+
+ l.setLineWidth(INT_MAX/256);
+ layout.endLayout();
+
+ if (position - xs >= l.width())
+ return offset;
+ int cursor = l.xToCursor(position - xs);
+ if (cursor > 1)
+ --cursor;
+ return offset + cursor;
+ } else {
+ offset += components.at(i).string.length() - 1;
+ }
+ }
+ } else {
+ for (int i = 0; i < components.size(); ++i) {
+ int xs = components.at(i).offset;
+ int xe = xs + components.at(i).width;
+ if (position <= xe) {
+ QTextLayout layout(components.at(i).string, *components.at(i).font);
+ layout.beginLayout();
+ QTextLine l = layout.createLine();
+ if (!l.isValid())
+ return offset;
+
+ l.setLineWidth(INT_MAX/256);
+ layout.endLayout();
+
+ if (position - xs >= l.width())
+ return offset + components.at(i).string.length() - 1;
+ int cursor = l.xToCursor(position - xs);
+ if (cursor > 1)
+ --cursor;
+ return offset + cursor;
+ } else {
+ offset += components.at(i).string.length() - 1;
+ }
+ }
+ }
+ return run.length();
+}
+
+static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor)
+{
+ int start = 0;
+ for (int i = 0; i < components.size(); ++i) {
+ if (start + components.at(i).string.length() - 1 < cursor) {
+ start += components.at(i).string.length() - 1;
+ continue;
+ }
+ int xs = components.at(i).offset;
+ if (rtl)
+ xs = width - xs - components.at(i).width;
+ QTextLayout layout(components.at(i).string, *components.at(i).font);
+ layout.beginLayout();
+ QTextLine l = layout.createLine();
+ if (!l.isValid())
+ return 0;
+
+ l.setLineWidth(INT_MAX/256);
+ layout.endLayout();
+
+ return xs + l.cursorToX(cursor - start + 1);
+ }
+ return width;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt,
+ int h, int from, int to) const
+{
+ Vector<TextRunComponent, 1024> components;
+ int w = generateComponents(&components, *this, run);
+
+ if (from == 0 && to == run.length())
+ return FloatRect(pt.x(), pt.y(), w, h);
+
+ float x1 = cursorToX(components, w, run.rtl(), from);
+ float x2 = cursorToX(components, w, run.rtl(), to);
+ if (x2 < x1)
+ qSwap(x1, x2);
+
+ return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
+}
+
+int Font::lineGap() const
+{
+ return QFontMetrics(m_font).leading();
+}
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
index d32cc63..2121206 100644
--- a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
+++ b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
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 @@
namespace WebCore {
-void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData)
+void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData*)
+{
+}
+
+void GlyphPageTreeNode::pruneTreeFontData(const WebCore::SimpleFontData*)
{
}
diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp
index f414efa..a0edf8d 100644
--- a/WebCore/platform/graphics/qt/GradientQt.cpp
+++ b/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -52,7 +52,7 @@ QGradient* Gradient::platformGradient()
QColor stopColor;
Vector<ColorStop>::iterator stopIterator = m_stops.begin();
- qreal lastStop;
+ qreal lastStop(0.0);
const qreal lastStopDiff = 0.0000001;
while (stopIterator != m_stops.end()) {
stopColor.setRgbF(stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 600d77c..2e7cdcb 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -39,7 +39,7 @@
#include <windows.h>
#endif
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "Color.h"
#include "FloatConversion.h"
#include "Font.h"
@@ -280,7 +280,7 @@ PlatformGraphicsContext* GraphicsContext::platformContext() const
return m_data->p();
}
-AffineTransform GraphicsContext::getCTM() const
+TransformationMatrix GraphicsContext::getCTM() const
{
return platformContext()->combinedMatrix();
}
@@ -293,6 +293,11 @@ void GraphicsContext::savePlatformState()
void GraphicsContext::restorePlatformState()
{
m_data->p()->restore();
+
+ if (!m_data->currentPath.isEmpty() && m_common->state.pathTransform.isInvertible()) {
+ QMatrix matrix = m_common->state.pathTransform;
+ m_data->currentPath = m_data->currentPath * matrix;
+ }
}
/* FIXME: DISABLED WHILE MERGING BACK FROM UNITY
@@ -520,6 +525,15 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
p->restore();
}
+QPen GraphicsContext::pen()
+{
+ if (paintingDisabled())
+ return QPen();
+
+ QPainter *p = m_data->p();
+ return p->pen();
+}
+
void GraphicsContext::fillPath()
{
if (paintingDisabled())
@@ -533,15 +547,18 @@ void GraphicsContext::fillPath()
if (fillColor().alpha())
p->fillPath(path, p->brush());
break;
- case PatternColorSpace:
- p->fillPath(path, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM())));
+ case PatternColorSpace: {
+ TransformationMatrix affine;
+ p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine)));
break;
+ }
case GradientColorSpace:
- QGradient* gradient = m_common->state.fillGradient.get()->platformGradient();
+ QGradient* gradient = m_common->state.fillGradient->platformGradient();
*gradient = applySpreadMethod(*gradient, spreadMethod());
p->fillPath(path, QBrush(*gradient));
break;
}
+ m_data->currentPath = QPainterPath();
}
void GraphicsContext::strokePath()
@@ -559,13 +576,14 @@ void GraphicsContext::strokePath()
p->strokePath(path, pen);
break;
case PatternColorSpace: {
- pen.setBrush(QBrush(m_common->state.strokePattern.get()->createPlatformPattern(getCTM())));
+ TransformationMatrix affine;
+ pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine)));
p->setPen(pen);
p->strokePath(path, pen);
break;
}
case GradientColorSpace: {
- QGradient* gradient = m_common->state.strokeGradient.get()->platformGradient();
+ QGradient* gradient = m_common->state.strokeGradient->platformGradient();
*gradient = applySpreadMethod(*gradient, spreadMethod());
pen.setBrush(QBrush(*gradient));
p->setPen(pen);
@@ -573,6 +591,7 @@ void GraphicsContext::strokePath()
break;
}
}
+ m_data->currentPath = QPainterPath();
}
void GraphicsContext::fillRect(const FloatRect& rect)
@@ -587,13 +606,16 @@ void GraphicsContext::fillRect(const FloatRect& rect)
if (fillColor().alpha())
p->fillRect(rect, p->brush());
break;
- case PatternColorSpace:
- p->fillRect(rect, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM())));
+ case PatternColorSpace: {
+ TransformationMatrix affine;
+ p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine)));
break;
+ }
case GradientColorSpace:
p->fillRect(rect, QBrush(*(m_common->state.fillGradient.get()->platformGradient())));
break;
}
+ m_data->currentPath = QPainterPath();
}
void GraphicsContext::fillRect(const FloatRect& rect, const Color& c)
@@ -621,7 +643,9 @@ void GraphicsContext::beginPath()
void GraphicsContext::addPath(const Path& path)
{
- m_data->currentPath = *(path.platformPath());
+ QPainterPath newPath = m_data->currentPath;
+ newPath.addPath(*(path.platformPath()));
+ m_data->currentPath = newPath;
}
bool GraphicsContext::inTransparencyLayer() const
@@ -645,6 +669,17 @@ void GraphicsContext::clip(const FloatRect& rect)
else p->setClipRect(rect, Qt::IntersectClip);
}
+void GraphicsContext::clipPath(WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QPainterPath newPath = m_data->currentPath;
+ newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+ p->setClipPath(newPath);
+}
+
/**
* Focus ring handling is not handled here. Qt style in
* RenderTheme handles drawing focus on widgets which
@@ -823,8 +858,9 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
if (dashLength % 2)
count *= 2;
+ float penWidth = narrowPrecisionToFloat(double(pen.widthF()));
for (unsigned i = 0; i < count; i++)
- pattern.append(dashes[i % dashLength] / narrowPrecisionToFloat(pen.widthF()));
+ pattern.append(dashes[i % dashLength] / penWidth);
pen.setDashPattern(pattern);
pen.setDashOffset(dashOffset);
@@ -901,6 +937,12 @@ void GraphicsContext::translate(float x, float y)
return;
m_data->p()->translate(x, y);
+
+ if (!m_data->currentPath.isEmpty()) {
+ QMatrix matrix;
+ m_data->currentPath = m_data->currentPath * matrix.translate(-x, -y);
+ m_common->state.pathTransform.translate(x, y);
+ }
}
IntPoint GraphicsContext::origin()
@@ -917,6 +959,12 @@ void GraphicsContext::rotate(float radians)
return;
m_data->p()->rotate(180/M_PI*radians);
+
+ if (!m_data->currentPath.isEmpty()) {
+ QMatrix matrix;
+ m_data->currentPath = m_data->currentPath * matrix.rotate(-180/M_PI*radians);
+ m_common->state.pathTransform.rotate(radians);
+ }
}
void GraphicsContext::scale(const FloatSize& s)
@@ -925,6 +973,12 @@ void GraphicsContext::scale(const FloatSize& s)
return;
m_data->p()->scale(s.width(), s.height());
+
+ if (!m_data->currentPath.isEmpty()) {
+ QMatrix matrix;
+ m_data->currentPath = m_data->currentPath * matrix.scale(1 / s.width(), 1 / s.height());
+ m_common->state.pathTransform.scale(s.width(), s.height());
+ }
}
void GraphicsContext::clipOut(const IntRect& rect)
@@ -982,12 +1036,20 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
m_data->p()->setClipPath(path, Qt::IntersectClip);
}
-void GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContext::concatCTM(const TransformationMatrix& transform)
{
if (paintingDisabled())
return;
m_data->p()->setMatrix(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.
+ if (!m_data->currentPath.isEmpty() && transform.isInvertible()) {
+ QMatrix matrix = transform.inverse();
+ m_data->currentPath = m_data->currentPath * matrix;
+ m_common->state.pathTransform.multiply(transform);
+ }
}
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
@@ -995,13 +1057,6 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
notImplemented();
}
-void GraphicsContext::setPlatformFont(const Font& aFont)
-{
- if (paintingDisabled())
- return;
- m_data->p()->setFont(aFont.font());
-}
-
void GraphicsContext::setPlatformStrokeColor(const Color& color)
{
if (paintingDisabled())
@@ -1039,7 +1094,7 @@ void GraphicsContext::setPlatformFillColor(const Color& color)
m_data->p()->setBrush(QBrush(color));
}
-void GraphicsContext::setUseAntialiasing(bool enable)
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
{
if (paintingDisabled())
return;
@@ -1051,8 +1106,8 @@ void GraphicsContext::setUseAntialiasing(bool enable)
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
- // painting through native HDC is only supported for plugin, where mayCreateBitmap is always TRUE
- Q_ASSERT(mayCreateBitmap == TRUE);
+ // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
+ Q_ASSERT(mayCreateBitmap);
if (dstRect.isEmpty())
return 0;
@@ -1090,6 +1145,7 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
memset(bmpInfo.bmBits, 0, bufferSize);
}
+#if !PLATFORM(WIN_CE)
// Make sure we can do world transforms.
SetGraphicsMode(bitmapDC, GM_ADVANCED);
@@ -1102,15 +1158,15 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
xform.eDx = -dstRect.x();
xform.eDy = -dstRect.y();
::SetWorldTransform(bitmapDC, &xform);
-
+#endif
return bitmapDC;
}
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
- // painting through native HDC is only supported for plugin, where mayCreateBitmap is always TRUE
- Q_ASSERT(mayCreateBitmap == TRUE);
+ // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
+ Q_ASSERT(mayCreateBitmap);
if (hdc) {
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index e3b00a1..394c7a7 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -178,9 +178,26 @@ ImageDecoderQt::ReadContext::IncrementalReadResult
return IncrementalReadComplete;
}
+ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data)
+{
+ // We need at least 4 bytes to figure out what kind of image we're dealing with.
+ if (data.size() < 4)
+ return 0;
+
+ QByteArray bytes = QByteArray::fromRawData(data.data(), data.size());
+ QBuffer buffer(&bytes);
+ if (!buffer.open(QBuffer::ReadOnly))
+ return 0;
+
+ QString imageFormat = QString::fromLatin1(QImageReader::imageFormat(&buffer).toLower());
+ if (imageFormat.isEmpty())
+ return 0; // Image format not supported
+
+ return new ImageDecoderQt(imageFormat);
+}
-// ImageDecoderQt
-ImageDecoderQt::ImageDecoderQt( )
+ImageDecoderQt::ImageDecoderQt(const QString &imageFormat)
+ : m_imageFormat(imageFormat)
{
}
@@ -254,7 +271,6 @@ int ImageDecoderQt::frameCount() const
return m_imageList.size();
}
-
int ImageDecoderQt::repetitionCount() const
{
if (debugImageDecoderQt)
@@ -262,7 +278,6 @@ int ImageDecoderQt::repetitionCount() const
return m_loopCount;
}
-
bool ImageDecoderQt::supportsAlpha() const
{
return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel();
@@ -275,6 +290,13 @@ int ImageDecoderQt::duration(size_t index) const
return m_imageList[index].m_duration;
}
+String ImageDecoderQt::filenameExtension() const
+{
+ if (debugImageDecoderQt)
+ qDebug() << " ImageDecoderQt::filenameExtension() returns" << m_imageFormat;
+ return m_imageFormat;
+};
+
RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
{
Q_ASSERT("use imageAtIndex instead");
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h
index 3573dd0..a2eb6aa 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.h
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -38,34 +38,30 @@ namespace WebCore {
class ImageDecoderQt : public ImageDecoder
{
- ImageDecoderQt(const ImageDecoderQt&);
- ImageDecoderQt &operator=(const ImageDecoderQt&);
public:
- ImageDecoderQt();
+ static ImageDecoderQt* create(const SharedBuffer& data);
~ImageDecoderQt();
typedef Vector<char> IncomingData;
virtual void setData(const IncomingData& data, bool allDataReceived);
-
virtual bool isSizeAvailable() const;
-
virtual int frameCount() const;
-
-
virtual int repetitionCount() const;
-
-
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
QPixmap* imageAtIndex(size_t index) const;
-
virtual bool supportsAlpha() const;
-
int duration(size_t index) const;
+ virtual String filenameExtension() const;
void clearFrame(size_t index);
+
private:
+ ImageDecoderQt(const QString &imageFormat);
+ ImageDecoderQt(const ImageDecoderQt&);
+ ImageDecoderQt &operator=(const ImageDecoderQt&);
+
class ReadContext;
void reset();
bool hasFirstImageHeader() const;
@@ -89,6 +85,7 @@ private:
ImageList m_imageList;
mutable QHash<int, QPixmap> m_pixmapCache;
int m_loopCount;
+ QString m_imageFormat;
};
diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp
index 9234c69..99062f9 100644
--- a/WebCore/platform/graphics/qt/ImageQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -34,7 +34,7 @@
#include "FloatRect.h"
#include "PlatformString.h"
#include "GraphicsContext.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "NotImplemented.h"
#include "StillImageQt.h"
#include "qwebsettings.h"
@@ -69,14 +69,16 @@ static QPixmap loadResourcePixmap(const char *name)
namespace WebCore {
-void FrameData::clear()
+bool FrameData::clear(bool clearMetadata)
{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
if (m_frame) {
m_frame = 0;
- // NOTE: We purposefully don't reset metadata here, so that even if we
- // throw away previously-decoded data, animation loops can still access
- // properties like frame durations without re-decoding.
+ return true;
}
+ return false;
}
@@ -91,7 +93,7 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name)
}
-void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
notImplemented();
@@ -136,7 +138,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
ctxt->restore();
}
-void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform,
const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
{
QPixmap* framePixmap = nativeImageForCurrentFrame();
diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
index 1d14f9d..d62acc3 100644
--- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
@@ -29,6 +29,7 @@
#include "config.h"
#include "ImageSource.h"
#include "ImageDecoderQt.h"
+#include "NotImplemented.h"
#include "SharedBuffer.h"
#include <QBuffer>
@@ -36,25 +37,6 @@
#include <QImageReader>
namespace WebCore {
-static bool canHandleImage(const SharedBuffer& _data)
-{
- // We need at least 4 bytes to figure out what kind of image we're dealing with.
- if (_data.size() < 4)
- return false;
-
- QByteArray data = QByteArray::fromRawData(_data.data(), _data.size());
- QBuffer buffer(&data);
- if (!buffer.open(QBuffer::ReadOnly))
- return false;
-
- return !QImageReader::imageFormat(&buffer).isEmpty();
-}
-
-ImageDecoderQt* createDecoder(const SharedBuffer& data) {
- if (!canHandleImage(data))
- return 0;
- return new ImageDecoderQt();
-}
ImageSource::ImageSource()
: m_decoder(0)
@@ -63,7 +45,7 @@ ImageSource::ImageSource()
ImageSource::~ImageSource()
{
- delete m_decoder;
+ clear(true);
}
bool ImageSource::initialized() const
@@ -78,7 +60,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);
+ m_decoder = ImageDecoderQt::create(*data);
if (!m_decoder)
return;
@@ -86,6 +68,14 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
m_decoder->setData(data->buffer(), allDataReceived);
}
+String ImageSource::filenameExtension() const
+{
+ if (!m_decoder)
+ return String();
+
+ return m_decoder->filenameExtension();
+}
+
bool ImageSource::isSizeAvailable()
{
if (!m_decoder)
@@ -162,13 +152,20 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index)
return (m_decoder && m_decoder->imageAtIndex(index) != 0);
}
-void ImageSource::clear()
+void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
{
- delete m_decoder;
+ if (!destroyAll) {
+ if (m_decoder)
+ m_decoder->clearFrameBufferCache(clearBeforeFrame);
+ return;
+ }
+
+ delete m_decoder;
m_decoder = 0;
+ if (data)
+ setData(data, allDataReceived);
}
-
}
// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
index 431e68e..b1a48fb 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -84,6 +84,9 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
{
// Hint to Phonon to disable overlay painting
m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen);
+#if QT_VERSION < 0x040500
+ m_videoWidget->setAttribute(Qt::WA_QuitOnClose, false);
+#endif
createPath(m_mediaObject, m_videoWidget);
createPath(m_mediaObject, m_audioOutput);
@@ -96,7 +99,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
this, SLOT(stateChanged(Phonon::State, Phonon::State)));
- connect(m_mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool)));
connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool)));
@@ -105,7 +107,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
connect(m_mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)),
this, SLOT(currentSourceChanged(const Phonon::MediaSource&)));
connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
- connect(m_mediaObject, SIGNAL(prefinishMarkReached(qint32)), this, SLOT(prefinishMarkReached(qint32)));
connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
}
@@ -314,7 +315,7 @@ void MediaPlayerPrivate::updateStates()
m_mediaObject->pause();
}
} else if (phononState == Phonon::PausedState) {
- m_networkState = MediaPlayer::LoadedFirstFrame;
+ m_networkState = MediaPlayer::Loaded;
m_readyState = MediaPlayer::CanPlayThrough;
} else if (phononState == Phonon::ErrorState) {
if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) {
@@ -371,42 +372,6 @@ void MediaPlayerPrivate::setRect(const IntRect& newRect)
m_videoWidget->resize(newRect.width(), newRect.height());
}
-
-void MediaPlayerPrivate::loadStateChanged()
-{
- notImplemented();
-}
-
-void MediaPlayerPrivate::rateChanged()
-{
- notImplemented();
-}
-
-void MediaPlayerPrivate::sizeChanged()
-{
- notImplemented();
-}
-
-void MediaPlayerPrivate::timeChanged()
-{
- notImplemented();
-}
-
-void MediaPlayerPrivate::volumeChanged()
-{
- notImplemented();
-}
-
-void MediaPlayerPrivate::didEnd()
-{
- notImplemented();
-}
-
-void MediaPlayerPrivate::loadingFailed()
-{
- notImplemented();
-}
-
IntSize MediaPlayerPrivate::naturalSize() const
{
if (!hasVideo()) {
@@ -430,17 +395,12 @@ IntSize MediaPlayerPrivate::naturalSize() const
bool MediaPlayerPrivate::eventFilter(QObject* obj, QEvent* event)
{
- if (event->type() == QEvent::Paint)
+ if (event->type() == QEvent::UpdateRequest)
m_player->repaint();
return QObject::eventFilter(obj, event);
}
-void MediaPlayerPrivate::repaint()
-{
- m_player->repaint();
-}
-
void MediaPlayerPrivate::paint(GraphicsContext* graphicsContect, const IntRect& rect)
{
if (graphicsContect->paintingDisabled())
@@ -469,12 +429,6 @@ void MediaPlayerPrivate::stateChanged(Phonon::State newState, Phonon::State oldS
updateStates();
}
-void MediaPlayerPrivate::tick(qint64)
-{
- updateStates();
- m_player->timeChanged();
-}
-
void MediaPlayerPrivate::metaDataChanged()
{
LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()");
@@ -516,12 +470,6 @@ void MediaPlayerPrivate::aboutToFinish()
LOG_MEDIAOBJECT();
}
-void MediaPlayerPrivate::prefinishMarkReached(qint32)
-{
- notImplemented();
- LOG_MEDIAOBJECT();
-}
-
void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime)
{
LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%d)", totalTime);
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
index 5eb2a09..1b20a84 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -111,15 +111,6 @@ namespace WebCore {
void setVisible(bool);
void setRect(const IntRect&);
- void loadStateChanged();
- void rateChanged();
- void sizeChanged();
- void timeChanged();
- void volumeChanged();
- void didEnd();
- void loadingFailed();
-
- void repaint();
void paint(GraphicsContext*, const IntRect&);
static void getSupportedTypes(HashSet<String>&);
static bool isAvailable() { return true; }
@@ -129,7 +120,6 @@ namespace WebCore {
private slots:
void stateChanged(Phonon::State, Phonon::State);
- void tick(qint64);
void metaDataChanged();
void seekableChanged(bool);
void hasVideoChanged(bool);
@@ -137,7 +127,6 @@ namespace WebCore {
void finished();
void currentSourceChanged(const Phonon::MediaSource&);
void aboutToFinish();
- void prefinishMarkReached(qint32);
void totalTimeChanged(qint64);
private:
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index 76f375c..bd0192c 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -29,9 +29,12 @@
#include "config.h"
#include "Path.h"
+#include "TransformationMatrix.h"
#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
#include "PlatformString.h"
-#include "AffineTransform.h"
+#include "StrokeStyleApplier.h"
#include <QPainterPath>
#include <QMatrix>
#include <QString>
@@ -39,6 +42,10 @@
#define _USE_MATH_DEFINES
#include <math.h>
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
namespace WebCore {
Path::Path()
@@ -77,6 +84,28 @@ bool Path::contains(const FloatPoint& point, WindRule rule) const
return contains;
}
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+
+ // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer
+ // on each call.
+ std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false);
+ GraphicsContext* gc = scratchImage->context();
+ QPainterPathStroker stroke;
+ applier->strokeStyle(gc);
+
+ QPen pen = gc->pen();
+ stroke.setWidth(pen.widthF());
+ stroke.setCapStyle(pen.capStyle());
+ stroke.setJoinStyle(pen.joinStyle());
+ stroke.setMiterLimit(pen.miterLimit());
+ stroke.setDashPattern(pen.dashPattern());
+ stroke.setDashOffset(pen.dashOffset());
+
+ return (stroke.createStroke(*platformPath())).contains(point);
+}
+
void Path::translate(const FloatSize& size)
{
QMatrix matrix;
@@ -89,6 +118,27 @@ FloatRect Path::boundingRect() const
return m_path->boundingRect();
}
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer
+ // on each call.
+ std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false);
+ GraphicsContext* gc = scratchImage->context();
+ QPainterPathStroker stroke;
+ if (applier) {
+ applier->strokeStyle(gc);
+
+ QPen pen = gc->pen();
+ stroke.setWidth(pen.widthF());
+ stroke.setCapStyle(pen.capStyle());
+ stroke.setJoinStyle(pen.joinStyle());
+ stroke.setMiterLimit(pen.miterLimit());
+ stroke.setDashPattern(pen.dashPattern());
+ stroke.setDashOffset(pen.dashOffset());
+ }
+ return (stroke.createStroke(*platformPath())).boundingRect();
+}
+
void Path::moveTo(const FloatPoint& point)
{
m_path->moveTo(point);
@@ -263,7 +313,7 @@ void Path::apply(void* info, PathApplierFunction function) const
}
}
-void Path::transform(const AffineTransform& transform)
+void Path::transform(const TransformationMatrix& transform)
{
if (m_path) {
QMatrix mat = transform;
diff --git a/WebCore/platform/graphics/qt/PatternQt.cpp b/WebCore/platform/graphics/qt/PatternQt.cpp
index 883a258..5b76841 100644
--- a/WebCore/platform/graphics/qt/PatternQt.cpp
+++ b/WebCore/platform/graphics/qt/PatternQt.cpp
@@ -26,12 +26,12 @@
#include "config.h"
#include "Pattern.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "GraphicsContext.h"
namespace WebCore {
-QBrush Pattern::createPlatformPattern(const AffineTransform& transform) const
+QBrush Pattern::createPlatformPattern(const TransformationMatrix& transform) const
{
QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame();
if (!pixmap)
diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
index 1ffce33..6cf4e55 100644
--- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
+++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
@@ -1,5 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -19,37 +20,47 @@
This class provides all functionality needed for loading images, style sheets and html
pages from the web. It has a memory cache for these objects.
*/
+
#include "config.h"
#include "SimpleFontData.h"
-#include "SVGFontData.h"
+#include <QFontMetrics>
namespace WebCore {
-SimpleFontData::SimpleFontData(const FontPlatformData& font, bool customFont, bool loading, SVGFontData*)
- : m_font(font)
- , m_isCustomFont(customFont)
- , m_isLoading(loading)
+void SimpleFontData::determinePitch()
{
+ m_treatAsFixedPitch = m_font.font().fixedPitch();
}
-SimpleFontData::~SimpleFontData()
+bool SimpleFontData::containsCharacters(const UChar*, int length) const
{
+ return true;
}
-bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+void SimpleFontData::platformInit()
{
- return true;
+ QFontMetrics fm(m_font.font());
+
+ m_ascent = fm.ascent();
+ m_descent = fm.descent();
+ m_lineSpacing = fm.lineSpacing();
+ m_xHeight = fm.xHeight();
+ m_spaceWidth = fm.width(QLatin1Char(' '));
+ m_lineGap = fm.leading();
}
-const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
+void SimpleFontData::platformGlyphInit()
{
- return this;
+ m_spaceGlyph = 0;
+ m_adjustedSpaceWidth = m_spaceWidth;
+ determinePitch();
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
}
-bool SimpleFontData::isSegmented() const
+void SimpleFontData::platformDestroy()
{
- return false;
}
}
diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h
index 37b8b2c..2b2c1f7 100644
--- a/WebCore/platform/graphics/qt/StillImageQt.h
+++ b/WebCore/platform/graphics/qt/StillImageQt.h
@@ -41,7 +41,7 @@ namespace WebCore {
// FIXME: StillImages are underreporting decoded sizes and will be unable
// to prune because these functions are not implemented yet.
- virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) { }
+ virtual void destroyDecodedData(bool destroyAll = true) { }
virtual unsigned decodedSize() const { return 0; }
virtual IntSize size() const;
diff --git a/WebCore/platform/graphics/qt/AffineTransformQt.cpp b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
index 2793043..47abd17 100644
--- a/WebCore/platform/graphics/qt/AffineTransformQt.cpp
+++ b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
@@ -24,34 +24,34 @@
*/
#include "config.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "IntRect.h"
#include "FloatRect.h"
namespace WebCore {
-AffineTransform::AffineTransform()
+TransformationMatrix::TransformationMatrix()
: m_transform()
{
}
-AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty)
: m_transform(a, b, c, d, tx, ty)
{
}
-AffineTransform::AffineTransform(const PlatformAffineTransform& matrix)
+TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
: m_transform(matrix)
{
}
-void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
+void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty)
{
m_transform.setMatrix(a, b, c, d, tx, ty);
}
-void AffineTransform::map(double x, double y, double* x2, double* y2) const
+void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
{
qreal tx2, ty2;
m_transform.map(qreal(x), qreal(y), &tx2, &ty2);
@@ -59,140 +59,140 @@ void AffineTransform::map(double x, double y, double* x2, double* y2) const
*y2 = ty2;
}
-IntRect AffineTransform::mapRect(const IntRect& rect) const
+IntRect TransformationMatrix::mapRect(const IntRect& rect) const
{
return m_transform.mapRect(rect);
}
-FloatRect AffineTransform::mapRect(const FloatRect& rect) const
+FloatRect TransformationMatrix::mapRect(const FloatRect& rect) const
{
return m_transform.mapRect(rect);
}
-bool AffineTransform::isIdentity() const
+bool TransformationMatrix::isIdentity() const
{
return m_transform.isIdentity();
}
-double AffineTransform::a() const
+double TransformationMatrix::a() const
{
return m_transform.m11();
}
-void AffineTransform::setA(double a)
+void TransformationMatrix::setA(double a)
{
m_transform.setMatrix(a, b(), c(), d(), e(), f());
}
-double AffineTransform::b() const
+double TransformationMatrix::b() const
{
return m_transform.m12();
}
-void AffineTransform::setB(double b)
+void TransformationMatrix::setB(double b)
{
m_transform.setMatrix(a(), b, c(), d(), e(), f());
}
-double AffineTransform::c() const
+double TransformationMatrix::c() const
{
return m_transform.m21();
}
-void AffineTransform::setC(double c)
+void TransformationMatrix::setC(double c)
{
m_transform.setMatrix(a(), b(), c, d(), e(), f());
}
-double AffineTransform::d() const
+double TransformationMatrix::d() const
{
return m_transform.m22();
}
-void AffineTransform::setD(double d)
+void TransformationMatrix::setD(double d)
{
m_transform.setMatrix(a(), b(), c(), d, e(), f());
}
-double AffineTransform::e() const
+double TransformationMatrix::e() const
{
return m_transform.dx();
}
-void AffineTransform::setE(double e)
+void TransformationMatrix::setE(double e)
{
m_transform.setMatrix(a(), b(), c(), d(), e, f());
}
-double AffineTransform::f() const
+double TransformationMatrix::f() const
{
return m_transform.dy();
}
-void AffineTransform::setF(double f)
+void TransformationMatrix::setF(double f)
{
m_transform.setMatrix(a(), b(), c(), d(), e(), f);
}
-void AffineTransform::reset()
+void TransformationMatrix::reset()
{
m_transform.reset();
}
-AffineTransform& AffineTransform::scale(double sx, double sy)
+TransformationMatrix& TransformationMatrix::scale(double sx, double sy)
{
m_transform.scale(sx, sy);
return *this;
}
-AffineTransform& AffineTransform::rotate(double d)
+TransformationMatrix& TransformationMatrix::rotate(double d)
{
m_transform.rotate(d);
return *this;
}
-AffineTransform& AffineTransform::translate(double tx, double ty)
+TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
{
m_transform.translate(tx, ty);
return *this;
}
-AffineTransform& AffineTransform::shear(double sx, double sy)
+TransformationMatrix& TransformationMatrix::shear(double sx, double sy)
{
m_transform.shear(sx, sy);
return *this;
}
-double AffineTransform::det() const
+double TransformationMatrix::det() const
{
return m_transform.det();
}
-AffineTransform AffineTransform::inverse() const
+TransformationMatrix TransformationMatrix::inverse() const
{
if(!isInvertible())
- return AffineTransform();
+ return TransformationMatrix();
return m_transform.inverted();
}
-AffineTransform::operator QMatrix() const
+TransformationMatrix::operator QMatrix() const
{
return m_transform;
}
-bool AffineTransform::operator==(const AffineTransform& other) const
+bool TransformationMatrix::operator==(const TransformationMatrix& other) const
{
return m_transform == other.m_transform;
}
-AffineTransform& AffineTransform::operator*=(const AffineTransform& other)
+TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other)
{
m_transform *= other.m_transform;
return *this;
}
-AffineTransform AffineTransform::operator*(const AffineTransform& other)
+TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& other)
{
return m_transform * other.m_transform;
}
diff --git a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h
new file mode 100644
index 0000000..5d85652
--- /dev/null
+++ b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2006,2007,2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BitmapImageSingleFrameSkia_h
+#define BitmapImageSingleFrameSkia_h
+
+#include "Image.h"
+#include "NativeImageSkia.h"
+
+namespace WebCore {
+
+// This image class can be used in places which need an Image, but have
+// raw pixel data rather than undecoded image data.
+// The Image is simpler than a BitmapImage, as it does not have image
+// observers, animation, multiple frames, or non-decoded data.
+// Therefore trimming the decoded data (destroyDecodedData()) has no effect.
+//
+// The difficulty with putting this in BitmapImage::create(NativeImagePtr)
+// is that NativeImagePtr = NativeImageSkia, yet callers have SkBitmap.
+class BitmapImageSingleFrameSkia : public Image {
+public:
+ // Creates a new Image, by copying the pixel values out of |bitmap|.
+ // If creation failed, returns null.
+ static PassRefPtr<BitmapImageSingleFrameSkia> create(const SkBitmap&);
+
+ virtual bool isBitmapImage() const { return true; }
+
+ virtual IntSize size() const
+ {
+ return IntSize(m_nativeImage.width(), m_nativeImage.height());
+ }
+
+ // Do nothing, as we only have the one representation of data (decoded).
+ virtual void destroyDecodedData(bool destroyAll = true) { }
+
+ virtual unsigned decodedSize() const
+ {
+ return m_nativeImage.decodedSize();
+ }
+
+ // We only have a single frame.
+ virtual NativeImagePtr nativeImageForCurrentFrame()
+ {
+ return &m_nativeImage;
+ }
+
+protected:
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
+
+private:
+ NativeImageSkia m_nativeImage;
+
+ // Use create().
+ BitmapImageSingleFrameSkia() { }
+};
+
+} // namespace WebCore
+
+#endif // BitmapImageSingleFrameSkia_h
diff --git a/WebCore/platform/graphics/skia/FloatPointSkia.cpp b/WebCore/platform/graphics/skia/FloatPointSkia.cpp
new file mode 100644
index 0000000..054a772
--- /dev/null
+++ b/WebCore/platform/graphics/skia/FloatPointSkia.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+#include "SkPoint.h"
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const SkPoint& p)
+ : m_x(p.fX)
+ , m_y(p.fY)
+{
+}
+
+FloatPoint::operator SkPoint() const
+{
+ SkPoint p = { WebCoreFloatToSkScalar(m_x), WebCoreFloatToSkScalar(m_y) };
+ return p;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/FloatRectSkia.cpp b/WebCore/platform/graphics/skia/FloatRectSkia.cpp
new file mode 100644
index 0000000..a10371f
--- /dev/null
+++ b/WebCore/platform/graphics/skia/FloatRectSkia.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include "SkRect.h"
+
+namespace WebCore {
+
+FloatRect::FloatRect(const SkRect& r)
+ : m_location(r.fLeft, r.fTop)
+ , m_size(r.width(), r.height())
+{
+}
+
+FloatRect::operator SkRect() const
+{
+ SkRect rect = { x(), y(), right(), bottom() };
+ return rect;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp
new file mode 100644
index 0000000..eff7c66
--- /dev/null
+++ b/WebCore/platform/graphics/skia/GradientSkia.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+
+#include "SkGradientShader.h"
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ if (m_gradient)
+ m_gradient->safeUnref();
+ m_gradient = 0;
+}
+
+static inline U8CPU F2B(float x)
+{
+ return static_cast<int>(x * 255);
+}
+
+static SkColor makeSkColor(float a, float r, float g, float b)
+{
+ return SkColorSetARGB(F2B(a), F2B(r), F2B(g), F2B(b));
+}
+
+// Determine the total number of stops needed, including pseudo-stops at the
+// ends as necessary.
+static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count)
+{
+ const Gradient::ColorStop* stop = stopData;
+ size_t countUsed = count;
+ if (count < 1 || stop->stop > 0.0)
+ countUsed++;
+ stop += count - 1;
+ if (count < 2 || stop->stop < 1.0)
+ countUsed++;
+ return countUsed;
+}
+
+// Collect sorted stop position and color information into the pos and colors
+// buffers, ensuring stops at both 0.0 and 1.0. The buffers must be large
+// enough to hold information for all stops, including the new endpoints if
+// stops at 0.0 and 1.0 aren't already included.
+static void fillStops(const Gradient::ColorStop* stopData,
+ size_t count, SkScalar* pos, SkColor* colors)
+{
+ const Gradient::ColorStop* stop = stopData;
+ size_t start = 0;
+ if (count < 1) {
+ // A gradient with no stops must be transparent black.
+ pos[0] = WebCoreFloatToSkScalar(0.0);
+ colors[0] = makeSkColor(0.0, 0.0, 0.0, 0.0);
+ start = 1;
+ } else if (stop->stop > 0.0) {
+ // Copy the first stop to 0.0. The first stop position may have a slight
+ // rounding error, but we don't care in this float comparison, since
+ // 0.0 comes through cleanly and people aren't likely to want a gradient
+ // with a stop at (0 + epsilon).
+ pos[0] = WebCoreFloatToSkScalar(0.0);
+ colors[0] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue);
+ start = 1;
+ }
+
+ for (size_t i = start; i < start + count; i++) {
+ pos[i] = WebCoreFloatToSkScalar(stop->stop);
+ colors[i] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue);
+ ++stop;
+ }
+
+ // Copy the last stop to 1.0 if needed. See comment above about this float
+ // comparison.
+ if (count < 1 || (--stop)->stop < 1.0) {
+ pos[start + count] = WebCoreFloatToSkScalar(1.0);
+ colors[start + count] = colors[start + count - 1];
+ }
+}
+
+static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
+{
+ return a.stop < b.stop;
+}
+
+SkShader* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ // FIXME: This and compareStops() are also in Gradient.cpp and
+ // CSSGradientValue.cpp; probably should refactor in WebKit.
+ if (!m_stopsSorted) {
+ if (m_stops.size())
+ std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+ m_stopsSorted = true;
+ }
+ size_t countUsed = totalStopsNeeded(m_stops.data(), m_stops.size());
+ ASSERT(countUsed >= 2);
+ ASSERT(countUsed >= m_stops.size());
+
+ // FIXME: Why is all this manual pointer math needed?!
+ SkAutoMalloc storage(countUsed * (sizeof(SkColor) + sizeof(SkScalar)));
+ SkColor* colors = (SkColor*)storage.get();
+ SkScalar* pos = (SkScalar*)(colors + countUsed);
+
+ fillStops(m_stops.data(), m_stops.size(), pos, colors);
+
+ if (m_radial) {
+ // FIXME: CSS radial Gradients allow an offset focal point (the
+ // "start circle"), but skia doesn't seem to support that, so this just
+ // ignores m_p0/m_r0 and draws the gradient centered in the "end
+ // circle" (m_p1/m_r1).
+ // See http://webkit.org/blog/175/introducing-css-gradients/ for a
+ // description of the expected behavior.
+ m_gradient = SkGradientShader::CreateRadial(m_p1,
+ WebCoreFloatToSkScalar(m_r1), colors, pos,
+ static_cast<int>(countUsed), SkShader::kClamp_TileMode);
+ } else {
+ SkPoint pts[2] = { m_p0, m_p1 };
+ m_gradient = SkGradientShader::CreateLinear(pts, colors, pos,
+ static_cast<int>(countUsed), SkShader::kClamp_TileMode);
+ }
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->setFillGradient(this);
+ context->fillRect(rect);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h b/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h
new file mode 100644
index 0000000..29738f4
--- /dev/null
+++ b/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsContextPlatformPrivate_h
+#define GraphicsContextPlatformPrivate_h
+
+#include <wtf/Noncopyable.h>
+
+class PlatformContextSkia;
+
+namespace WebCore {
+
+// This class just holds onto a PlatformContextSkia for GraphicsContext.
+class GraphicsContextPlatformPrivate : Noncopyable {
+public:
+ GraphicsContextPlatformPrivate(PlatformContextSkia* platformContext)
+ : m_context(platformContext) { }
+
+ PlatformContextSkia* context() { return m_context; }
+
+private:
+ // Non-owning pointer to the PlatformContext.
+ PlatformContextSkia* m_context;
+};
+
+} // namespace WebCore
+
+#endif // GraphicsContextPlatformPrivate_h
diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
new file mode 100644
index 0000000..e6c7783
--- /dev/null
+++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -0,0 +1,1122 @@
+/*
+ * Copyright (c) 2006, 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 "GraphicsContext.h"
+
+#include "GraphicsContextPlatformPrivate.h"
+#include "GraphicsContextPrivate.h"
+#include "Color.h"
+#include "FloatRect.h"
+#include "Gradient.h"
+#include "IntRect.h"
+#include "NativeImageSkia.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+#include "TransformationMatrix.h"
+
+#include "SkBitmap.h"
+#include "SkBlurDrawLooper.h"
+#include "SkCornerPathEffect.h"
+#include "skia/ext/platform_canvas.h"
+#include "SkiaUtils.h"
+#include "SkShader.h"
+
+#include <math.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+namespace {
+
+// "Seatbelt" functions ------------------------------------------------------
+//
+// These functions check certain graphics primitives for being "safe".
+// Skia has historically crashed when sent crazy data. These functions do
+// additional checking to prevent crashes.
+//
+// Ideally, all of these would be fixed in the graphics layer and we would not
+// have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA
+// flag to check the graphics layer.
+#define ENSURE_VALUE_SAFETY_FOR_SKIA
+
+static bool isCoordinateSkiaSafe(float coord)
+{
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+ // First check for valid floats.
+#if defined(_MSC_VER)
+ if (!_finite(coord))
+#else
+ if (!finite(coord))
+#endif
+ return false;
+
+ // Skia uses 16.16 fixed point and 26.6 fixed point in various places. If
+ // the transformed point exceeds 15 bits, we just declare that it's
+ // unreasonable to catch both of these cases.
+ static const int maxPointMagnitude = 32767;
+ if (coord > maxPointMagnitude || coord < -maxPointMagnitude)
+ return false;
+
+ return true;
+#else
+ return true;
+#endif
+}
+
+static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt)
+{
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+ // Now check for points that will overflow. We check the *transformed*
+ // points since this is what will be rasterized.
+ SkPoint xPt;
+ transform.mapPoints(&xPt, &pt, 1);
+ return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY);
+#else
+ return true;
+#endif
+}
+
+static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc)
+{
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+ SkPoint topleft = {rc.fLeft, rc.fTop};
+ SkPoint bottomright = {rc.fRight, rc.fBottom};
+ return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright);
+#else
+ return true;
+#endif
+}
+
+bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path)
+{
+#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA
+ SkPoint current_points[4];
+ SkPath::Iter iter(path, false);
+ for (SkPath::Verb verb = iter.next(current_points);
+ verb != SkPath::kDone_Verb;
+ verb = iter.next(current_points)) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ // This move will be duplicated in the next verb, so we can ignore.
+ break;
+ case SkPath::kLine_Verb:
+ // iter.next returns 2 points.
+ if (!isPointSkiaSafe(transform, current_points[0])
+ || !isPointSkiaSafe(transform, current_points[1]))
+ return false;
+ break;
+ case SkPath::kQuad_Verb:
+ // iter.next returns 3 points.
+ if (!isPointSkiaSafe(transform, current_points[0])
+ || !isPointSkiaSafe(transform, current_points[1])
+ || !isPointSkiaSafe(transform, current_points[2]))
+ return false;
+ break;
+ case SkPath::kCubic_Verb:
+ // iter.next returns 4 points.
+ if (!isPointSkiaSafe(transform, current_points[0])
+ || !isPointSkiaSafe(transform, current_points[1])
+ || !isPointSkiaSafe(transform, current_points[2])
+ || !isPointSkiaSafe(transform, current_points[3]))
+ return false;
+ break;
+ case SkPath::kClose_Verb:
+ case SkPath::kDone_Verb:
+ default:
+ break;
+ }
+ }
+ return true;
+#else
+ return true;
+#endif
+}
+
+// Local helper functions ------------------------------------------------------
+
+void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle)
+{
+ SkIRect ir;
+ int rx = SkMin32(SkScalarRound(rect.width()), size.width());
+ int ry = SkMin32(SkScalarRound(rect.height()), size.height());
+
+ ir.set(-rx, -ry, rx, ry);
+ switch (startAngle) {
+ case 0:
+ ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom);
+ break;
+ case 90:
+ ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom);
+ break;
+ case 180:
+ ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop);
+ break;
+ case 270:
+ ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop);
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ SkRect r;
+ r.set(ir);
+ path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false);
+}
+
+inline int fastMod(int value, int max)
+{
+ int sign = SkExtractSign(value);
+
+ value = SkApplySign(value, sign);
+ if (value >= max)
+ value %= max;
+ return SkApplySign(value, sign);
+}
+
+inline float square(float n)
+{
+ return n * n;
+}
+
+} // namespace
+
+// -----------------------------------------------------------------------------
+
+// This may be called with a NULL pointer to create a graphics context that has
+// no painting.
+GraphicsContext::GraphicsContext(PlatformGraphicsContext* gc)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(gc))
+{
+ setPaintingDisabled(!gc || !platformContext()->canvas());
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ delete m_data;
+ this->destroyGraphicsContextPrivate(m_common);
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ ASSERT(!paintingDisabled());
+ return m_data->context();
+}
+
+// State saving ----------------------------------------------------------------
+
+void GraphicsContext::savePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ // Save our private State.
+ platformContext()->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (paintingDisabled())
+ return;
+
+ // Restore our private State.
+ platformContext()->restore();
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ // We need the "alpha" layer flag here because the base layer is opaque
+ // (the surface of the page) but layers on top may have transparent parts.
+ // Without explicitly setting the alpha flag, the layer will inherit the
+ // opaque setting of the base and some things won't work properly.
+ platformContext()->canvas()->saveLayerAlpha(
+ 0,
+ static_cast<unsigned char>(opacity * 255),
+ static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag |
+ SkCanvas::kFullColorLayer_SaveFlag));
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+#if PLATFORM(WIN_OS)
+ platformContext()->canvas()->getTopPlatformDevice().
+ fixupAlphaBeforeCompositing();
+#endif
+ platformContext()->canvas()->restore();
+}
+
+// Graphics primitives ---------------------------------------------------------
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r(rect);
+ if (!isRectSkiaSafe(getCTM(), r))
+ return;
+
+ SkPath path;
+ path.addOval(r, SkPath::kCW_Direction);
+ // only perform the inset if we won't invert r
+ if (2 * thickness < rect.width() && 2 * thickness < rect.height()) {
+ r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness));
+ path.addOval(r, SkPath::kCCW_Direction);
+ }
+ platformContext()->canvas()->clipPath(path);
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->addPath(*path.platformPath());
+}
+
+void GraphicsContext::beginPath()
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->beginPath();
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setDrawLooper(0);
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r))
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+ platformContext()->canvas()->drawRect(r, paint);
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r(rect);
+ if (!isRectSkiaSafe(getCTM(), r))
+ return;
+
+ platformContext()->canvas()->clipRect(r);
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& p = *path.platformPath();
+ if (!isPathSkiaSafe(getCTM(), p))
+ return;
+
+ platformContext()->canvas()->clipPath(p);
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r(rect);
+ if (!isRectSkiaSafe(getCTM(), r))
+ return;
+
+ platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOut(const Path& p)
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& path = *p.platformPath();
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect oval(rect);
+ if (!isRectSkiaSafe(getCTM(), oval))
+ return;
+
+ SkPath path;
+ path.addOval(oval, SkPath::kCCW_Direction);
+ platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipPath(WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath* oldPath = platformContext()->currentPath();
+ SkPath path(*oldPath);
+ path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
+ platformContext()->canvas()->clipPath(path);
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect& rect,
+ const ImageBuffer* imageBuffer)
+{
+ if (paintingDisabled())
+ return;
+
+ // FIXME: This is needed for image masking and complex text fills.
+ notImplemented();
+}
+
+void GraphicsContext::concatCTM(const TransformationMatrix& xform)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->canvas()->concat(xform);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numPoints,
+ const FloatPoint* points,
+ bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ SkPath path;
+
+ path.incReserve(numPoints);
+ path.moveTo(WebCoreFloatToSkScalar(points[0].x()),
+ WebCoreFloatToSkScalar(points[0].y()));
+ for (size_t i = 1; i < numPoints; i++) {
+ path.lineTo(WebCoreFloatToSkScalar(points[i].x()),
+ WebCoreFloatToSkScalar(points[i].y()));
+ }
+
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ SkPaint paint;
+ if (fillColor().alpha() > 0) {
+ platformContext()->setupPaintForFilling(&paint);
+ platformContext()->canvas()->drawPath(path, paint);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ platformContext()->setupPaintForStroking(&paint, 0, 0);
+ platformContext()->canvas()->drawPath(path, paint);
+ }
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& elipseRect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect rect = elipseRect;
+ if (!isRectSkiaSafe(getCTM(), rect))
+ return;
+
+ SkPaint paint;
+ if (fillColor().alpha() > 0) {
+ platformContext()->setupPaintForFilling(&paint);
+ platformContext()->canvas()->drawOval(rect, paint);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ platformContext()->setupPaintForStroking(&paint, &rect, 0);
+ platformContext()->canvas()->drawOval(rect, paint);
+ }
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+ if (0 == rectCount)
+ return;
+
+ SkRegion focusRingRegion;
+ const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.5);
+ for (unsigned i = 0; i < rectCount; i++) {
+ SkIRect r = rects[i];
+ r.inset(-focusRingOutset, -focusRingOutset);
+ focusRingRegion.op(r, SkRegion::kUnion_Op);
+ }
+
+ SkPath path;
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+
+ paint.setColor(focusRingColor().rgb());
+ paint.setStrokeWidth(focusRingOutset * 2);
+ paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref();
+ focusRingRegion.getBoundaryPath(&path);
+ platformContext()->canvas()->drawPath(path, paint);
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle penStyle = strokeStyle();
+ if (penStyle == NoStroke)
+ return;
+
+ SkPaint paint;
+ SkPoint pts[2] = { (SkPoint)point1, (SkPoint)point2 };
+ if (!isPointSkiaSafe(getCTM(), pts[0]) || !isPointSkiaSafe(getCTM(), pts[1]))
+ return;
+
+ // We know these are vertical or horizontal lines, so the length will just
+ // be the sum of the displacement component vectors give or take 1 -
+ // 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));
+
+ // "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) {
+ pts[0].fX = pts[0].fX + SK_ScalarHalf;
+ pts[1].fX = pts[0].fX;
+ } else { // Horizontal line
+ pts[0].fY = pts[0].fY + SK_ScalarHalf;
+ pts[1].fY = pts[0].fY;
+ }
+ }
+ platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt,
+ int width,
+ bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ // Create the pattern we'll use to draw the underline.
+ static SkBitmap* misspellBitmap = 0;
+ if (!misspellBitmap) {
+ // We use a 2-pixel-high misspelling indicator because that seems to be
+ // what WebKit is designed for, and how much room there is in a typical
+ // page for it.
+ const int rowPixels = 32; // Must be multiple of 4 for pattern below.
+ const int colPixels = 2;
+ misspellBitmap = new SkBitmap;
+ misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ rowPixels, colPixels);
+ misspellBitmap->allocPixels();
+
+ misspellBitmap->eraseARGB(0, 0, 0, 0);
+ const uint32_t lineColor = 0xFFFF0000; // Opaque red.
+ const uint32_t antiColor = 0x60600000; // Semitransparent red.
+
+ // Pattern: X o o X o o X
+ // o X o o X o
+ uint32_t* row1 = misspellBitmap->getAddr32(0, 0);
+ uint32_t* row2 = misspellBitmap->getAddr32(0, 1);
+ for (int x = 0; x < rowPixels; x++) {
+ switch (x % 4) {
+ case 0:
+ row1[x] = lineColor;
+ break;
+ case 1:
+ row1[x] = antiColor;
+ row2[x] = antiColor;
+ break;
+ case 2:
+ row2[x] = lineColor;
+ break;
+ case 3:
+ row1[x] = antiColor;
+ row2[x] = antiColor;
+ break;
+ }
+ }
+ }
+
+ // Offset it vertically by 1 so that there's some space under the text.
+ SkScalar originX = SkIntToScalar(pt.x());
+ SkScalar originY = SkIntToScalar(pt.y()) + 1;
+
+ // Make a shader for the bitmap with an origin of the box we'll draw. This
+ // shader is refcounted and will have an initial refcount of 1.
+ SkShader* shader = SkShader::CreateBitmapShader(
+ *misspellBitmap, SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ SkMatrix matrix;
+ matrix.reset();
+ matrix.postTranslate(originX, originY);
+ shader->setLocalMatrix(matrix);
+
+ // Assign the shader to the paint & release our reference. The paint will
+ // now own the shader and the shader will be destroyed when the paint goes
+ // out of scope.
+ SkPaint paint;
+ paint.setShader(shader);
+ shader->unref();
+
+ SkRect rect;
+ rect.set(originX,
+ originY,
+ originX + SkIntToScalar(width),
+ originY + SkIntToScalar(misspellBitmap->height()));
+ platformContext()->canvas()->drawRect(rect, paint);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& pt,
+ int width,
+ bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ int thickness = SkMax32(static_cast<int>(strokeThickness()), 1);
+ SkRect r;
+ r.fLeft = SkIntToScalar(pt.x());
+ r.fTop = SkIntToScalar(pt.y());
+ r.fRight = r.fLeft + SkIntToScalar(width);
+ r.fBottom = r.fTop + SkIntToScalar(thickness);
+
+ SkPaint paint;
+ paint.setColor(strokeColor().rgb());
+ platformContext()->canvas()->drawRect(r, paint);
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r))
+ // See the fillRect below.
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+
+ platformContext()->drawRect(r);
+}
+
+void GraphicsContext::fillPath()
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& path = *platformContext()->currentPath();
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ const GraphicsContextState& state = m_common->state;
+ ColorSpace colorSpace = state.fillColorSpace;
+
+ if (colorSpace == SolidColorSpace && !fillColor().alpha())
+ return;
+
+ platformContext()->setFillRule(state.fillRule == RULE_EVENODD ?
+ SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
+
+ 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);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r))
+ // See the other version of fillRect below.
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+
+ const GraphicsContextState& state = m_common->state;
+ ColorSpace colorSpace = state.fillColorSpace;
+
+ if (colorSpace == SolidColorSpace && !fillColor().alpha())
+ return;
+
+ 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);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!color.alpha())
+ return;
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r)) {
+ // Special case when the rectangle overflows fixed point. This is a
+ // workaround to fix bug 1212844. When the input rectangle is very
+ // large, it can overflow Skia's internal fixed point rect. This
+ // should be fixable in Skia (since the output bitmap isn't that
+ // large), but until that is fixed, we try to handle it ourselves.
+ //
+ // We manually clip the rectangle to the current clip rect. This
+ // will prevent overflow. The rectangle will be transformed to the
+ // canvas' coordinate space before it is converted to fixed point
+ // so we are guaranteed not to overflow after doing this.
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+ }
+
+ SkPaint paint;
+ platformContext()->setupPaintCommon(&paint);
+ paint.setColor(color.rgb());
+ platformContext()->canvas()->drawRect(r, paint);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect,
+ const IntSize& topLeft,
+ const IntSize& topRight,
+ const IntSize& bottomLeft,
+ const IntSize& bottomRight,
+ const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r = rect;
+ if (!isRectSkiaSafe(getCTM(), r))
+ // See fillRect().
+ ClipRectToCanvas(*platformContext()->canvas(), r, &r);
+
+ SkPath path;
+ addCornerArc(&path, r, topRight, 270);
+ addCornerArc(&path, r, bottomRight, 0);
+ addCornerArc(&path, r, bottomLeft, 90);
+ addCornerArc(&path, r, topLeft, 180);
+
+ SkPaint paint;
+ platformContext()->setupPaintForFilling(&paint);
+ platformContext()->canvas()->drawPath(path, paint);
+ return fillRect(rect, color);
+}
+
+TransformationMatrix GraphicsContext::getCTM() const
+{
+ return platformContext()->canvas()->getTotalMatrix();
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ // This logic is copied from GraphicsContextCG, eseidel 5/05/08
+
+ // It is not enough just to round to pixels in device space. The rotation
+ // part of the affine transform matrix to device space can mess with this
+ // conversion if we have a rotating image like the hands of the world clock
+ // widget. We just need the scale, so we get the affine transform matrix and
+ // extract the scale.
+
+ const SkMatrix& deviceMatrix = platformContext()->canvas()->getTotalMatrix();
+ if (deviceMatrix.isIdentity())
+ return rect;
+
+ float deviceScaleX = sqrtf(square(deviceMatrix.getScaleX())
+ + square(deviceMatrix.getSkewY()));
+ float deviceScaleY = sqrtf(square(deviceMatrix.getSkewX())
+ + square(deviceMatrix.getScaleY()));
+
+ FloatPoint deviceOrigin(rect.x() * deviceScaleX, rect.y() * deviceScaleY);
+ FloatPoint deviceLowerRight((rect.x() + rect.width()) * deviceScaleX,
+ (rect.y() + rect.height()) * deviceScaleY);
+
+ deviceOrigin.setX(roundf(deviceOrigin.x()));
+ deviceOrigin.setY(roundf(deviceOrigin.y()));
+ deviceLowerRight.setX(roundf(deviceLowerRight.x()));
+ deviceLowerRight.setY(roundf(deviceLowerRight.y()));
+
+ // Don't let the height or width round to 0 unless either was originally 0
+ if (deviceOrigin.y() == deviceLowerRight.y() && rect.height() != 0)
+ deviceLowerRight.move(0, 1);
+ if (deviceOrigin.x() == deviceLowerRight.x() && rect.width() != 0)
+ deviceLowerRight.move(1, 0);
+
+ FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX,
+ deviceOrigin.y() / deviceScaleY);
+ FloatPoint roundedLowerRight(deviceLowerRight.x() / deviceScaleX,
+ deviceLowerRight.y() / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()),
+ WebCoreFloatToSkScalar(size.height()));
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setAlpha(alpha);
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setPorterDuffMode(WebCoreCompositeToSkiaComposite(op));
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setLineCap(LineCap cap)
+{
+ if (paintingDisabled())
+ return;
+ switch (cap) {
+ case ButtCap:
+ platformContext()->setLineCap(SkPaint::kButt_Cap);
+ break;
+ case RoundCap:
+ platformContext()->setLineCap(SkPaint::kRound_Cap);
+ break;
+ case SquareCap:
+ platformContext()->setLineCap(SkPaint::kSquare_Cap);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ if (paintingDisabled())
+ return;
+
+ // FIXME: This is lifted directly off SkiaSupport, lines 49-74
+ // so it is not guaranteed to work correctly.
+ size_t dashLength = dashes.size();
+ if (!dashLength)
+ return;
+
+ size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2;
+ SkScalar* intervals = new SkScalar[count];
+
+ for (unsigned int i = 0; i < count; i++)
+ intervals[i] = dashes[i % dashLength];
+
+ platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset));
+
+ delete[] intervals;
+}
+
+void GraphicsContext::setLineJoin(LineJoin join)
+{
+ if (paintingDisabled())
+ return;
+ switch (join) {
+ case MiterJoin:
+ platformContext()->setLineJoin(SkPaint::kMiter_Join);
+ break;
+ case RoundJoin:
+ platformContext()->setLineJoin(SkPaint::kRound_Join);
+ break;
+ case BevelJoin:
+ platformContext()->setLineJoin(SkPaint::kBevel_Join);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setMiterLimit(limit);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+ platformContext()->setFillColor(color.rgb());
+}
+
+void GraphicsContext::setPlatformShadow(const IntSize& size,
+ int blurInt,
+ const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ double width = size.width();
+ double height = size.height();
+ double blur = blurInt;
+
+ // TODO(tc): This still does not address the issue that shadows
+ // within canvas elements should ignore transforms.
+ if (m_common->state.shadowsIgnoreTransforms) {
+ // Currently only the GraphicsContext associated with the
+ // CanvasRenderingContext for HTMLCanvasElement have shadows ignore
+ // Transforms. So with this flag set, we know this state is associated
+ // with a CanvasRenderingContext.
+ // CG uses natural orientation for Y axis, but the HTML5 canvas spec
+ // does not.
+ // So we now flip the height since it was flipped in
+ // CanvasRenderingContext in order to work with CG.
+ height = -height;
+ }
+
+ SkColor c;
+ if (color.isValid())
+ c = color.rgb();
+ else
+ c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" apple shadow color.
+
+ // TODO(tc): Should we have a max value for the blur? CG clamps at 1000.0
+ // for perf reasons.
+ SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c);
+ platformContext()->setDrawLooper(dl);
+ dl->unref();
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeColor(strokecolor.rgb());
+}
+
+void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& stroke)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeStyle(stroke);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setStrokeThickness(thickness);
+}
+
+void GraphicsContext::setPlatformTextDrawingMode(int mode)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setTextDrawingMode(mode);
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->setUseAntialiasing(enable);
+}
+
+void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect oval = r;
+ if (strokeStyle() == NoStroke) {
+ // Stroke using the fill color.
+ // TODO(brettw) is this really correct? It seems unreasonable.
+ platformContext()->setupPaintForFilling(&paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness()));
+ } else
+ platformContext()->setupPaintForStroking(&paint, 0, 0);
+
+ // We do this before converting to scalar, so we don't overflow SkFixed.
+ startAngle = fastMod(startAngle, 360);
+ angleSpan = fastMod(angleSpan, 360);
+
+ SkPath path;
+ path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+ platformContext()->canvas()->drawPath(path, paint);
+}
+
+void GraphicsContext::strokePath()
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& path = *platformContext()->currentPath();
+ if (!isPathSkiaSafe(getCTM(), path))
+ return;
+
+ const GraphicsContextState& state = m_common->state;
+ ColorSpace colorSpace = state.strokeColorSpace;
+
+ if (colorSpace == SolidColorSpace && !strokeColor().alpha())
+ return;
+
+ 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);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ if (!isRectSkiaSafe(getCTM(), rect))
+ return;
+
+ const GraphicsContextState& state = m_common->state;
+ ColorSpace colorSpace = state.strokeColorSpace;
+
+ if (colorSpace == SolidColorSpace && !strokeColor().alpha())
+ return;
+
+ SkPaint paint;
+ 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);
+}
+
+void GraphicsContext::rotate(float angleInRadians)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->canvas()->rotate(WebCoreFloatToSkScalar(
+ angleInRadians * (180.0f / 3.14159265f)));
+}
+
+void GraphicsContext::translate(float w, float h)
+{
+ if (paintingDisabled())
+ return;
+
+ platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w),
+ WebCoreFloatToSkScalar(h));
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
new file mode 100644
index 0000000..fdfcb85
--- /dev/null
+++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "BitmapImage.h"
+#include "BitmapImageSingleFrameSkia.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+#include "SkiaUtils.h"
+
+using namespace std;
+
+namespace WebCore {
+
+// We pass a technically-uninitialized canvas to the platform context here since
+// the canvas initialization completes in ImageBuffer::ImageBuffer. But
+// PlatformContext doesn't actually need to use the object, and this makes all
+// the ownership easier to manage.
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_platformContext(0) // Canvas is set in ImageBuffer constructor.
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ if (!m_data.m_canvas.initialize(size.width(), size.height(), false)) {
+ success = false;
+ return;
+ }
+
+ m_data.m_platformContext.setCanvas(&m_data.m_canvas);
+ m_context.set(new GraphicsContext(&m_data.m_platformContext));
+
+ // 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);
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+Image* ImageBuffer::image() const
+{
+ if (!m_image) {
+ // 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."
+ m_image = BitmapImageSingleFrameSkia::create(
+ *m_data.m_platformContext.bitmap());
+ }
+ return m_image.get();
+}
+
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
+{
+ ASSERT(context());
+
+ RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
+ unsigned char* data = result->data()->data();
+
+ if (rect.x() < 0 || rect.y() < 0 ||
+ (rect.x() + rect.width()) > m_size.width() ||
+ (rect.y() + rect.height()) > m_size.height())
+ memset(data, 0, result->data()->length());
+
+ int originX = rect.x();
+ int destX = 0;
+ if (originX < 0) {
+ destX = -originX;
+ originX = 0;
+ }
+ int endX = rect.x() + rect.width();
+ if (endX > m_size.width())
+ endX = m_size.width();
+ int numColumns = endX - originX;
+
+ int originY = rect.y();
+ int destY = 0;
+ if (originY < 0) {
+ destY = -originY;
+ originY = 0;
+ }
+ int endY = rect.y() + rect.height();
+ if (endY > m_size.height())
+ endY = m_size.height();
+ int numRows = endY - originY;
+
+ const SkBitmap& bitmap = *context()->platformContext()->bitmap();
+ ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ SkAutoLockPixels bitmapLock(bitmap);
+
+ unsigned destBytesPerRow = 4 * rect.width();
+ unsigned char* destRow = data + destY * destBytesPerRow + destX * 4;
+
+ for (int y = 0; y < numRows; ++y) {
+ uint32_t* srcRow = bitmap.getAddr32(originX, originY + y);
+ for (int x = 0; x < numColumns; ++x) {
+ SkColor color = SkPMColorToColor(srcRow[x]);
+ unsigned char* destPixel = &destRow[x * 4];
+ destPixel[0] = SkColorGetR(color);
+ destPixel[1] = SkColorGetG(color);
+ destPixel[2] = SkColorGetB(color);
+ destPixel[3] = SkColorGetA(color);
+ }
+ destRow += destBytesPerRow;
+ }
+
+ return result;
+}
+
+void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect,
+ const IntPoint& destPoint)
+{
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originX = sourceRect.x();
+ int destX = destPoint.x() + sourceRect.x();
+ ASSERT(destX >= 0);
+ ASSERT(destX < m_size.width());
+ ASSERT(originX >= 0);
+ ASSERT(originX < sourceRect.right());
+
+ int endX = destPoint.x() + sourceRect.right();
+ ASSERT(endX <= m_size.width());
+
+ int numColumns = endX - destX;
+
+ int originY = sourceRect.y();
+ int destY = destPoint.y() + sourceRect.y();
+ ASSERT(destY >= 0);
+ ASSERT(destY < m_size.height());
+ ASSERT(originY >= 0);
+ ASSERT(originY < sourceRect.bottom());
+
+ int endY = destPoint.y() + sourceRect.bottom();
+ ASSERT(endY <= m_size.height());
+ int numRows = endY - destY;
+
+ const SkBitmap& bitmap = *context()->platformContext()->bitmap();
+ ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ SkAutoLockPixels bitmapLock(bitmap);
+
+ unsigned srcBytesPerRow = 4 * source->width();
+
+ const unsigned char* srcRow = source->data()->data() + originY * srcBytesPerRow + originX * 4;
+
+ for (int y = 0; y < numRows; ++y) {
+ uint32_t* destRow = bitmap.getAddr32(destX, destY + y);
+ for (int x = 0; x < numColumns; ++x) {
+ const unsigned char* srcPixel = &srcRow[x * 4];
+ destRow[x] = SkPreMultiplyARGB(srcPixel[3], srcPixel[0],
+ srcPixel[1], srcPixel[2]);
+ }
+ srcRow += srcBytesPerRow;
+ }
+}
+
+String ImageBuffer::toDataURL(const String&) const
+{
+ notImplemented();
+ return String();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp
new file mode 100644
index 0000000..1123fe9
--- /dev/null
+++ b/WebCore/platform/graphics/skia/ImageSkia.cpp
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "BitmapImage.h"
+#include "BitmapImageSingleFrameSkia.h"
+#include "ChromiumBridge.h"
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Logging.h"
+#include "NativeImageSkia.h"
+#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+#include "PlatformString.h"
+#include "SkiaUtils.h"
+#include "SkShader.h"
+#include "TransformationMatrix.h"
+
+#include "skia/ext/image_operations.h"
+#include "skia/ext/platform_canvas.h"
+
+namespace WebCore {
+
+// Used by computeResamplingMode to tell how bitmaps should be resampled.
+enum ResamplingMode {
+ // Nearest neighbor resampling. Used when we detect that the page is
+ // trying to make a pattern by stretching a small bitmap very large.
+ RESAMPLE_NONE,
+
+ // Default skia resampling. Used for large growing of images where high
+ // quality resampling doesn't get us very much except a slowdown.
+ RESAMPLE_LINEAR,
+
+ // High quality resampling.
+ RESAMPLE_AWESOME,
+};
+
+static ResamplingMode computeResamplingMode(const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight)
+{
+ int destIWidth = static_cast<int>(destWidth);
+ int destIHeight = static_cast<int>(destHeight);
+
+ // The percent change below which we will not resample. This usually means
+ // an off-by-one error on the web page, and just doing nearest neighbor
+ // sampling is usually good enough.
+ const float kFractionalChangeThreshold = 0.025f;
+
+ // Images smaller than this in either direction are considered "small" and
+ // are not resampled ever (see below).
+ const int kSmallImageSizeThreshold = 8;
+
+ // The amount an image can be stretched in a single direction before we
+ // say that it is being stretched so much that it must be a line or
+ // background that doesn't need resampling.
+ const float kLargeStretch = 3.0f;
+
+ // Figure out if we should resample this image. We try to prune out some
+ // common cases where resampling won't give us anything, since it is much
+ // slower than drawing stretched.
+ if (srcWidth == destIWidth && srcHeight == destIHeight) {
+ // We don't need to resample if the source and destination are the same.
+ return RESAMPLE_NONE;
+ }
+
+ if (srcWidth <= kSmallImageSizeThreshold
+ || srcHeight <= kSmallImageSizeThreshold
+ || destWidth <= kSmallImageSizeThreshold
+ || destHeight <= kSmallImageSizeThreshold) {
+ // Never resample small images. These are often used for borders and
+ // rules (think 1x1 images used to make lines).
+ return RESAMPLE_NONE;
+ }
+
+ if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
+ // Large image detected.
+
+ // Don't resample if it is being stretched a lot in only one direction.
+ // This is trying to catch cases where somebody has created a border
+ // (which might be large) and then is stretching it to fill some part
+ // of the page.
+ if (srcWidth == destWidth || srcHeight == destHeight)
+ return RESAMPLE_NONE;
+
+ // The image is growing a lot and in more than one direction. Resampling
+ // is slow and doesn't give us very much when growing a lot.
+ return RESAMPLE_LINEAR;
+ }
+
+ if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold)
+ && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) {
+ // It is disappointingly common on the web for image sizes to be off by
+ // one or two pixels. We don't bother resampling if the size difference
+ // is a small fraction of the original size.
+ return RESAMPLE_NONE;
+ }
+
+ // When the image is not yet done loading, use linear. We don't cache the
+ // partially resampled images, and as they come in incrementally, it causes
+ // us to have to resample the whole thing every time.
+ if (!bitmap.isDataComplete())
+ return RESAMPLE_LINEAR;
+
+ // Everything else gets resampled.
+ return RESAMPLE_AWESOME;
+}
+
+// Draws the given bitmap to the given canvas. The subset of the source bitmap
+// identified by src_rect is drawn to the given destination rect. The bitmap
+// will be resampled to resample_width * resample_height (this is the size of
+// the whole image, not the subset). See shouldResampleBitmap for more.
+//
+// This does a lot of computation to resample only the portion of the bitmap
+// that will only be drawn. This is critical for performance since when we are
+// scrolling, for example, we are only drawing a small strip of the image.
+// Resampling the whole image every time is very slow, so this speeds up things
+// dramatically.
+static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
+{
+ // First get the subset we need. This is efficient and does not copy pixels.
+ SkBitmap subset;
+ bitmap.extractSubset(&subset, srcIRect);
+ SkRect srcRect;
+ srcRect.set(srcIRect);
+
+ // Whether we're doing a subset or using the full source image.
+ bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0
+ && srcIRect.width() == bitmap.width()
+ && srcIRect.height() == bitmap.height();
+
+ // We will always draw in integer sizes, so round the destination rect.
+ SkIRect destRectRounded;
+ destRect.round(&destRectRounded);
+ SkIRect resizedImageRect; // Represents the size of the resized image.
+ resizedImageRect.set(0, 0, destRectRounded.width(), destRectRounded.height());
+
+ if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) {
+ // Yay, this bitmap frame already has a resized version.
+ SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), destRectRounded.height());
+ canvas.drawBitmapRect(resampled, 0, destRect, &paint);
+ return;
+ }
+
+ // Compute the visible portion of our rect.
+ SkRect destBitmapSubsetSk;
+ ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
+ destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);
+
+ // The matrix inverting, etc. could have introduced rounding error which
+ // causes the bounds to be outside of the resized bitmap. We round outward
+ // so we always lean toward it being larger rather than smaller than we
+ // need, and then clamp to the bitmap bounds so we don't get any invalid
+ // data.
+ SkIRect destBitmapSubsetSkI;
+ destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
+ if (!destBitmapSubsetSkI.intersect(resizedImageRect))
+ return; // Resized image does not intersect.
+
+ if (srcIsFull && bitmap.shouldCacheResampling(
+ resizedImageRect.width(),
+ resizedImageRect.height(),
+ destBitmapSubsetSkI.width(),
+ destBitmapSubsetSkI.height())) {
+ // We're supposed to resize the entire image and cache it, even though
+ // we don't need all of it.
+ SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
+ destRectRounded.height());
+ canvas.drawBitmapRect(resampled, 0, destRect, &paint);
+ } else {
+ // We should only resize the exposed part of the bitmap to do the
+ // minimal possible work.
+ gfx::Rect destBitmapSubset(destBitmapSubsetSkI.fLeft,
+ destBitmapSubsetSkI.fTop,
+ destBitmapSubsetSkI.width(),
+ destBitmapSubsetSkI.height());
+
+ // Resample the needed part of the image.
+ SkBitmap resampled = skia::ImageOperations::Resize(subset,
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ destRectRounded.width(), destRectRounded.height(),
+ destBitmapSubset);
+
+ // Compute where the new bitmap should be drawn. Since our new bitmap
+ // may be smaller than the original, we have to shift it over by the
+ // same amount that we cut off the top and left.
+ SkRect offsetDestRect = {
+ destBitmapSubset.x() + destRect.fLeft,
+ destBitmapSubset.y() + destRect.fTop,
+ destBitmapSubset.right() + destRect.fLeft,
+ destBitmapSubset.bottom() + destRect.fTop };
+
+ canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
+ }
+}
+
+static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkPorterDuff::Mode& compOp)
+{
+ SkPaint paint;
+ paint.setPorterDuffXfermode(compOp);
+
+ skia::PlatformCanvas* canvas = platformContext->canvas();
+
+ ResamplingMode resampling = platformContext->isPrinting() ? RESAMPLE_NONE :
+ computeResamplingMode(bitmap, srcRect.width(), srcRect.height(),
+ SkScalarToFloat(destRect.width()),
+ SkScalarToFloat(destRect.height()));
+ if (resampling == RESAMPLE_AWESOME) {
+ paint.setFilterBitmap(false);
+ drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
+ } else {
+ // No resampling necessary, we can just draw the bitmap. We want to
+ // filter it if we decided to do linear interpolation above, or if there
+ // is something interesting going on with the matrix (like a rotation).
+ // Note: for serialization, we will want to subset the bitmap first so
+ // we don't send extra pixels.
+ paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
+ canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
+ }
+}
+
+// Transforms the given dimensions with the given matrix. Used to see how big
+// images will be once transformed.
+static void TransformDimensions(const SkMatrix& matrix, float srcWidth, float srcHeight, float* destWidth, float* destHeight) {
+ // Transform 3 points to see how long each side of the bitmap will be.
+ SkPoint src_points[3]; // (0, 0), (width, 0), (0, height).
+ src_points[0].set(0, 0);
+ src_points[1].set(SkFloatToScalar(srcWidth), 0);
+ src_points[2].set(0, SkFloatToScalar(srcHeight));
+
+ // Now measure the length of the two transformed vectors relative to the
+ // transformed origin to see how big the bitmap will be. Note: for skews,
+ // this isn't the best thing, but we don't have skews.
+ SkPoint dest_points[3];
+ matrix.mapPoints(dest_points, src_points, 3);
+ *destWidth = SkScalarToFloat((dest_points[1] - dest_points[0]).length());
+ *destHeight = SkScalarToFloat((dest_points[2] - dest_points[0]).length());
+}
+
+// A helper method for translating negative width and height values.
+static FloatRect normalizeRect(const FloatRect& rect)
+{
+ FloatRect norm = rect;
+ if (norm.width() < 0) {
+ norm.setX(norm.x() + norm.width());
+ norm.setWidth(-norm.width());
+ }
+ if (norm.height() < 0) {
+ norm.setY(norm.y() + norm.height());
+ norm.setHeight(-norm.height());
+ }
+ return norm;
+}
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ // ImageSource::createFrameAtIndex() allocated |m_frame| and passed
+ // ownership to BitmapImage; we must delete it here.
+ delete m_frame;
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ return ChromiumBridge::loadPlatformImageResource(name);
+}
+
+void Image::drawPattern(GraphicsContext* context,
+ const FloatRect& floatSrcRect,
+ const TransformationMatrix& patternTransform,
+ const FloatPoint& phase,
+ CompositeOperator compositeOp,
+ const FloatRect& destRect)
+{
+ if (destRect.isEmpty() || floatSrcRect.isEmpty())
+ return; // nothing to draw
+
+ NativeImageSkia* bitmap = nativeImageForCurrentFrame();
+ if (!bitmap)
+ return;
+
+ // This is a very inexpensive operation. It will generate a new bitmap but
+ // it will internally reference the old bitmap's pixels, adjusting the row
+ // stride so the extra pixels appear as padding to the subsetted bitmap.
+ SkBitmap srcSubset;
+ SkIRect srcRect = enclosingIntRect(floatSrcRect);
+ bitmap->extractSubset(&srcSubset, srcRect);
+
+ SkBitmap resampled;
+ SkShader* shader;
+
+ // Figure out what size the bitmap will be in the destination. The
+ // destination rect is the bounds of the pattern, we need to use the
+ // matrix to see how bit it will be.
+ float destBitmapWidth, destBitmapHeight;
+ TransformDimensions(patternTransform, srcRect.width(), srcRect.height(),
+ &destBitmapWidth, &destBitmapHeight);
+
+ // Compute the resampling mode.
+ ResamplingMode resampling;
+ if (context->platformContext()->isPrinting())
+ resampling = RESAMPLE_LINEAR;
+ else {
+ resampling = computeResamplingMode(*bitmap,
+ srcRect.width(), srcRect.height(),
+ destBitmapWidth, destBitmapHeight);
+ }
+
+ // Load the transform WebKit requested.
+ SkMatrix matrix(patternTransform);
+
+ if (resampling == RESAMPLE_AWESOME) {
+ // Do nice resampling.
+ SkBitmap resampled = skia::ImageOperations::Resize(srcSubset,
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ static_cast<int>(destBitmapWidth),
+ static_cast<int>(destBitmapHeight));
+ shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+
+ // Since we just resized the bitmap, we need to undo the scale set in
+ // the image transform.
+ matrix.setScaleX(SkIntToScalar(1));
+ matrix.setScaleY(SkIntToScalar(1));
+ } else {
+ // No need to do nice resampling.
+ shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+ }
+
+ // We also need to translate it such that the origin of the pattern is the
+ // origin of the destination rect, which is what WebKit expects. Skia uses
+ // the coordinate system origin as the base for the patter. If WebKit wants
+ // a shifted image, it will shift it from there using the patternTransform.
+ float adjustedX = phase.x() + floatSrcRect.x() *
+ narrowPrecisionToFloat(patternTransform.a());
+ float adjustedY = phase.y() + floatSrcRect.y() *
+ narrowPrecisionToFloat(patternTransform.d());
+ matrix.postTranslate(SkFloatToScalar(adjustedX),
+ SkFloatToScalar(adjustedY));
+ shader->setLocalMatrix(matrix);
+
+ SkPaint paint;
+ paint.setShader(shader)->unref();
+ paint.setPorterDuffXfermode(WebCoreCompositeToSkiaComposite(compositeOp));
+ paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
+
+ context->platformContext()->paintSkPaint(destRect, paint);
+}
+
+// ================================================
+// BitmapImage Class
+// ================================================
+
+// FIXME: These should go to BitmapImageSkia.cpp
+
+void BitmapImage::initPlatformData()
+{
+ // This is not used. On Mac, the "platform" data is a cache of some OS
+ // specific versions of the image that are created is some cases. These
+ // aren't normally used, it is equivalent to getHBITMAP on Windows, and
+ // the platform data is the cache.
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+ // See initPlatformData above.
+}
+
+void BitmapImage::checkForSolidColor()
+{
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
+ const FloatRect& srcRect, CompositeOperator compositeOp)
+{
+ if (!m_source.initialized())
+ return;
+
+ // Spin the animation to the correct frame before we try to draw it, so we
+ // don't draw an old frame and then immediately need to draw a newer one,
+ // causing flicker and wasting CPU.
+ startAnimation();
+
+ const NativeImageSkia* bm = nativeImageForCurrentFrame();
+ if (!bm)
+ return; // It's too early and we don't have an image yet.
+
+ FloatRect normDstRect = normalizeRect(dstRect);
+ FloatRect normSrcRect = normalizeRect(srcRect);
+
+ if (normSrcRect.isEmpty() || normDstRect.isEmpty())
+ return; // Nothing to draw.
+
+ paintSkBitmap(ctxt->platformContext(),
+ *bm,
+ enclosingIntRect(normSrcRect),
+ enclosingIntRect(normDstRect),
+ WebCoreCompositeToSkiaComposite(compositeOp));
+}
+
+// FIXME: These should go into BitmapImageSingleFrameSkia.cpp
+
+void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
+ const FloatRect& dstRect,
+ const FloatRect& srcRect,
+ CompositeOperator compositeOp)
+{
+ FloatRect normDstRect = normalizeRect(dstRect);
+ FloatRect normSrcRect = normalizeRect(srcRect);
+
+ if (normSrcRect.isEmpty() || normDstRect.isEmpty())
+ return; // Nothing to draw.
+
+ paintSkBitmap(ctxt->platformContext(),
+ m_nativeImage,
+ enclosingIntRect(normSrcRect),
+ enclosingIntRect(normDstRect),
+ WebCoreCompositeToSkiaComposite(compositeOp));
+}
+
+PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap)
+{
+ RefPtr<BitmapImageSingleFrameSkia> image(adoptRef(new BitmapImageSingleFrameSkia()));
+ if (!bitmap.copyTo(&image->m_nativeImage, bitmap.config()))
+ return 0;
+ return image.release();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
new file mode 100644
index 0000000..f77620b
--- /dev/null
+++ b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+#include "ImageSourceSkia.h"
+#include "SharedBuffer.h"
+
+#include "GIFImageDecoder.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)
+{
+ // We need at least 4 bytes to figure out what kind of image we're dealing with.
+ int length = data.size();
+ if (length < 4)
+ return 0;
+
+ const unsigned char* uContents = (const unsigned char*)data.data();
+ const char* contents = data.data();
+
+ // GIFs begin with GIF8(7 or 9).
+ if (strncmp(contents, "GIF8", 4) == 0)
+ return new GIFImageDecoder();
+
+ // Test for PNG.
+ if (uContents[0]==0x89 &&
+ uContents[1]==0x50 &&
+ uContents[2]==0x4E &&
+ uContents[3]==0x47)
+ return new PNGImageDecoder();
+
+ // JPEG
+ if (uContents[0]==0xFF &&
+ uContents[1]==0xD8 &&
+ uContents[2]==0xFF)
+ return new JPEGImageDecoder();
+
+ // BMP
+ if (strncmp(contents, "BM", 2) == 0)
+ return new BMPImageDecoder();
+
+ // ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
+ // 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);
+
+ // XBMs require 8 bytes of info.
+ if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
+ return new XBMImageDecoder();
+
+ // Give up. We don't know what the heck this is.
+ return 0;
+}
+
+ImageSource::ImageSource()
+ : m_decoder(0)
+{}
+
+ImageSource::~ImageSource()
+{
+ clear(true);
+}
+
+void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
+{
+ // TODO(darin): Figure out what to do with the |data| and |allDataReceived| params.
+
+ if (destroyAll) {
+ delete m_decoder;
+ m_decoder = 0;
+ return;
+ }
+
+ if (m_decoder)
+ m_decoder->clearFrameBufferCache(clearBeforeFrame);
+}
+
+bool ImageSource::initialized() const
+{
+ return m_decoder;
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ // Make the decoder by sniffing the bytes.
+ // 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)
+ m_decoder = createDecoder(data->buffer(), IntSize());
+
+ // 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
+ // has failed.
+ if (!m_decoder || m_decoder->failed())
+ return;
+ m_decoder->setData(data, allDataReceived);
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ if (!m_decoder)
+ return false;
+
+ return m_decoder->isSizeAvailable();
+}
+
+IntSize ImageSource::size() const
+{
+ if (!m_decoder)
+ return IntSize();
+
+ return m_decoder->size();
+}
+
+IntSize ImageSource::frameSizeAtIndex(size_t) const
+{
+ // TODO(brettw) do we need anything here?
+ return size();
+}
+
+int ImageSource::repetitionCount()
+{
+ if (!m_decoder)
+ return cAnimationNone;
+
+ return m_decoder->repetitionCount();
+}
+
+size_t ImageSource::frameCount() const
+{
+ if (!m_decoder)
+ return 0;
+ return m_decoder->failed() ? 0 : m_decoder->frameCount();
+}
+
+NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return 0;
+
+ // Note that the buffer can have NULL bytes even when it is marked as
+ // non-empty. It seems "FrameEmpty" is only set before the frame has been
+ // initialized. If it is decoded and it happens to be empty, it will be
+ // marked as "FrameComplete" but will still have NULL bytes.
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ 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());
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return false;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ return buffer && buffer->status() == RGBA32Buffer::FrameComplete;
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return 0;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ 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
+ // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for
+ // more.
+ const float duration = buffer->duration() / 1000.0f;
+ return (duration < 0.051f) ? 0.100f : duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ if (!m_decoder || !m_decoder->supportsAlpha())
+ return false;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return false;
+
+ 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/ImageSourceSkia.h b/WebCore/platform/graphics/skia/ImageSourceSkia.h
new file mode 100644
index 0000000..9cb4a95
--- /dev/null
+++ b/WebCore/platform/graphics/skia/ImageSourceSkia.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ImageSource.h"
+
+namespace WebCore {
+
+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);
+};
+
+}
diff --git a/WebCore/platform/graphics/skia/IntPointSkia.cpp b/WebCore/platform/graphics/skia/IntPointSkia.cpp
new file mode 100644
index 0000000..fd9a6fd
--- /dev/null
+++ b/WebCore/platform/graphics/skia/IntPointSkia.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include "SkPoint.h"
+
+namespace WebCore {
+
+IntPoint::IntPoint(const SkIPoint& p)
+ : m_x(p.fX)
+ , m_y(p.fY)
+{
+}
+
+IntPoint::operator SkIPoint() const
+{
+ SkIPoint p = { m_x, m_y };
+ return p;
+}
+
+IntPoint::operator SkPoint() const
+{
+ SkPoint p = { SkIntToScalar(m_x), SkIntToScalar(m_y) };
+ return p;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/IntRectSkia.cpp b/WebCore/platform/graphics/skia/IntRectSkia.cpp
new file mode 100644
index 0000000..ea138ee
--- /dev/null
+++ b/WebCore/platform/graphics/skia/IntRectSkia.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include "SkRect.h"
+
+namespace WebCore {
+
+IntRect::operator SkIRect() const
+{
+ SkIRect rect = { x(), y(), right(), bottom() };
+ return rect;
+}
+
+IntRect::operator SkRect() const
+{
+ SkRect rect;
+ rect.set(SkIntToScalar(x()), SkIntToScalar(y()), SkIntToScalar(right()), SkIntToScalar(bottom()));
+ return rect;
+}
+
+IntRect::IntRect(const SkIRect& r)
+ : m_location(r.fLeft, r.fTop)
+ , m_size(r.width(), r.height())
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.cpp b/WebCore/platform/graphics/skia/NativeImageSkia.cpp
new file mode 100644
index 0000000..e59d1e2
--- /dev/null
+++ b/WebCore/platform/graphics/skia/NativeImageSkia.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "skia/ext/image_operations.h"
+
+#include "NativeImageSkia.h"
+#include "SkiaUtils.h"
+
+NativeImageSkia::NativeImageSkia()
+ : m_isDataComplete(false),
+ m_lastRequestSize(0, 0),
+ m_resizeRequests(0)
+{
+}
+
+int NativeImageSkia::decodedSize() const
+{
+ return getSize() + m_resizedImage.getSize();
+}
+
+bool NativeImageSkia::hasResizedBitmap(int w, int h) const
+{
+ if (m_lastRequestSize.width() == w && m_lastRequestSize.height() == h)
+ m_resizeRequests++;
+ else {
+ m_lastRequestSize = WebCore::IntSize(w, h);
+ m_resizeRequests = 0;
+ }
+
+ return m_resizedImage.width() == w && m_resizedImage.height() == h;
+}
+
+// FIXME: don't cache when image is in-progress.
+
+SkBitmap NativeImageSkia::resizedBitmap(int w, int h) const
+{
+ if (m_resizedImage.width() != w || m_resizedImage.height() != h)
+ m_resizedImage = skia::ImageOperations::Resize(*this, skia::ImageOperations::RESIZE_LANCZOS3, w, h);
+
+ return m_resizedImage;
+}
+
+bool NativeImageSkia::shouldCacheResampling(int destWidth,
+ int destHeight,
+ int destSubsetWidth,
+ int destSubsetHeight) const
+{
+ // We can not cache incomplete frames. This might be a good optimization in
+ // the future, were we know how much of the frame has been decoded, so when
+ // we incrementally draw more of the image, we only have to resample the
+ // parts that are changed.
+ if (!m_isDataComplete)
+ return false;
+
+ // If the destination bitmap is small, we'll always allow caching, since
+ // there is not very much penalty for computing it and it may come in handy.
+ static const int kSmallBitmapSize = 4096;
+ if (destWidth * destHeight <= kSmallBitmapSize)
+ return true;
+
+ // If "too many" requests have been made for this bitmap, we assume that
+ // many more will be made as well, and we'll go ahead and cache it.
+ static const int kManyRequestThreshold = 4;
+ if (m_lastRequestSize.width() == destWidth &&
+ m_lastRequestSize.height() == destHeight) {
+ if (m_resizeRequests >= kManyRequestThreshold)
+ return true;
+ } else {
+ // When a different size is being requested, count this as a query
+ // (hasResizedBitmap) and reset the counter.
+ m_lastRequestSize = WebCore::IntSize(destWidth, destHeight);
+ m_resizeRequests = 0;
+ }
+
+ // Otherwise, use the heuristic that if more than 1/4 of the image is
+ // requested, it's worth caching.
+ int destSize = destWidth * destHeight;
+ int destSubsetSize = destSubsetWidth * destSubsetHeight;
+ return destSize / 4 < destSubsetSize;
+}
diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.h b/WebCore/platform/graphics/skia/NativeImageSkia.h
new file mode 100644
index 0000000..5947238
--- /dev/null
+++ b/WebCore/platform/graphics/skia/NativeImageSkia.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NativeImageSkia_h
+#define NativeImageSkia_h
+
+#include "SkBitmap.h"
+#include "IntSize.h"
+
+// This object is used as the "native image" in our port. When WebKit uses
+// "NativeImagePtr", it is a pointer to this type. It is an SkBitmap, but also
+// stores a cached resized image.
+class NativeImageSkia : public SkBitmap {
+public:
+ NativeImageSkia();
+
+ // Returns the number of bytes of image data. This includes the cached
+ // resized version if there is one.
+ int decodedSize() const;
+
+ // Sets the data complete flag. This is called by the image decoder when
+ // all data is complete, and used by us to know whether we can cache
+ // resized images.
+ void setDataComplete() { m_isDataComplete = true; }
+
+ // Returns true if the entire image has been decoded.
+ bool isDataComplete() const { return m_isDataComplete; }
+
+ // We can keep a resized version of the bitmap cached on this object.
+ // This function will return true if there is a cached version of the
+ // given image subset with the given dimensions.
+ bool hasResizedBitmap(int width, int height) const;
+
+ // This will return an existing resized image, or generate a new one of
+ // the specified size and store it in the cache. Subsetted images can not
+ // be cached unless the subset is the entire bitmap.
+ SkBitmap resizedBitmap(int width, int height) const;
+
+ // Returns true if the given resize operation should either resize the whole
+ // image and cache it, or resize just the part it needs and throw the result
+ // away.
+ //
+ // On the one hand, if only a small subset is desired, then we will waste a
+ // lot of time resampling the entire thing, so we only want to do exactly
+ // what's required. On the other hand, resampling the entire bitmap is
+ // better if we're going to be using it more than once (like a bitmap
+ // scrolling on and off the screen. Since we only cache when doing the
+ // entire thing, it's best to just do it up front.
+ bool shouldCacheResampling(int destWidth,
+ int destHeight,
+ int destSubsetWidth,
+ int destSubsetHeight) const;
+
+private:
+ // Set to true when the data is complete. Before the entire image has
+ // loaded, we do not want to cache a resize.
+ bool m_isDataComplete;
+
+ // The cached bitmap. This will be empty() if there is no cached image.
+ mutable SkBitmap m_resizedImage;
+
+ // References how many times that the image size has been requested for
+ // the last size.
+ //
+ // Every time we get a request, if it matches the m_lastRequestSize, we'll
+ // increment the counter, and if not, we'll reset the counter and save the
+ // size.
+ //
+ // This allows us to see if many requests have been made for the same
+ // resized image, we know that we should probably cache it, even if all of
+ // those requests individually are small and would not otherwise be cached.
+ mutable WebCore::IntSize m_lastRequestSize;
+ mutable int m_resizeRequests;
+};
+
+#endif // NativeImageSkia_h
+
diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp
new file mode 100644
index 0000000..ca99322
--- /dev/null
+++ b/WebCore/platform/graphics/skia/PathSkia.cpp
@@ -0,0 +1,316 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "Path.h"
+
+#include "FloatRect.h"
+#include "ImageBuffer.h"
+#include "StrokeStyleApplier.h"
+
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkiaUtils.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+Path::Path()
+{
+ m_path = new SkPath;
+}
+
+Path::Path(const Path& other)
+{
+ m_path = new SkPath(*other.m_path);
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path& Path::operator=(const Path& other)
+{
+ *m_path = *other.m_path;
+ return *this;
+}
+
+bool Path::isEmpty() const
+{
+ return m_path->isEmpty();
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ return SkPathContainsPoint(m_path, point,
+ rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
+}
+
+void Path::translate(const FloatSize& size)
+{
+ m_path->offset(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height()));
+}
+
+FloatRect Path::boundingRect() const
+{
+ SkRect rect;
+ m_path->computeBounds(&rect, SkPath::kExact_BoundsType);
+ return rect;
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path->moveTo(point);
+}
+
+void Path::addLineTo(const FloatPoint& point)
+{
+ m_path->lineTo(point);
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
+{
+ m_path->quadTo(cp, ep);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep)
+{
+ m_path->cubicTo(p1, p2, ep);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ m_path->arcTo(p1, p2, WebCoreFloatToSkScalar(radius));
+}
+
+void Path::closeSubpath()
+{
+ m_path->close();
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise) {
+ SkScalar cx = WebCoreFloatToSkScalar(p.x());
+ SkScalar cy = WebCoreFloatToSkScalar(p.y());
+ SkScalar radius = WebCoreFloatToSkScalar(r);
+
+ SkRect oval;
+ oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
+
+ float sweep = ea - sa;
+ // check for a circle
+ if (sweep >= 2 * piFloat || sweep <= -2 * piFloat)
+ m_path->addOval(oval);
+ else {
+ SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat);
+ SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat);
+
+ // Counterclockwise arcs should be drawn with negative sweeps, while
+ // clockwise arcs should be drawn with positive sweeps. Check to see
+ // if the situation is reversed and correct it by adding or subtracting
+ // a full circle
+ if (anticlockwise && sweepDegrees > 0) {
+ sweepDegrees -= SkIntToScalar(360);
+ } else if (!anticlockwise && sweepDegrees < 0) {
+ sweepDegrees += SkIntToScalar(360);
+ }
+
+ m_path->arcTo(oval, startDegrees, sweepDegrees, false);
+ }
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ m_path->addRect(rect);
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ m_path->addOval(rect);
+}
+
+void Path::clear()
+{
+ m_path->reset();
+}
+
+static FloatPoint* convertPathPoints(FloatPoint dst[], const SkPoint src[], int count)
+{
+ for (int i = 0; i < count; i++) {
+ dst[i].setX(SkScalarToFloat(src[i].fX));
+ dst[i].setY(SkScalarToFloat(src[i].fY));
+ }
+ return dst;
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ SkPath::Iter iter(*m_path, false);
+ SkPoint pts[4];
+ PathElement pathElement;
+ FloatPoint pathPoints[3];
+
+ for (;;) {
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ pathElement.type = PathElementMoveToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[0], 1);
+ break;
+ case SkPath::kLine_Verb:
+ pathElement.type = PathElementAddLineToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ pathElement.type = PathElementAddQuadCurveToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[1], 2);
+ break;
+ case SkPath::kCubic_Verb:
+ pathElement.type = PathElementAddCurveToPoint;
+ pathElement.points = convertPathPoints(pathPoints, &pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ pathElement.type = PathElementCloseSubpath;
+ pathElement.points = convertPathPoints(pathPoints, 0, 0);
+ break;
+ case SkPath::kDone_Verb:
+ return;
+ }
+ function(info, &pathElement);
+ }
+}
+
+void Path::transform(const TransformationMatrix& xform)
+{
+ m_path->transform(xform);
+}
+
+String Path::debugString() const
+{
+ String result;
+
+ SkPath::Iter iter(*m_path, false);
+ SkPoint pts[4];
+
+ int numPoints = m_path->getPoints(0, 0);
+ SkPath::Verb verb;
+
+ do {
+ verb = iter.next(pts);
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY);
+ numPoints -= 1;
+ break;
+ case SkPath::kLine_Verb:
+ if (!iter.isCloseLine()) {
+ result += String::format("L%.2f,%.2f ", pts[1].fX, pts[1].fY);
+ numPoints -= 1;
+ }
+ break;
+ case SkPath::kQuad_Verb:
+ result += String::format("Q%.2f,%.2f,%.2f,%.2f ",
+ pts[1].fX, pts[1].fY,
+ pts[2].fX, pts[2].fY);
+ numPoints -= 2;
+ break;
+ case SkPath::kCubic_Verb:
+ result += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ",
+ pts[1].fX, pts[1].fY,
+ pts[2].fX, pts[2].fY,
+ pts[3].fX, pts[3].fY);
+ numPoints -= 3;
+ break;
+ case SkPath::kClose_Verb:
+ result += "Z ";
+ break;
+ case SkPath::kDone_Verb:
+ break;
+ }
+ } while (verb != SkPath::kDone_Verb);
+
+ // If you have a path that ends with an M, Skia will not iterate the
+ // trailing M. That's nice of it, but Apple's paths output the trailing M
+ // and we want out layout dumps to look like theirs
+ if (numPoints) {
+ ASSERT(numPoints==1);
+ m_path->getLastPt(pts);
+ result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY);
+ }
+
+ return result.stripWhiteSpace();
+}
+
+// Computes the bounding box for the stroke and style currently selected into
+// the given bounding box. This also takes into account the stroke width.
+static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context)
+{
+ SkPaint paint;
+ context->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ SkPath boundingPath;
+ paint.getFillPath(context->platformContext()->currentPath(), &boundingPath);
+ SkRect r;
+ boundingPath.computeBounds(&r, SkPath::kExact_BoundsType);
+ return r;
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ GraphicsContext* scratch = scratchContext();
+ scratch->save();
+ scratch->beginPath();
+ scratch->addPath(*this);
+
+ if (applier)
+ applier->strokeStyle(scratch);
+
+ FloatRect r = boundingBoxForCurrentStroke(scratch);
+ scratch->restore();
+ return r;
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+ GraphicsContext* scratch = scratchContext();
+ scratch->save();
+
+ applier->strokeStyle(scratch);
+
+ SkPaint paint;
+ scratch->platformContext()->setupPaintForStroking(&paint, 0, 0);
+ SkPath strokePath;
+ paint.getFillPath(*platformPath(), &strokePath);
+ bool contains = SkPathContainsPoint(&strokePath, point,
+ SkPath::kWinding_FillType);
+
+ scratch->restore();
+ return contains;
+}
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/PatternSkia.cpp b/WebCore/platform/graphics/skia/PatternSkia.cpp
new file mode 100644
index 0000000..be8eb8a
--- /dev/null
+++ b/WebCore/platform/graphics/skia/PatternSkia.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 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 "Pattern.h"
+
+#include "Image.h"
+#include "NativeImageSkia.h"
+#include "TransformationMatrix.h"
+
+#include "SkShader.h"
+#include "SkCanvas.h"
+
+namespace WebCore {
+
+PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const
+{
+ // Note: patternTransform is ignored since it seems to be applied elsewhere
+ // (when the pattern is used?). Applying it to the pattern (i.e.
+ // shader->setLocalMatrix) results in a double transformation. This can be
+ // seen, for instance, as an extra offset in:
+ // LayoutTests/fast/canvas/patternfill-repeat.html
+ // and expanded scale and skew in:
+ // LayoutTests/svg/W3C-SVG-1.1/pservers-grad-06-b.svg
+
+ SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame();
+ if (m_repeatX && m_repeatY)
+ return SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
+
+ // Skia does not have a "draw the tile only once" option. Clamp_TileMode
+ // repeats the last line of the image after drawing one tile. To avoid
+ // filling the space with arbitrary pixels, this workaround forces the
+ // image to have a line of transparent pixels on the "repeated" edge(s),
+ // thus causing extra space to be transparent filled.
+ SkShader::TileMode tileModeX = m_repeatX ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+ SkShader::TileMode tileModeY = m_repeatY ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+ int expandW = m_repeatX ? 0 : 1;
+ int expandH = m_repeatY ? 0 : 1;
+
+ // Create a transparent bitmap 1 pixel wider and/or taller than the
+ // original, then copy the orignal into it.
+ // FIXME: Is there a better way to pad (not scale) an image in skia?
+ SkBitmap bm2;
+ bm2.setConfig(bm->config(), bm->width() + expandW, bm->height() + expandH);
+ bm2.allocPixels();
+ bm2.eraseARGB(0x00, 0x00, 0x00, 0x00);
+ SkCanvas canvas(bm2);
+ canvas.drawBitmap(*bm, 0, 0);
+ return SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
new file mode 100644
index 0000000..60dbbe0
--- /dev/null
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "GraphicsContext.h"
+#include "NativeImageSkia.h"
+#include "PlatformContextSkia.h"
+#include "SkiaUtils.h"
+
+#include "skia/ext/image_operations.h"
+#include "skia/ext/platform_canvas.h"
+
+#include "SkBitmap.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkDashPathEffect.h"
+
+#include <wtf/MathExtras.h>
+
+#if defined(__linux__)
+#include "GdkSkia.h"
+#endif
+
+// State -----------------------------------------------------------------------
+
+// Encapsulates the additional painting state information we store for each
+// pushed graphics state.
+struct PlatformContextSkia::State {
+ State();
+ State(const State&);
+ ~State();
+
+ // Common shader state.
+ float m_alpha;
+ SkPorterDuff::Mode m_porterDuffMode;
+ SkShader* m_gradient;
+ SkShader* m_pattern;
+ bool m_useAntialiasing;
+ SkDrawLooper* m_looper;
+
+ // Fill.
+ SkColor m_fillColor;
+
+ // Stroke.
+ WebCore::StrokeStyle m_strokeStyle;
+ SkColor m_strokeColor;
+ float m_strokeThickness;
+ int m_dashRatio; // Ratio of the length of a dash to its width.
+ float m_miterLimit;
+ SkPaint::Cap m_lineCap;
+ SkPaint::Join m_lineJoin;
+ SkDashPathEffect* m_dash;
+
+ // Text. (See cTextFill & friends in GraphicsContext.h.)
+ int m_textDrawingMode;
+
+ // Helper function for applying the state's alpha value to the given input
+ // color to produce a new output color.
+ SkColor applyAlpha(SkColor) const;
+
+private:
+ // Not supported.
+ void operator=(const State&);
+};
+
+// 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_useAntialiasing(true)
+ , m_looper(0)
+ , m_fillColor(0xFF000000)
+ , m_strokeStyle(WebCore::SolidStroke)
+ , m_strokeColor(WebCore::Color::black)
+ , m_strokeThickness(0)
+ , m_dashRatio(3)
+ , m_miterLimit(4)
+ , m_lineCap(SkPaint::kDefault_Cap)
+ , m_lineJoin(SkPaint::kDefault_Join)
+ , m_dash(0)
+ , m_textDrawingMode(WebCore::cTextFill)
+{
+}
+
+PlatformContextSkia::State::State(const State& other)
+{
+ memcpy(this, &other, sizeof(State));
+
+ m_looper->safeRef();
+ m_dash->safeRef();
+ m_gradient->safeRef();
+ m_pattern->safeRef();
+}
+
+PlatformContextSkia::State::~State()
+{
+ m_looper->safeUnref();
+ m_dash->safeUnref();
+ m_gradient->safeUnref();
+ m_pattern->safeUnref();
+}
+
+SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
+{
+ int s = roundf(m_alpha * 256);
+ if (s >= 256)
+ return c;
+ if (s < 0)
+ return 0;
+
+ int a = SkAlphaMul(SkColorGetA(c), s);
+ return (c & 0x00FFFFFF) | (a << 24);
+}
+
+// PlatformContextSkia ---------------------------------------------------------
+
+// Danger: canvas can be NULL.
+PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
+ : m_canvas(canvas)
+ , m_stateStack(sizeof(State))
+{
+ m_stateStack.append(State());
+ m_state = &m_stateStack.last();
+#if defined(OS_LINUX)
+ m_gdkskia = m_canvas ? gdk_skia_new(m_canvas) : 0;
+#endif
+}
+
+PlatformContextSkia::~PlatformContextSkia()
+{
+#if defined(OS_LINUX)
+ if (m_gdkskia) {
+ g_object_unref(m_gdkskia);
+ m_gdkskia = 0;
+ }
+#endif
+}
+
+void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
+{
+ m_canvas = canvas;
+}
+
+void PlatformContextSkia::save()
+{
+ m_stateStack.append(*m_state);
+ m_state = &m_stateStack.last();
+
+ // Save our native canvas.
+ canvas()->save();
+}
+
+void PlatformContextSkia::restore()
+{
+ m_stateStack.removeLast();
+ m_state = &m_stateStack.last();
+
+ // Restore our native canvas.
+ canvas()->restore();
+}
+
+void PlatformContextSkia::drawRect(SkRect rect)
+{
+ SkPaint paint;
+ int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000;
+ if (fillcolorNotTransparent) {
+ setupPaintForFilling(&paint);
+ canvas()->drawRect(rect, paint);
+ }
+
+ if (m_state->m_strokeStyle != WebCore::NoStroke &&
+ (m_state->m_strokeColor & 0xFF000000)) {
+ if (fillcolorNotTransparent) {
+ // This call is expensive so don't call it unnecessarily.
+ paint.reset();
+ }
+ setupPaintForStroking(&paint, &rect, 0);
+ canvas()->drawRect(rect, paint);
+ }
+}
+
+void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
+{
+#ifdef SK_DEBUGx
+ {
+ SkPaint defaultPaint;
+ SkASSERT(*paint == defaultPaint);
+ }
+#endif
+
+ paint->setAntiAlias(m_state->m_useAntialiasing);
+ paint->setPorterDuffXfermode(m_state->m_porterDuffMode);
+ 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));
+}
+
+float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
+{
+ setupPaintCommon(paint);
+ float width = m_state->m_strokeThickness;
+
+ // This allows dashing and dotting to work properly for hairline strokes.
+ if (width == 0)
+ width = 1;
+
+ paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
+ paint->setStyle(SkPaint::kStroke_Style);
+ paint->setStrokeWidth(SkFloatToScalar(width));
+ paint->setStrokeCap(m_state->m_lineCap);
+ paint->setStrokeJoin(m_state->m_lineJoin);
+ paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
+
+ if (rect != 0 && (static_cast<int>(roundf(width)) & 1))
+ rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
+
+ if (m_state->m_dash)
+ paint->setPathEffect(m_state->m_dash);
+ else {
+ switch (m_state->m_strokeStyle) {
+ case WebCore::NoStroke:
+ case WebCore::SolidStroke:
+ break;
+ case WebCore::DashedStroke:
+ 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.
+ int numDashes = length / roundf(width);
+ 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();
+ }
+ }
+
+ return width;
+}
+
+void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
+{
+ SkRefCnt_SafeAssign(m_state->m_looper, dl);
+}
+
+void PlatformContextSkia::setMiterLimit(float ml)
+{
+ m_state->m_miterLimit = ml;
+}
+
+void PlatformContextSkia::setAlpha(float alpha)
+{
+ m_state->m_alpha = alpha;
+}
+
+void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
+{
+ m_state->m_lineCap = lc;
+}
+
+void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
+{
+ m_state->m_lineJoin = lj;
+}
+
+void PlatformContextSkia::setPorterDuffMode(SkPorterDuff::Mode pdm)
+{
+ m_state->m_porterDuffMode = pdm;
+}
+
+void PlatformContextSkia::setFillColor(SkColor color)
+{
+ m_state->m_fillColor = color;
+}
+
+SkDrawLooper* PlatformContextSkia::getDrawLooper() const
+{
+ return m_state->m_looper;
+}
+
+WebCore::StrokeStyle PlatformContextSkia::getStrokeStyle() const
+{
+ return m_state->m_strokeStyle;
+}
+
+void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle)
+{
+ m_state->m_strokeStyle = strokeStyle;
+}
+
+void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
+{
+ m_state->m_strokeColor = strokeColor;
+}
+
+float PlatformContextSkia::getStrokeThickness() const
+{
+ return m_state->m_strokeThickness;
+}
+
+void PlatformContextSkia::setStrokeThickness(float thickness)
+{
+ m_state->m_strokeThickness = thickness;
+}
+
+int PlatformContextSkia::getTextDrawingMode() const
+{
+ return m_state->m_textDrawingMode;
+}
+
+void PlatformContextSkia::setTextDrawingMode(int mode)
+{
+ // cTextClip is never used, so we assert that it isn't set:
+ // https://bugs.webkit.org/show_bug.cgi?id=21898
+ ASSERT((mode & WebCore::cTextClip) == 0);
+ m_state->m_textDrawingMode = mode;
+}
+
+void PlatformContextSkia::setUseAntialiasing(bool enable)
+{
+ m_state->m_useAntialiasing = enable;
+}
+
+SkColor PlatformContextSkia::fillColor() const
+{
+ return m_state->m_fillColor;
+}
+
+void PlatformContextSkia::beginPath()
+{
+ m_path.reset();
+}
+
+void PlatformContextSkia::addPath(const SkPath& path)
+{
+ m_path.addPath(path);
+}
+
+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)
+{
+ if (pattern != m_state->m_pattern) {
+ m_state->m_pattern->safeUnref();
+ m_state->m_pattern = pattern;
+ }
+}
+
+void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
+{
+ if (dash != m_state->m_dash) {
+ m_state->m_dash->safeUnref();
+ m_state->m_dash = dash;
+ }
+}
+
+void PlatformContextSkia::paintSkPaint(const SkRect& rect,
+ const SkPaint& paint)
+{
+ m_canvas->drawRect(rect, paint);
+}
+
+const SkBitmap* PlatformContextSkia::bitmap() const
+{
+ return &m_canvas->getDevice()->accessBitmap(false);
+}
+
+bool PlatformContextSkia::isPrinting()
+{
+ return m_canvas->getTopPlatformDevice().IsVectorial();
+}
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h
new file mode 100644
index 0000000..78e9a19
--- /dev/null
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PlatformContextSkia_h
+#define PlatformContextSkia_h
+
+#include "GraphicsContext.h"
+#include "Noncopyable.h"
+
+#include "SkDashPathEffect.h"
+#include "SkDrawLooper.h"
+#include "SkDeque.h"
+#include "skia/ext/platform_canvas.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+
+#include <wtf/Vector.h>
+
+typedef struct _GdkDrawable GdkSkia;
+
+// This class holds the platform-specific state for GraphicsContext. We put
+// most of our Skia wrappers on this class. In theory, a lot of this stuff could
+// be moved to GraphicsContext directly, except that some code external to this
+// would like to poke at our graphics layer as well (like the Image and Font
+// stuff, which needs some amount of our wrappers and state around SkCanvas).
+//
+// So in general, this class uses just Skia types except when there's no easy
+// conversion. GraphicsContext is responsible for converting the WebKit types to
+// Skia types and setting up the eventual call to the Skia functions.
+//
+// This class then keeps track of all the current Skia state. WebKit expects
+// that the graphics state that is pushed and popped by save() and restore()
+// includes things like colors and pen styles. Skia does this differently, where
+// push and pop only includes transforms and bitmaps, and the application is
+// 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 {
+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.
+ PlatformContextSkia(skia::PlatformCanvas*);
+ ~PlatformContextSkia();
+
+ // Sets the canvas associated with this context. Use when supplying NULL
+ // to the constructor.
+ void setCanvas(skia::PlatformCanvas*);
+
+ void save();
+ void restore();
+
+ // Sets up the common flags on a paint for antialiasing, effects, etc.
+ // This is implicitly called by setupPaintFill and setupPaintStroke, but
+ // you may wish to call it directly sometimes if you don't want that other
+ // behavior.
+ void setupPaintCommon(SkPaint*) const;
+
+ // Sets up the paint for the current fill style.
+ void setupPaintForFilling(SkPaint*) const;
+
+ // Sets up the paint for stroking. Returns an int representing the width of
+ // the pen, or 1 if the pen's width is 0 if a non-zero length is provided,
+ // the number of dashes/dots on a dashed/dotted line will be adjusted to
+ // start and end that length with a dash/dot.
+ float setupPaintForStroking(SkPaint*, SkRect*, int length) const;
+
+ // State setting functions.
+ void setDrawLooper(SkDrawLooper*); // Note: takes an additional ref.
+ void setMiterLimit(float);
+ void setAlpha(float);
+ void setLineCap(SkPaint::Cap);
+ void setLineJoin(SkPaint::Join);
+ void setFillRule(SkPath::FillType);
+ void setPorterDuffMode(SkPorterDuff::Mode);
+ void setFillColor(SkColor);
+ void setStrokeStyle(WebCore::StrokeStyle);
+ void setStrokeColor(SkColor);
+ void setStrokeThickness(float thickness);
+ void setTextDrawingMode(int mode);
+ void setUseAntialiasing(bool enable);
+ void setGradient(SkShader*);
+ void setPattern(SkShader*);
+ void setDashPathEffect(SkDashPathEffect*);
+
+ SkDrawLooper* getDrawLooper() const;
+ WebCore::StrokeStyle getStrokeStyle() const;
+ float getStrokeThickness() const;
+ int getTextDrawingMode() const;
+
+ void beginPath();
+ void addPath(const SkPath&);
+ const SkPath* currentPath() const { return &m_path; }
+
+ SkColor fillColor() const;
+
+ skia::PlatformCanvas* canvas() { return m_canvas; }
+
+ // FIXME: This should be pushed down to GraphicsContext.
+ void drawRect(SkRect rect);
+
+ // FIXME: I'm still unsure how I will serialize this call.
+ void paintSkPaint(const SkRect&, const SkPaint&);
+
+ const SkBitmap* bitmap() const;
+
+ // Returns the canvas used for painting, NOT guaranteed to be non-NULL.
+ //
+ // Warning: This function is deprecated so the users are reminded that they
+ // should use this layer of indirection instead of using the canvas
+ // directly. This is to help with the eventual serialization.
+ skia::PlatformCanvas* canvas() const;
+
+ // Returns if the context is a printing context instead of a display
+ // context. Bitmap shouldn't be resampled when printing to keep the best
+ // possible quality.
+ bool isPrinting();
+
+#if defined(__linux__)
+ // FIXME: should be camelCase.
+ GdkSkia* gdk_skia() const { return m_gdkskia; }
+#endif
+
+private:
+ // Defines drawing style.
+ struct State;
+
+ // NULL indicates painting is disabled. Never delete this object.
+ skia::PlatformCanvas* m_canvas;
+
+ // States stack. Enables local drawing state change with save()/restore()
+ // calls.
+ WTF::Vector<State> m_stateStack;
+ // Pointer to the current drawing state. This is a cached value of
+ // mStateStack.back().
+ State* m_state;
+
+ // Current path.
+ SkPath m_path;
+
+#if defined(__linux__)
+ // A pointer to a GDK Drawable wrapping of this Skia canvas
+ GdkSkia* m_gdkskia;
+#endif
+};
+
+#endif // PlatformContextSkia_h
diff --git a/WebCore/platform/graphics/skia/PlatformGraphics.h b/WebCore/platform/graphics/skia/PlatformGraphics.h
new file mode 100644
index 0000000..4ae8835
--- /dev/null
+++ b/WebCore/platform/graphics/skia/PlatformGraphics.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PlatformGraphics_h
+#define PlatformGraphics_h
+
+typedef class SkShader* PlatformGradient;
+typedef class SkShader* PlatformPattern;
+
+#endif // PlatformGraphics_h
diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
new file mode 100644
index 0000000..6e79a7e
--- /dev/null
+++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SkiaFontWin.h"
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+#include <wtf/ListHashSet.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+struct CachedOutlineKey {
+ CachedOutlineKey() : font(0), glyph(0), path(0) {}
+ CachedOutlineKey(HFONT f, WORD g) : font(f), glyph(g), path(0) {}
+
+ HFONT font;
+ WORD glyph;
+
+ // The lifetime of this pointer is managed externally to this class. Be sure
+ // to call DeleteOutline to remove items.
+ SkPath* path;
+};
+
+const bool operator==(const CachedOutlineKey& a, const CachedOutlineKey& b)
+{
+ return a.font == b.font && a.glyph == b.glyph;
+}
+
+struct CachedOutlineKeyHash {
+ static unsigned hash(const CachedOutlineKey& key)
+ {
+ unsigned keyBytes;
+ memcpy(&keyBytes, &key.font, sizeof(unsigned));
+ return keyBytes + key.glyph;
+ }
+
+ static unsigned equal(const CachedOutlineKey& a, const CachedOutlineKey& b)
+ {
+ return a.font == b.font && a.glyph == b.glyph;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+typedef ListHashSet<CachedOutlineKey, CachedOutlineKeyHash> OutlineCache;
+
+// FIXME: Convert from static constructor to accessor function. WebCore tries to
+// avoid global constructors to save on start-up time.
+static OutlineCache outlineCache;
+
+// The global number of glyph outlines we'll cache.
+static const int outlineCacheSize = 256;
+
+static SkScalar FIXEDToSkScalar(FIXED fixed)
+{
+ SkFixed skFixed;
+ memcpy(&skFixed, &fixed, sizeof(SkFixed));
+ return SkFixedToScalar(skFixed);
+}
+
+// Removes the given key from the cached outlines, also deleting the path.
+static void deleteOutline(OutlineCache::iterator deleteMe)
+{
+ delete deleteMe->path;
+ outlineCache.remove(deleteMe);
+}
+
+static void addPolyCurveToPath(const TTPOLYCURVE* polyCurve, SkPath* path)
+{
+ switch (polyCurve->wType) {
+ case TT_PRIM_LINE:
+ for (WORD i = 0; i < polyCurve->cpfx; i++) {
+ path->lineTo(FIXEDToSkScalar(polyCurve->apfx[i].x), -FIXEDToSkScalar(polyCurve->apfx[i].y));
+ }
+ break;
+
+ case TT_PRIM_QSPLINE:
+ // FIXME: doesn't this duplicate points if we do the loop > once?
+ for (WORD i = 0; i < polyCurve->cpfx - 1; i++) {
+ SkScalar bx = FIXEDToSkScalar(polyCurve->apfx[i].x);
+ SkScalar by = FIXEDToSkScalar(polyCurve->apfx[i].y);
+
+ SkScalar cx = FIXEDToSkScalar(polyCurve->apfx[i + 1].x);
+ SkScalar cy = FIXEDToSkScalar(polyCurve->apfx[i + 1].y);
+ if (i < polyCurve->cpfx - 2) {
+ // We're not the last point, compute C.
+ cx = SkScalarAve(bx, cx);
+ cy = SkScalarAve(by, cy);
+ }
+
+ // Need to flip the y coordinates since the font's coordinate system is
+ // flipped from ours vertically.
+ path->quadTo(bx, -by, cx, -cy);
+ }
+ break;
+
+ case TT_PRIM_CSPLINE:
+ // FIXME
+ break;
+ }
+}
+
+// The size of the glyph path buffer.
+static const int glyphPathBufferSize = 4096;
+
+// Fills the given SkPath with the outline for the given glyph index. The font
+// currently selected into the given DC is used. Returns true on success.
+static bool getPathForGlyph(HDC dc, WORD glyph, SkPath* path)
+{
+ char buffer[glyphPathBufferSize];
+ GLYPHMETRICS gm;
+ MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // Each one is (fract,value).
+
+ DWORD totalSize = GetGlyphOutlineW(dc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE,
+ &gm, glyphPathBufferSize, buffer, &mat);
+ if (totalSize == GDI_ERROR)
+ return false;
+
+ const char* curGlyph = buffer;
+ const char* endGlyph = &buffer[totalSize];
+ while (curGlyph < endGlyph) {
+ const TTPOLYGONHEADER* polyHeader =
+ reinterpret_cast<const TTPOLYGONHEADER*>(curGlyph);
+ path->moveTo(FIXEDToSkScalar(polyHeader->pfxStart.x),
+ -FIXEDToSkScalar(polyHeader->pfxStart.y));
+
+ const char* curPoly = curGlyph + sizeof(TTPOLYGONHEADER);
+ const char* endPoly = curGlyph + polyHeader->cb;
+ while (curPoly < endPoly) {
+ const TTPOLYCURVE* polyCurve =
+ reinterpret_cast<const TTPOLYCURVE*>(curPoly);
+ addPolyCurveToPath(polyCurve, path);
+ curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx;
+ }
+ curGlyph += polyHeader->cb;
+ }
+
+ path->close();
+ return true;
+}
+
+// Returns a SkPath corresponding to the give glyph in the given font. The font
+// should be selected into the given DC. The returned path is owned by the
+// hashtable. Returns 0 on error.
+const SkPath* SkiaWinOutlineCache::lookupOrCreatePathForGlyph(HDC hdc, HFONT font, WORD glyph)
+{
+ CachedOutlineKey key(font, glyph);
+ OutlineCache::iterator found = outlineCache.find(key);
+ if (found != outlineCache.end()) {
+ // Keep in MRU order by removing & reinserting the value.
+ key = *found;
+ outlineCache.remove(found);
+ outlineCache.add(key);
+ return key.path;
+ }
+
+ key.path = new SkPath;
+ if (!getPathForGlyph(hdc, glyph, key.path))
+ return 0;
+
+ if (outlineCache.size() > outlineCacheSize)
+ // The cache is too big, find the oldest value (first in the list).
+ deleteOutline(outlineCache.begin());
+
+ outlineCache.add(key);
+ return key.path;
+}
+
+
+void SkiaWinOutlineCache::removePathsForFont(HFONT hfont)
+{
+ // ListHashSet isn't the greatest structure for deleting stuff out of, but
+ // removing entries will be relatively rare (we don't remove fonts much, nor
+ // do we draw out own glyphs using these routines much either).
+ //
+ // We keep a list of all glyphs we're removing which we do in a separate
+ // pass.
+ Vector<CachedOutlineKey> outlinesToDelete;
+ for (OutlineCache::iterator i = outlineCache.begin();
+ i != outlineCache.end(); ++i)
+ outlinesToDelete.append(*i);
+
+ for (Vector<CachedOutlineKey>::iterator i = outlinesToDelete.begin();
+ i != outlinesToDelete.end(); ++i)
+ deleteOutline(outlineCache.find(*i));
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.h b/WebCore/platform/graphics/skia/SkiaFontWin.h
new file mode 100644
index 0000000..2adab39
--- /dev/null
+++ b/WebCore/platform/graphics/skia/SkiaFontWin.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SkiaWinOutlineCache_h
+#define SkiaWinOutlineCache_h
+
+#include <windows.h>
+
+class SkPath;
+
+namespace WebCore {
+
+// FIXME: Rename file to SkiaWinOutlineCache
+class SkiaWinOutlineCache {
+public:
+ static const SkPath* lookupOrCreatePathForGlyph(HDC, HFONT, WORD);
+ // Removes any cached glyphs from the outline cache corresponding to the
+ // given font handle.
+ static void removePathsForFont(HFONT);
+
+private:
+ SkiaWinOutlineCache();
+};
+
+} // namespace WebCore
+
+#endif // SkiaWinOutlineCache_h
diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp
new file mode 100644
index 0000000..6d9ffe2
--- /dev/null
+++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2006,2007,2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "SkiaUtils.h"
+
+#include "ImageBuffer.h"
+#include "SharedBuffer.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkMatrix.h"
+#include "SkRegion.h"
+
+namespace WebCore {
+
+static const struct CompositOpToPorterDuffMode {
+ uint8_t mCompositOp;
+ uint8_t mPorterDuffMode;
+} gMapCompositOpsToPorterDuffModes[] = {
+ { CompositeClear, SkPorterDuff::kClear_Mode },
+ { CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { 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::kLighten_Mode }
+};
+
+SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op)
+{
+ const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes;
+
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) {
+ if (table[i].mCompositOp == op)
+ return (SkPorterDuff::Mode)table[i].mPorterDuffMode;
+ }
+
+ SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositeOperator %d\n", op));
+ return SkPorterDuff::kSrcOver_Mode; // fall-back
+}
+
+static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
+{
+ SkASSERT(component == (uint8_t)component);
+ return (component * scale + 0x8000) >> 16;
+}
+
+SkColor SkPMColorToColor(SkPMColor pm)
+{
+ if (0 == pm)
+ return 0;
+
+ unsigned a = SkGetPackedA32(pm);
+ uint32_t scale = (255 << 16) / a;
+
+ return SkColorSetARGB(a,
+ InvScaleByte(SkGetPackedR32(pm), scale),
+ InvScaleByte(SkGetPackedG32(pm), scale),
+ InvScaleByte(SkGetPackedB32(pm), scale));
+}
+
+Color SkPMColorToWebCoreColor(SkPMColor pm)
+{
+ return SkPMColorToColor(pm);
+}
+
+void IntersectRectAndRegion(const SkRegion& region, const SkRect& srcRect, SkRect* destRect) {
+ // The cliperator requires an int rect, so we round out.
+ SkIRect srcRectRounded;
+ srcRect.roundOut(&srcRectRounded);
+
+ // The Cliperator will iterate over a bunch of rects where our transformed
+ // rect and the clipping region (which may be non-square) overlap.
+ SkRegion::Cliperator cliperator(region, srcRectRounded);
+ if (cliperator.done()) {
+ destRect->setEmpty();
+ return;
+ }
+
+ // Get the union of all visible rects in the clip that overlap our bitmap.
+ SkIRect currentVisibleRect = cliperator.rect();
+ cliperator.next();
+ while (!cliperator.done()) {
+ currentVisibleRect.join(cliperator.rect());
+ cliperator.next();
+ }
+
+ destRect->set(currentVisibleRect);
+}
+
+void ClipRectToCanvas(const SkCanvas& canvas, const SkRect& srcRect, SkRect* destRect) {
+ // Translate into the canvas' coordinate space. This is where the clipping
+ // region applies.
+ SkRect transformedSrc;
+ canvas.getTotalMatrix().mapRect(&transformedSrc, srcRect);
+
+ // Do the intersection.
+ SkRect transformedDest;
+ IntersectRectAndRegion(canvas.getTotalClip(), transformedSrc, &transformedDest);
+
+ // Now transform it back into world space.
+ SkMatrix inverseTransform;
+ canvas.getTotalMatrix().invert(&inverseTransform);
+ inverseTransform.mapRect(destRect, transformedDest);
+}
+
+bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft)
+{
+ SkRegion rgn;
+ SkRegion clip;
+
+ SkPath::FillType originalFillType = originalPath->getFillType();
+
+ const SkPath* path = originalPath;
+ SkPath scaledPath;
+ int scale = 1;
+
+ SkRect bounds;
+ originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType);
+
+ // We can immediately return false if the point is outside the bounding rect
+ if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y())))
+ return false;
+
+ originalPath->setFillType(ft);
+
+ // Skia has trouble with coordinates close to the max signed 16-bit values
+ // If we have those, we need to scale.
+ //
+ // TODO: remove this code once Skia is patched to work properly with large
+ // values
+ const SkScalar kMaxCoordinate = SkIntToScalar(1<<15);
+ SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);
+
+ if (biggestCoord > kMaxCoordinate) {
+ scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate));
+
+ SkMatrix m;
+ m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale)));
+ originalPath->transform(m, &scaledPath);
+ path = &scaledPath;
+ }
+
+ int x = static_cast<int>(floorf(point.x() / scale));
+ int y = static_cast<int>(floorf(point.y() / scale));
+ clip.setRect(x, y, x + 1, y + 1);
+
+ bool contains = rgn.setPath(*path, clip);
+
+ originalPath->setFillType(originalFillType);
+ return contains;
+}
+
+GraphicsContext* scratchContext()
+{
+ static ImageBuffer* scratch = 0;
+ if (!scratch)
+ scratch = ImageBuffer::create(IntSize(1, 1), false).release();
+ // We don't bother checking for failure creating the ImageBuffer, since our
+ // ImageBuffer initializer won't fail.
+ return scratch->context();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/skia/SkiaUtils.h b/WebCore/platform/graphics/skia/SkiaUtils.h
new file mode 100644
index 0000000..0e68574
--- /dev/null
+++ b/WebCore/platform/graphics/skia/SkiaUtils.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2006,2007,2008, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// All of the functions in this file should move to new homes and this file should be deleted.
+
+#ifndef SkiaUtils_h
+#define SkiaUtils_h
+
+#include <wtf/MathExtras.h>
+#include "GraphicsContext.h"
+#include "SkPath.h"
+#include "SkPorterDuff.h"
+
+class SkCanvas;
+class SkRegion;
+
+namespace WebCore {
+
+SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator);
+
+// move this guy into SkColor.h
+SkColor SkPMColorToColor(SkPMColor);
+
+// This should be an operator on Color
+Color SkPMColorToWebCoreColor(SkPMColor);
+
+// Skia has problems when passed infinite, etc floats, filter them to 0.
+inline SkScalar WebCoreFloatToSkScalar(float f)
+{
+ return SkFloatToScalar(isfinite(f) ? f : 0);
+}
+
+inline SkScalar WebCoreDoubleToSkScalar(double d)
+{
+ return SkDoubleToScalar(isfinite(d) ? d : 0);
+}
+
+// Computes the smallest rectangle that, which when drawn to the given canvas,
+// will cover the same area as the source rectangle. It will clip to the canvas'
+// clip, doing the necessary coordinate transforms.
+//
+// srcRect and destRect can be the same.
+void ClipRectToCanvas(const SkCanvas&, const SkRect& srcRect, SkRect* destRect);
+
+// Determine if a given WebKit point is contained in a path
+bool SkPathContainsPoint(SkPath*, const FloatPoint&, SkPath::FillType);
+
+// Returns a statically allocated 1x1 GraphicsContext intended for temporary
+// operations. Please save() the state and restore() it when you're done with
+// the context.
+GraphicsContext* scratchContext();
+
+} // namespace WebCore
+
+#endif // SkiaUtils_h
diff --git a/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
new file mode 100644
index 0000000..1e2a194
--- /dev/null
+++ b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp
@@ -0,0 +1,222 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+#include "TransformationMatrix.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include "SkiaUtils.h"
+
+namespace WebCore {
+
+TransformationMatrix::TransformationMatrix()
+{
+ m_transform.reset();
+}
+
+TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f)
+{
+ setMatrix(a, b, c, d, e, f);
+}
+
+TransformationMatrix::TransformationMatrix(const SkMatrix& matrix)
+ : m_transform(matrix)
+{
+}
+
+void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f)
+{
+ m_transform.reset();
+
+ m_transform.setScaleX(WebCoreDoubleToSkScalar(a));
+ m_transform.setSkewX(WebCoreDoubleToSkScalar(c));
+ m_transform.setTranslateX(WebCoreDoubleToSkScalar(e));
+
+ m_transform.setScaleY(WebCoreDoubleToSkScalar(d));
+ m_transform.setSkewY(WebCoreDoubleToSkScalar(b));
+ m_transform.setTranslateY(WebCoreDoubleToSkScalar(f));
+}
+
+void TransformationMatrix::map(double x, double y, double* x2, double* y2) const
+{
+ SkPoint src, dst;
+ src.set(WebCoreDoubleToSkScalar(x), WebCoreDoubleToSkScalar(y));
+ m_transform.mapPoints(&dst, &src, 1);
+
+ *x2 = SkScalarToDouble(dst.fX);
+ *y2 = SkScalarToDouble(dst.fY);
+}
+
+IntRect TransformationMatrix::mapRect(const IntRect& src) const
+{
+ SkRect dst;
+ m_transform.mapRect(&dst, src);
+ return enclosingIntRect(dst);
+}
+
+FloatRect TransformationMatrix::mapRect(const FloatRect& src) const
+{
+ SkRect dst;
+ m_transform.mapRect(&dst, src);
+ return dst;
+}
+
+bool TransformationMatrix::isIdentity() const
+{
+ return m_transform.isIdentity();
+}
+
+void TransformationMatrix::reset()
+{
+ m_transform.reset();
+}
+
+TransformationMatrix &TransformationMatrix::scale(double sx, double sy)
+{
+ m_transform.preScale(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0);
+ return *this;
+}
+
+TransformationMatrix &TransformationMatrix::rotate(double d)
+{
+ m_transform.preRotate(WebCoreDoubleToSkScalar(d), 0, 0);
+ return *this;
+}
+
+TransformationMatrix &TransformationMatrix::translate(double tx, double ty)
+{
+ m_transform.preTranslate(WebCoreDoubleToSkScalar(tx), WebCoreDoubleToSkScalar(ty));
+ return *this;
+}
+
+TransformationMatrix &TransformationMatrix::shear(double sx, double sy)
+{
+ m_transform.preSkew(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0);
+ return *this;
+}
+
+double TransformationMatrix::det() const
+{
+ return SkScalarToDouble(m_transform.getScaleX()) * SkScalarToDouble(m_transform.getScaleY()) -
+ SkScalarToDouble(m_transform.getSkewY()) * SkScalarToDouble(m_transform.getSkewX());
+}
+
+TransformationMatrix TransformationMatrix::inverse() const
+{
+ TransformationMatrix inverse;
+ m_transform.invert(&inverse.m_transform);
+ return inverse;
+}
+
+TransformationMatrix::operator SkMatrix() const
+{
+ return m_transform;
+}
+
+bool TransformationMatrix::operator==(const TransformationMatrix& m2) const
+{
+ return m_transform == m2.m_transform;
+}
+
+TransformationMatrix &TransformationMatrix::operator*=(const TransformationMatrix& m2)
+{
+ m_transform.setConcat(m2.m_transform, m_transform);
+ return *this;
+}
+
+TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& m2)
+{
+ TransformationMatrix cat;
+ cat.m_transform.setConcat(m2.m_transform, m_transform);
+ return cat;
+}
+
+double TransformationMatrix::a() const
+{
+ return SkScalarToDouble(m_transform.getScaleX());
+}
+
+void TransformationMatrix::setA(double a)
+{
+ m_transform.setScaleX(WebCoreDoubleToSkScalar(a));
+}
+
+double TransformationMatrix::b() const
+{
+ return SkScalarToDouble(m_transform.getSkewY());
+}
+
+void TransformationMatrix::setB(double b)
+{
+ m_transform.setSkewY(WebCoreDoubleToSkScalar(b));
+}
+
+double TransformationMatrix::c() const
+{
+ return SkScalarToDouble(m_transform.getSkewX());
+}
+
+void TransformationMatrix::setC(double c)
+{
+ m_transform.setSkewX(WebCoreDoubleToSkScalar(c));
+}
+
+double TransformationMatrix::d() const
+{
+ return SkScalarToDouble(m_transform.getScaleY());
+}
+
+void TransformationMatrix::setD(double d)
+{
+ m_transform.setScaleY(WebCoreDoubleToSkScalar(d));
+}
+
+double TransformationMatrix::e() const
+{
+ return SkScalarToDouble(m_transform.getTranslateX());
+}
+
+void TransformationMatrix::setE(double e)
+{
+ m_transform.setTranslateX(WebCoreDoubleToSkScalar(e));
+}
+
+double TransformationMatrix::f() const
+{
+ return SkScalarToDouble(m_transform.getTranslateY());
+}
+
+void TransformationMatrix::setF(double f)
+{
+ m_transform.setTranslateY(WebCoreDoubleToSkScalar(f));
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/IdentityTransformOperation.h b/WebCore/platform/graphics/transforms/IdentityTransformOperation.h
new file mode 100644
index 0000000..347737c
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/IdentityTransformOperation.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef IdentityTransformOperation_h
+#define IdentityTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class IdentityTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<IdentityTransformOperation> create()
+ {
+ return adoptRef(new IdentityTransformOperation());
+ }
+
+private:
+ virtual bool isIdentity() const { return true; }
+ virtual OperationType getOperationType() const { return IDENTITY; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == IDENTITY; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ return isSameType(o);
+ }
+
+ virtual bool apply(TransformationMatrix&, const IntSize&) const
+ {
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation*, double, bool = false)
+ {
+ return this;
+ }
+
+ IdentityTransformOperation()
+ {
+ }
+
+};
+
+} // namespace WebCore
+
+#endif // IdentityTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
new file mode 100644
index 0000000..153d96d
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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.
+ *
+ */
+
+#include "config.h"
+#include "MatrixTransformOperation.h"
+
+#include <algorithm>
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ // convert the TransformOperations into matrices
+ IntSize size;
+ TransformationMatrix fromT;
+ TransformationMatrix toT(m_a, m_b, m_c, m_d, m_e, m_f);
+ if (from) {
+ const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(from);
+ fromT.setMatrix(m->m_a, m->m_b, m->m_c, m->m_d, m->m_e, m->m_f);
+ }
+
+ if (blendToIdentity)
+ std::swap(fromT, toT);
+
+ toT.blend(fromT, progress);
+ return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f());
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
new file mode 100644
index 0000000..d272229
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MatrixTransformOperation_h
+#define MatrixTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class MatrixTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<MatrixTransformOperation> create(double a, double b, double c, double d, double e, double f)
+ {
+ return adoptRef(new MatrixTransformOperation(a, b, c, d, e, f));
+ }
+
+private:
+ virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; }
+ virtual OperationType getOperationType() const { return MATRIX; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+
+ const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(&o);
+ return m_a == m->m_a && m_b == m->m_b && m_c == m->m_c && m_d == m->m_d && m_e == m->m_e && m_f == m->m_f;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ TransformationMatrix matrix(m_a, m_b, m_c, m_d, m_e, m_f);
+ transform = matrix * transform;
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ MatrixTransformOperation(double a, double b, double c, double d, double e, double f)
+ : m_a(a)
+ , m_b(b)
+ , m_c(c)
+ , m_d(d)
+ , m_e(e)
+ , m_f(f)
+ {
+ }
+
+ double m_a;
+ double m_b;
+ double m_c;
+ double m_d;
+ double m_e;
+ double m_f;
+};
+
+} // namespace WebCore
+
+#endif // MatrixTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
new file mode 100644
index 0000000..4887cee
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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.
+ *
+ */
+
+#include "config.h"
+#include "RotateTransformOperation.h"
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return RotateTransformOperation::create(m_angle - m_angle * progress, m_type);
+
+ const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from);
+ double fromAngle = fromOp ? fromOp->m_angle : 0;
+ return RotateTransformOperation::create(fromAngle + (m_angle - fromAngle) * progress, m_type);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
new file mode 100644
index 0000000..adc6c4c
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RotateTransformOperation_h
+#define RotateTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class RotateTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<RotateTransformOperation> create(double angle, OperationType type)
+ {
+ return adoptRef(new RotateTransformOperation(angle, type));
+ }
+
+ virtual bool isIdentity() const { return m_angle == 0; }
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const RotateTransformOperation* r = static_cast<const RotateTransformOperation*>(&o);
+ return m_angle == r->m_angle;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize& /*borderBoxSize*/) const
+ {
+ transform.rotate(m_angle);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ double angle() const { return m_angle; }
+
+private:
+ RotateTransformOperation(double angle, OperationType type)
+ : m_angle(angle)
+ , m_type(type)
+ {
+ }
+
+ double m_angle;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // RotateTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
new file mode 100644
index 0000000..49a8fd8
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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.
+ *
+ */
+
+#include "config.h"
+#include "ScaleTransformOperation.h"
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> ScaleTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return ScaleTransformOperation::create(m_x + (1. - m_x) * progress, m_y + (1. - m_y) * progress, m_type);
+
+ const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from);
+ double fromX = fromOp ? fromOp->m_x : 1.;
+ double fromY = fromOp ? fromOp->m_y : 1.;
+ return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress, fromY + (m_y - fromY) * progress, m_type);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.h b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
new file mode 100644
index 0000000..289f8a1
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ScaleTransformOperation_h
+#define ScaleTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class ScaleTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, OperationType type)
+ {
+ return adoptRef(new ScaleTransformOperation(sx, sy, type));
+ }
+
+private:
+ virtual bool isIdentity() const { return m_x == 1 && m_y == 1; }
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const ScaleTransformOperation* s = static_cast<const ScaleTransformOperation*>(&o);
+ return m_x == s->m_x && m_y == s->m_y;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.scale(m_x, m_y);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ ScaleTransformOperation(double sx, double sy, OperationType type)
+ : m_x(sx)
+ , m_y(sy)
+ , m_type(type)
+ {
+ }
+
+ double m_x;
+ double m_y;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // ScaleTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp b/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp
new file mode 100644
index 0000000..2a430e9
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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.
+ *
+ */
+
+#include "config.h"
+#include "SkewTransformOperation.h"
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> SkewTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return SkewTransformOperation::create(m_angleX - m_angleX * progress, m_angleY - m_angleY * progress, m_type);
+
+ const SkewTransformOperation* fromOp = static_cast<const SkewTransformOperation*>(from);
+ double fromAngleX = fromOp ? fromOp->m_angleX : 0;
+ double fromAngleY = fromOp ? fromOp->m_angleY : 0;
+ return SkewTransformOperation::create(fromAngleX + (m_angleX - fromAngleX) * progress, fromAngleY + (m_angleY - fromAngleY) * progress, m_type);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/SkewTransformOperation.h b/WebCore/platform/graphics/transforms/SkewTransformOperation.h
new file mode 100644
index 0000000..6343710
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/SkewTransformOperation.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SkewTransformOperation_h
+#define SkewTransformOperation_h
+
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class SkewTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<SkewTransformOperation> create(double angleX, double angleY, OperationType type)
+ {
+ return adoptRef(new SkewTransformOperation(angleX, angleY, type));
+ }
+
+private:
+ virtual bool isIdentity() const { return m_angleX == 0 && m_angleY == 0; }
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const SkewTransformOperation* s = static_cast<const SkewTransformOperation*>(&o);
+ return m_angleX == s->m_angleX && m_angleY == s->m_angleY;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize&) const
+ {
+ transform.skew(m_angleX, m_angleY);
+ return false;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+ SkewTransformOperation(double angleX, double angleY, OperationType type)
+ : m_angleX(angleX)
+ , m_angleY(angleY)
+ , m_type(type)
+ {
+ }
+
+ double m_angleX;
+ double m_angleY;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // SkewTransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/TransformOperation.h b/WebCore/platform/graphics/transforms/TransformOperation.h
new file mode 100644
index 0000000..65a0def
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/TransformOperation.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TransformOperation_h
+#define TransformOperation_h
+
+#include "TransformationMatrix.h"
+#include "IntSize.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+// CSS Transforms (may become part of CSS3)
+
+class TransformOperation : public RefCounted<TransformOperation> {
+public:
+ enum OperationType {
+ SCALE_X, SCALE_Y, SCALE,
+ TRANSLATE_X, TRANSLATE_Y, TRANSLATE,
+ ROTATE,
+ SKEW_X, SKEW_Y, SKEW,
+ MATRIX, IDENTITY, NONE
+ };
+
+ virtual ~TransformOperation() { }
+
+ virtual bool operator==(const TransformOperation&) const = 0;
+ bool operator!=(const TransformOperation& o) const { return !(*this == o); }
+
+ virtual bool isIdentity() const = 0;
+
+ virtual bool apply(TransformationMatrix&, const IntSize& borderBoxSize) const = 0;
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0;
+
+ virtual OperationType getOperationType() const = 0;
+ virtual bool isSameType(const TransformOperation&) const { return false; }
+};
+
+} // namespace WebCore
+
+#endif // TransformOperation_h
diff --git a/WebCore/platform/graphics/transforms/TransformOperations.cpp b/WebCore/platform/graphics/transforms/TransformOperations.cpp
new file mode 100644
index 0000000..3d71480
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/TransformOperations.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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.
+ *
+ */
+
+#include "config.h"
+#include "TransformOperations.h"
+
+#include "IdentityTransformOperation.h"
+
+namespace WebCore {
+
+TransformOperations::TransformOperations(bool makeIdentity)
+{
+ if (makeIdentity)
+ m_operations.append(IdentityTransformOperation::create());
+}
+
+bool TransformOperations::operator==(const TransformOperations& o) const
+{
+ if (m_operations.size() != o.m_operations.size())
+ return false;
+
+ unsigned s = m_operations.size();
+ for (unsigned i = 0; i < s; i++) {
+ if (*m_operations[i] != *o.m_operations[i])
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h
new file mode 100644
index 0000000..f929417
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/TransformOperations.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TransformOperations_h
+#define TransformOperations_h
+
+#include "TransformOperation.h"
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class TransformOperations {
+public:
+ TransformOperations(bool makeIdentity = false);
+
+ bool operator==(const TransformOperations& o) const;
+ bool operator!=(const TransformOperations& o) const
+ {
+ return !(*this == o);
+ }
+
+ void apply(const IntSize& sz, TransformationMatrix& t) const
+ {
+ for (unsigned i = 0; i < m_operations.size(); ++i)
+ m_operations[i]->apply(t, sz);
+ }
+
+ Vector<RefPtr<TransformOperation> >& operations() { return m_operations; }
+ const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; }
+
+private:
+ Vector<RefPtr<TransformOperation> > m_operations;
+};
+
+} // namespace WebCore
+
+#endif // TransformOperations_h
diff --git a/WebCore/platform/graphics/AffineTransform.cpp b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
index fdeba44..b48d572 100644
--- a/WebCore/platform/graphics/AffineTransform.cpp
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp
@@ -24,18 +24,19 @@
*/
#include "config.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatRect.h"
+#include "FloatQuad.h"
#include "IntRect.h"
#include <wtf/MathExtras.h>
namespace WebCore {
-static void affineTransformDecompose(const AffineTransform& matrix, double sr[9])
+static void affineTransformDecompose(const TransformationMatrix& matrix, double sr[9])
{
- AffineTransform m(matrix);
+ TransformationMatrix m(matrix);
// Compute scaling factors
double sx = sqrt(m.a() * m.a() + m.b() * m.b());
@@ -73,7 +74,7 @@ static void affineTransformDecompose(const AffineTransform& matrix, double sr[9]
sr[7] = m.e(); sr[8] = m.f();
}
-static void affineTransformCompose(AffineTransform& m, const double sr[9])
+static void affineTransformCompose(TransformationMatrix& m, const double sr[9])
{
m.setA(sr[3]);
m.setB(sr[4]);
@@ -85,74 +86,74 @@ static void affineTransformCompose(AffineTransform& m, const double sr[9])
m.scale(sr[0], sr[1]);
}
-bool AffineTransform::isInvertible() const
+bool TransformationMatrix::isInvertible() const
{
return det() != 0.0;
}
-AffineTransform& AffineTransform::multiply(const AffineTransform& other)
+TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& other)
{
return (*this) *= other;
}
-AffineTransform& AffineTransform::scale(double s)
+TransformationMatrix& TransformationMatrix::scale(double s)
{
return scale(s, s);
}
-AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
+TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
{
return scale(sx, sy);
}
-AffineTransform& AffineTransform::rotateFromVector(double x, double y)
+TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
{
return rotate(rad2deg(atan2(y, x)));
}
-AffineTransform& AffineTransform::flipX()
+TransformationMatrix& TransformationMatrix::flipX()
{
return scale(-1.0f, 1.0f);
}
-AffineTransform& AffineTransform::flipY()
+TransformationMatrix& TransformationMatrix::flipY()
{
return scale(1.0f, -1.0f);
}
-AffineTransform& AffineTransform::skew(double angleX, double angleY)
+TransformationMatrix& TransformationMatrix::skew(double angleX, double angleY)
{
return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
}
-AffineTransform& AffineTransform::skewX(double angle)
+TransformationMatrix& TransformationMatrix::skewX(double angle)
{
return shear(tan(deg2rad(angle)), 0.0f);
}
-AffineTransform& AffineTransform::skewY(double angle)
+TransformationMatrix& TransformationMatrix::skewY(double angle)
{
return shear(0.0f, tan(deg2rad(angle)));
}
-AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
+TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
{
- AffineTransform transform;
+ TransformationMatrix transform;
transform.translate(dest.x() - source.x(), dest.y() - source.y());
transform.scale(dest.width() / source.width(), dest.height() / source.height());
return transform;
}
-IntPoint AffineTransform::mapPoint(const IntPoint& point) const
+IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const
{
double x2, y2;
map(point.x(), point.y(), &x2, &y2);
-
+
// Round the point.
return IntPoint(lround(x2), lround(y2));
}
-FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
+FloatPoint TransformationMatrix::mapPoint(const FloatPoint& point) const
{
double x2, y2;
map(point.x(), point.y(), &x2, &y2);
@@ -160,7 +161,17 @@ FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
}
-void AffineTransform::blend(const AffineTransform& from, double progress)
+FloatQuad TransformationMatrix::mapQuad(const FloatQuad& quad) const
+{
+ // FIXME: avoid 4 seperate library calls. Point mapping really needs
+ // to be platform-independent code.
+ return FloatQuad(mapPoint(quad.p1()),
+ mapPoint(quad.p2()),
+ mapPoint(quad.p3()),
+ mapPoint(quad.p4()));
+}
+
+void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
{
double srA[9], srB[9];
diff --git a/WebCore/platform/graphics/AffineTransform.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h
index 37c6033..db121d1 100644
--- a/WebCore/platform/graphics/AffineTransform.h
+++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h
@@ -20,31 +20,28 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AffineTransform_h
-#define AffineTransform_h
+#ifndef TransformationMatrix_h
+#define TransformationMatrix_h
#if PLATFORM(CG)
#include <CoreGraphics/CGAffineTransform.h>
-typedef CGAffineTransform PlatformAffineTransform;
+typedef CGAffineTransform PlatformTransformationMatrix;
#elif PLATFORM(QT)
#include <QMatrix>
-typedef QMatrix PlatformAffineTransform;
+typedef QMatrix PlatformTransformationMatrix;
#elif PLATFORM(CAIRO)
#include <cairo.h>
-typedef cairo_matrix_t PlatformAffineTransform;
-#elif PLATFORM(SGL)
+typedef cairo_matrix_t PlatformTransformationMatrix;
+#elif PLATFORM(SKIA) || PLATFORM(SGL)
#include "SkMatrix.h"
-typedef SkMatrix PlatformAffineTransform;
-#elif PLATFORM(SKIA)
-#include "SkMatrix.h"
-typedef SkMatrix PlatformAffineTransform;
+typedef SkMatrix PlatformTransformationMatrix;
#elif PLATFORM(WX) && USE(WXGC)
#include <wx/defs.h>
#include <wx/graphics.h>
-typedef wxGraphicsMatrix PlatformAffineTransform;
+typedef wxGraphicsMatrix PlatformTransformationMatrix;
#endif
namespace WebCore {
@@ -53,13 +50,14 @@ class IntPoint;
class IntRect;
class FloatPoint;
class FloatRect;
+class FloatQuad;
-class AffineTransform {
+class TransformationMatrix {
public:
- AffineTransform();
- AffineTransform(double a, double b, double c, double d, double e, double f);
+ TransformationMatrix();
+ TransformationMatrix(double a, double b, double c, double d, double e, double f);
#if !PLATFORM(WX) || USE(WXGC)
- AffineTransform(const PlatformAffineTransform&);
+ TransformationMatrix(const PlatformTransformationMatrix&);
#endif
void setMatrix(double a, double b, double c, double d, double e, double f);
@@ -76,6 +74,8 @@ public:
FloatRect mapRect(const FloatRect&) const;
+ FloatQuad mapQuad(const FloatQuad&) const;
+
bool isIdentity() const;
double a() const;
@@ -98,43 +98,43 @@ public:
void reset();
- AffineTransform& multiply(const AffineTransform&);
- AffineTransform& scale(double);
- AffineTransform& scale(double sx, double sy);
- AffineTransform& scaleNonUniform(double sx, double sy);
- AffineTransform& rotate(double d);
- AffineTransform& rotateFromVector(double x, double y);
- AffineTransform& translate(double tx, double ty);
- AffineTransform& shear(double sx, double sy);
- AffineTransform& flipX();
- AffineTransform& flipY();
- AffineTransform& skew(double angleX, double angleY);
- AffineTransform& skewX(double angle);
- AffineTransform& skewY(double angle);
-
+ TransformationMatrix& multiply(const TransformationMatrix&);
+ TransformationMatrix& scale(double);
+ TransformationMatrix& scale(double sx, double sy);
+ TransformationMatrix& scaleNonUniform(double sx, double sy);
+ TransformationMatrix& rotate(double d);
+ TransformationMatrix& rotateFromVector(double x, double y);
+ TransformationMatrix& translate(double tx, double ty);
+ TransformationMatrix& shear(double sx, double sy);
+ TransformationMatrix& flipX();
+ TransformationMatrix& flipY();
+ TransformationMatrix& skew(double angleX, double angleY);
+ TransformationMatrix& skewX(double angle);
+ TransformationMatrix& skewY(double angle);
+
double det() const;
bool isInvertible() const;
- AffineTransform inverse() const;
+ TransformationMatrix inverse() const;
- void blend(const AffineTransform& from, double progress);
+ void blend(const TransformationMatrix& from, double progress);
#if !PLATFORM(WX) || USE(WXGC)
- operator PlatformAffineTransform() const;
+ operator PlatformTransformationMatrix() const;
#endif
- bool operator==(const AffineTransform&) const;
- bool operator!=(const AffineTransform& other) const { return !(*this == other); }
- AffineTransform& operator*=(const AffineTransform&);
- AffineTransform operator*(const AffineTransform&);
-
+ bool operator==(const TransformationMatrix&) const;
+ bool operator!=(const TransformationMatrix& other) const { return !(*this == other); }
+ TransformationMatrix& operator*=(const TransformationMatrix&);
+ TransformationMatrix operator*(const TransformationMatrix&);
+
private:
#if !PLATFORM(WX) || USE(WXGC)
- PlatformAffineTransform m_transform;
+ PlatformTransformationMatrix m_transform;
#endif
};
-AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest);
+TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest);
} // namespace WebCore
-#endif // AffineTransform_h
+#endif // TransformationMatrix_h
diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
new file mode 100644
index 0000000..47471c4
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 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.
+ *
+ */
+
+#include "config.h"
+#include "TranslateTransformOperation.h"
+
+namespace WebCore {
+
+PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity)
+{
+ if (from && !from->isSameType(*this))
+ return this;
+
+ if (blendToIdentity)
+ return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress), Length(m_y.type()).blend(m_y, progress), m_type);
+
+ const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from);
+ Length fromX = fromOp ? fromOp->m_x : Length(m_x.type());
+ Length fromY = fromOp ? fromOp->m_y : Length(m_y.type());
+ return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_type);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
new file mode 100644
index 0000000..61ccbcc
--- /dev/null
+++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TranslateTransformOperation_h
+#define TranslateTransformOperation_h
+
+#include "Length.h"
+#include "TransformOperation.h"
+
+namespace WebCore {
+
+class TranslateTransformOperation : public TransformOperation {
+public:
+ static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, OperationType type)
+ {
+ return adoptRef(new TranslateTransformOperation(tx, ty, type));
+ }
+
+ virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0; }
+ virtual OperationType getOperationType() const { return m_type; }
+ virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; }
+
+ virtual bool operator==(const TransformOperation& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const TranslateTransformOperation* t = static_cast<const TranslateTransformOperation*>(&o);
+ return m_x == t->m_x && m_y == t->m_y;
+ }
+
+ virtual bool apply(TransformationMatrix& transform, const IntSize& borderBoxSize) const
+ {
+ transform.translate(m_x.calcFloatValue(borderBoxSize.width()), m_y.calcFloatValue(borderBoxSize.height()));
+ return m_x.type() == Percent || m_y.type() == Percent;
+ }
+
+ virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false);
+
+private:
+ TranslateTransformOperation(const Length& tx, const Length& ty, OperationType type)
+ : m_x(tx)
+ , m_y(ty)
+ , m_type(type)
+ {
+ }
+
+ Length m_x;
+ Length m_y;
+ OperationType m_type;
+};
+
+} // namespace WebCore
+
+#endif // TranslateTransformOperation_h
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
index 1766cd9..9ca95f3 100644
--- a/WebCore/platform/graphics/win/FontCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 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
@@ -26,7 +26,7 @@
#include "config.h"
#include "Font.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatConversion.h"
#include "GlyphBuffer.h"
#include "GraphicsContext.h"
@@ -227,7 +227,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
XFORM xform;
GetWorldTransform(hdc, &xform);
- AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy);
+ TransformationMatrix hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy);
CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity;
if (font->platformData().syntheticOblique())
initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0));
@@ -294,14 +294,18 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
int from, int numGlyphs, const FloatPoint& point) const
{
- if (font->m_font.useGDI()) {
- drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
- return;
- }
-
CGContextRef cgContext = graphicsContext->platformContext();
+ bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();
+
+ if (font->platformData().useGDI()) {
+ static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs();
+ if (!canUsePlatformNativeGlyphs || !shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) {
+ drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
+ return;
+ }
+ }
- uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, WebCoreShouldUseFontSmoothing());
+ uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing);
const FontPlatformData& platformData = font->platformData();
@@ -322,7 +326,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
FloatSize translation = glyphBuffer.offsetAt(from);
CGContextSetFontSize(cgContext, platformData.size());
- wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false);
+ wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI());
IntSize shadowSize;
int shadowBlur;
diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp
index 49b3d76..9acc5a0 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -134,7 +134,7 @@ static const Vector<DWORD, 4>& getCJKCodePageMasks()
static bool initialized;
if (!initialized) {
initialized = true;
- IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface();
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
if (!langFontLink)
return codePageMasks;
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
index 26fceba..ba8afe7 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009 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
@@ -27,6 +27,7 @@
#include "SharedBuffer.h"
#include "SoftLinking.h"
#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
#include <wtf/RetainPtr.h>
// From t2embapi.h, which is missing from the Microsoft Platform SDK.
@@ -64,7 +65,10 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
ASSERT(m_fontReference);
ASSERT(T2embedLibrary());
- LOGFONT logFont;
+ static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs();
+ LOGFONT _logFont;
+
+ LOGFONT& logFont = canUsePlatformNativeGlyphs ? *static_cast<LOGFONT*>(malloc(sizeof(LOGFONT))) : _logFont;
if (m_name.isNull())
TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
else
@@ -86,6 +90,8 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b
logFont.lfWeight = bold ? 700 : 400;
HFONT hfont = CreateFontIndirect(&logFont);
+ if (canUsePlatformNativeGlyphs)
+ wkSetFontPlatformInfo(m_cgFont, &logFont, free);
return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode);
}
diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h
index d61afa8..09a8b55 100644
--- a/WebCore/platform/graphics/win/FontPlatformData.h
+++ b/WebCore/platform/graphics/win/FontPlatformData.h
@@ -45,6 +45,7 @@ public:
FontPlatformData()
#if PLATFORM(CAIRO)
: m_fontFace(0)
+ , m_scaledFont(0)
,
#else
:
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
index bbfdb9f..c7e59ab 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -2,7 +2,7 @@
* 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, 2008 Apple Inc.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -27,6 +27,7 @@
#include "PlatformString.h"
#include "StringHash.h"
#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
#include <wtf/HashMap.h>
#include <wtf/RetainPtr.h>
#include <wtf/Vector.h>
@@ -119,6 +120,11 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR*
ASSERT(m_cgFont);
}
}
+ if (m_useGDI && wkCanUsePlatformNativeGlyphs()) {
+ LOGFONT* logfont = static_cast<LOGFONT*>(malloc(sizeof(LOGFONT)));
+ GetObject(font, sizeof(*logfont), logfont);
+ wkSetFontPlatformInfo(m_cgFont.get(), logfont, free);
+ }
}
FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI)
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index 5a4279a..dccbe6c 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "GraphicsContext.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "NotImplemented.h"
#include "Path.h"
@@ -173,6 +173,16 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
m_data->restore();
}
+void GraphicsContext::setShouldIncludeChildWindows(bool include)
+{
+ m_data->m_shouldIncludeChildWindows = include;
+}
+
+bool GraphicsContext::shouldIncludeChildWindows() const
+{
+ return m_data->m_shouldIncludeChildWindows;
+}
+
GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
: m_hdc(0)
, m_size(size)
@@ -222,14 +232,16 @@ GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize siz
void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
{
RetainPtr<CGColorSpaceRef> deviceRGB(AdoptCF, CGColorSpaceCreateDeviceRGB());
- RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, image->buffer(), image->bufferLength(), kCFAllocatorNull));
+ // FIXME: Creating CFData is non-optimal, but needed to avoid crashing when printing. Ideally we should
+ // make a custom CGDataProvider that controls the WindowsBitmap lifetime. see <rdar://6394455>
+ RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreate(kCFAllocatorDefault, image->buffer(), image->bufferLength()));
RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(imageData.get()));
RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(image->size().width(), image->size().height(), 8, 32, image->bytesPerRow(), deviceRGB.get(),
kCGBitmapByteOrder32Little | kCGImageAlphaFirst, dataProvider.get(), 0, true, kCGRenderingIntentDefault));
CGContextDrawImage(m_data->m_cgContext, CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get());
}
-void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform)
{
if (!m_hdc)
return;
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index 3dcf6ba..892d24a 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "GraphicsContext.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "NotImplemented.h"
#include "Path.h"
@@ -102,7 +102,7 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
cairo_surface_mark_dirty(surface);
}
-void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform)
{
cairo_surface_t* surface = cairo_get_target(cr);
HDC hdc = cairo_win32_surface_get_dc(surface);
diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
index dbf9fad..b3ebcb0 100644
--- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -32,7 +32,7 @@
#include "GraphicsContextPlatformPrivateCairo.h"
#endif
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "NotImplemented.h"
#include "Path.h"
#include <wtf/MathExtras.h>
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index cef4217..1b09e1f 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 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
@@ -239,8 +239,9 @@ IntSize MediaPlayerPrivate::naturalSize() const
bool MediaPlayerPrivate::hasVideo() const
{
- // This is not used at the moment
- return true;
+ if (!m_qtMovie)
+ return false;
+ return m_qtMovie->hasVideo();
}
void MediaPlayerPrivate::setVolume(float volume)
diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp
index 8eee41b..32aecd3 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 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
@@ -710,6 +710,14 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount)
}
}
+
+bool QTMovieWin::hasVideo() const
+{
+ if (!m_private->m_movie)
+ return false;
+ return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));
+}
+
pascal OSErr movieDrawingCompleteProc(Movie movie, long data)
{
UppParam param;
diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h
index e31780a..2186974 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.h
+++ b/WebCore/platform/graphics/win/QTMovieWin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 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
@@ -86,6 +86,8 @@ public:
void disableUnsupportedTracks(unsigned& enabledTrackCount);
+ bool hasVideo() const;
+
static unsigned countSupportedTypes();
static void getSupportedType(unsigned index, const UChar*& str, unsigned& len);
diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
index 0e9f9fb..9d5c3b9 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -91,6 +91,7 @@ void SimpleFontData::platformCommonDestroy()
{
// We don't hash this on Win32, so it's effectively owned by us.
delete m_smallCapsFontData;
+ m_smallCapsFontData = 0;
ScriptFreeCache(&m_scriptCache);
delete m_scriptFontProperties;
@@ -124,7 +125,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con
// 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?
- IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface();
+ IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface();
if (!langFontLink)
return false;
@@ -176,6 +177,7 @@ void SimpleFontData::determinePitch()
float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
{
HDC hdc = GetDC(0);
+ SetGraphicsMode(hdc, GM_ADVANCED);
HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
int width;
GetCharWidthI(hdc, glyph, 1, 0, &width);
diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h
index e3a3cce..d2394dc 100644
--- a/WebCore/platform/graphics/wx/FontPlatformData.h
+++ b/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -81,7 +81,7 @@ public:
bool operator==(const FontPlatformData& other) const
{
if (m_fontState == VALID)
- return other.m_fontState == VALID && m_font.Ok() && other.m_font.Ok() && m_font.IsSameAs(other.m_font);
+ return other.m_fontState == VALID && m_font.IsOk() && other.m_font.IsOk() && m_font.IsSameAs(other.m_font);
else
return m_fontState == other.m_fontState;
}
@@ -89,7 +89,7 @@ public:
bool isHashTableDeletedValue() const { return m_fontState == DELETED; }
unsigned computeHash() const {
- ASSERT(m_font.Ok());
+ ASSERT(m_font.IsOk());
// make a hash that is unique for this font, but not globally unique - that is,
// a font whose properties are equal should generate the same hash
diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
index 435e7ce..59e388e 100644
--- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "GraphicsContext.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatRect.h"
#include "Font.h"
#include "IntRect.h"
@@ -284,7 +284,7 @@ void GraphicsContext::clip(const FloatRect& r)
wxPoint pos(0, 0);
if (windc) {
-#ifndef __WXGTK__
+#if !defined(__WXGTK__) || wxCHECK_VERSION(2,9,0)
wxWindow* window = windc->GetWindow();
#else
wxWindow* window = windc->m_owner;
@@ -349,10 +349,10 @@ void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
notImplemented();
}
-AffineTransform GraphicsContext::getCTM() const
+TransformationMatrix GraphicsContext::getCTM() const
{
notImplemented();
- return AffineTransform();
+ return TransformationMatrix();
}
void GraphicsContext::translate(float tx, float ty)
@@ -414,7 +414,13 @@ void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
void GraphicsContext::setCompositeOperation(CompositeOperator op)
{
if (m_data->context)
+ {
+#if wxCHECK_VERSION(2,9,0)
+ m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false)));
+#else
m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
+#endif
+ }
}
void GraphicsContext::beginPath()
@@ -455,7 +461,7 @@ void GraphicsContext::setPlatformFillColor(const Color& color)
m_data->context->SetBrush(wxBrush(color));
}
-void GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContext::concatCTM(const TransformationMatrix& transform)
{
if (paintingDisabled())
return;
@@ -464,7 +470,7 @@ void GraphicsContext::concatCTM(const AffineTransform& transform)
return;
}
-void GraphicsContext::setUseAntialiasing(bool enable)
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
{
if (paintingDisabled())
return;
diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
index 3ce4f2a..d523354 100644
--- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
@@ -30,6 +30,7 @@
#include "GIFImageDecoder.h"
#include "ICOImageDecoder.h"
#include "JPEGImageDecoder.h"
+#include "NotImplemented.h"
#include "PNGImageDecoder.h"
#include "SharedBuffer.h"
#include "XBMImageDecoder.h"
@@ -92,7 +93,7 @@ ImageSource::ImageSource()
ImageSource::~ImageSource()
{
- delete m_decoder;
+ clear(true);
}
bool ImageSource::initialized() const
@@ -141,6 +142,12 @@ int ImageSource::repetitionCount()
return m_decoder->repetitionCount();
}
+String ImageSource::filenameExtension() const
+{
+ notImplemented();
+ return String();
+}
+
size_t ImageSource::frameCount() const
{
return m_decoder ? m_decoder->frameCount() : 0;
@@ -152,10 +159,18 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index)
return (m_decoder && m_decoder->frameBufferAtIndex(index) != 0);
}
-void ImageSource::clear()
+void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived)
{
- delete m_decoder;
+ if (!destroyAll) {
+ if (m_decoder)
+ m_decoder->clearFrameBufferCache(clearBeforeFrame);
+ return;
+ }
+
+ delete m_decoder;
m_decoder = 0;
+ if (data)
+ setData(data, allDataReceived);
}
NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
@@ -205,8 +220,9 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
}
}
-
+#if !wxCHECK_VERSION(2,9,0)
bmp->UseAlpha();
+#endif
ASSERT(bmp->IsOk());
return bmp;
}
diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp
index a05a31f..e52e9ff 100644
--- a/WebCore/platform/graphics/wx/ImageWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageWx.cpp
@@ -26,7 +26,7 @@
#include "config.h"
#include "Image.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "BitmapImage.h"
#include "FloatRect.h"
#include "GraphicsContext.h"
@@ -52,15 +52,17 @@ namespace WebCore {
// this is in GraphicsContextWx.cpp
int getWxCompositingOperation(CompositeOperator op, bool hasAlpha);
-void FrameData::clear()
+bool FrameData::clear(bool clearMetadata)
{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
if (m_frame) {
delete m_frame;
m_frame = 0;
- // NOTE: We purposefully don't reset metadata here, so that even if we
- // throw away previously-decoded data, animation loops can still access
- // properties like frame durations without re-decoding.
+ return true;
}
+ return false;
}
// ================================================
@@ -95,6 +97,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR
#if USE(WXGC)
wxGCDC* context = (wxGCDC*)ctxt->platformContext();
+ wxGraphicsContext* gc = context->GetGraphicsContext();
#else
wxWindowDC* context = ctxt->platformContext();
#endif
@@ -114,7 +117,29 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR
// Set the compositing operation.
ctxt->setCompositeOperation(op);
+
+#if USE(WXGC)
+ float scaleX = src.width() / dst.width();
+ float scaleY = src.height() / dst.height();
+ FloatRect adjustedDestRect = dst;
+ FloatSize selfSize = currentFrameSize();
+
+ if (src.size() != selfSize) {
+ adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY));
+ adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY));
+ }
+
+ // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly.
+ int currHeight = bitmap->GetHeight();
+ if (currHeight < selfSize.height())
+ adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height());
+
+ gc->PushState();
+ gc->Clip(dst.x(), dst.y(), dst.width(), dst.height());
+ gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height());
+ gc->PopState();
+#else
IntRect srcIntRect(src);
IntRect dstIntRect(dst);
bool rescaling = false;
@@ -124,7 +149,8 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR
wxImage img = bitmap->ConvertToImage();
img.Rescale(dstIntRect.width(), dstIntRect.height());
bitmap = new wxBitmap(img);
- }
+ }
+
wxMemoryDC mydc;
ASSERT(bitmap->GetRefData());
mydc.SelectObject(*bitmap);
@@ -143,10 +169,12 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR
delete bitmap;
bitmap = NULL;
}
+#endif
+
ctxt->restore();
}
-void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect)
+void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect)
{
if (!m_source.initialized())
return;
@@ -169,23 +197,33 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c
#if USE(WXGC)
wxGraphicsContext* gc = context->GetGraphicsContext();
gc->ConcatTransform(patternTransform);
-#endif
-
+#else
wxMemoryDC mydc;
mydc.SelectObject(*bitmap);
+#endif
- while ( currentW < dstRect.width() ) {
- while ( currentH < dstRect.height() ) {
+ wxPoint origin(context->GetDeviceOrigin());
+ wxSize clientSize(context->GetSize());
+
+ while ( currentW < dstRect.width() && currentW < clientSize.x - origin.x ) {
+ while ( currentH < dstRect.height() && currentH < clientSize.y - origin.y) {
+#if USE(WXGC)
+ gc->DrawBitmap(*bitmap, (wxDouble)dstRect.x() + currentW, (wxDouble)dstRect.y() + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height());
+#else
context->Blit((wxCoord)dstRect.x() + currentW, (wxCoord)dstRect.y() + currentH,
(wxCoord)srcRect.width(), (wxCoord)srcRect.height(), &mydc,
(wxCoord)srcRect.x(), (wxCoord)srcRect.y(), wxCOPY, true);
+#endif
currentH += srcRect.height();
}
currentW += srcRect.width();
currentH = 0;
}
ctxt->restore();
+
+#if !USE(WXGC)
mydc.SelectObject(wxNullBitmap);
+#endif
// NB: delete is causing crashes during page load, but not during the deletion
// itself. It occurs later on when a valid bitmap created in frameAtIndex
diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp
index 5ff9914..60c71d5 100644
--- a/WebCore/platform/graphics/wx/PathWx.cpp
+++ b/WebCore/platform/graphics/wx/PathWx.cpp
@@ -26,10 +26,11 @@
#include "config.h"
#include "Path.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatPoint.h"
#include "FloatRect.h"
#include "NotImplemented.h"
+#include "StrokeStyleApplier.h"
#include <stdio.h>
@@ -64,7 +65,7 @@ Path::Path()
}
Path::~Path()
-{
+{
}
Path::Path(const Path& path)
@@ -73,7 +74,16 @@ Path::Path(const Path& path)
}
bool Path::contains(const FloatPoint& point, const WindRule rule) const
-{
+{
+#if USE(WXGC)
+ if (m_path) {
+#if wxCHECK_VERSION(2,9,0)
+ return m_path->Contains(point.x(), point.y(), static_cast<wxPolygonFillMode>(getWxWindRuleForWindRule(rule)));
+#else
+ return m_path->Contains(point.x(), point.y(), getWxWindRuleForWindRule(rule));
+#endif
+ }
+#endif
return false;
}
@@ -93,6 +103,12 @@ FloatRect Path::boundingRect() const
return FloatRect();
}
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ notImplemented();
+ return FloatRect();
+}
+
Path& Path::operator=(const Path&)
{
notImplemented();
@@ -121,60 +137,93 @@ void Path::moveTo(const FloatPoint& point)
#endif
}
-void Path::addLineTo(const FloatPoint&)
-{
- notImplemented();
+void Path::addLineTo(const FloatPoint& point)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddLineToPoint(point.x(), point.y());
+#endif
}
-void Path::addQuadCurveTo(const FloatPoint&, const FloatPoint&)
-{
- notImplemented();
+void Path::addQuadCurveTo(const FloatPoint& control, const FloatPoint& end)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddQuadCurveToPoint(control.x(), control.y(), end.x(), end.y());
+#endif
}
-void Path::addBezierCurveTo(const FloatPoint&, const FloatPoint&, const FloatPoint&)
-{
- notImplemented();
+void Path::addBezierCurveTo(const FloatPoint& control1, const FloatPoint& control2, const FloatPoint& end)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddCurveToPoint(control1.x(), control1.y(), control2.x(), control2.y(), end.x(), end.y());
+#endif
}
-void Path::addArcTo(const FloatPoint&, const FloatPoint&, float)
-{
- notImplemented();
+void Path::addArcTo(const FloatPoint& point1, const FloatPoint& point2, float radius)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddArcToPoint(point1.x(), point1.y(), point2.x(), point2.y(), radius);
+#endif
}
void Path::closeSubpath()
-{
- notImplemented();
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->CloseSubpath();
+#endif
}
-void Path::addArc(const FloatPoint&, float, float, float, bool)
-{
- notImplemented();
+void Path::addArc(const FloatPoint& point, float radius, float startAngle, float endAngle, bool clockwise)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddArc(point.x(), point.y(), radius, startAngle, endAngle, clockwise);
+#endif
}
-void Path::addRect(const FloatRect&)
-{
- notImplemented();
+void Path::addRect(const FloatRect& rect)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddRectangle(rect.x(), rect.y(), rect.width(), rect.height());
+#endif
}
-void Path::addEllipse(const FloatRect&)
-{
- notImplemented();
+void Path::addEllipse(const FloatRect& rect)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->AddEllipse(rect.x(), rect.y(), rect.width(), rect.height());
+#endif
}
-void Path::transform(const AffineTransform&)
-{
- notImplemented();
+void Path::transform(const TransformationMatrix& transform)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->Transform(transform);
+#endif
}
void Path::apply(void* info, PathApplierFunction function) const
-{
+{
notImplemented();
}
bool Path::isEmpty() const
{
- notImplemented();
- return false;
+#if USE(WXGC)
+ if (m_path) {
+ wxDouble width, height;
+ m_path->GetBox(NULL, NULL, &width, &height);
+ return (width == 0 && height == 0);
+ }
+#endif
+ return true;
}
}
diff --git a/WebCore/platform/graphics/wx/AffineTransformWx.cpp b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
index 12485ae..e6a02b8 100644
--- a/WebCore/platform/graphics/wx/AffineTransformWx.cpp
+++ b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp
@@ -20,11 +20,11 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
-#include "AffineTransform.h"
+#include "TransformationMatrix.h"
#include "FloatRect.h"
#include "IntRect.h"
@@ -37,105 +37,125 @@
namespace WebCore {
#if USE(WXGC)
-AffineTransform::AffineTransform(const PlatformAffineTransform& matrix)
+TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix)
{
m_transform = matrix;
}
#endif
-AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
+TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f)
{
#if USE(WXGC)
- wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
m_transform = renderer->CreateMatrix();
#endif
setMatrix(a, b, c, d, e, f);
}
-AffineTransform::AffineTransform()
-{
+TransformationMatrix::TransformationMatrix()
+{
// NB: If we ever support using Cairo backend on Win/Mac, this will need to be
// changed somehow (though I'm not sure how as we don't have a reference to the
// graphics context here.
#if USE(WXGC)
- wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
m_transform = renderer->CreateMatrix();
#endif
}
-AffineTransform AffineTransform::inverse() const
+TransformationMatrix TransformationMatrix::inverse() const
{
notImplemented();
return *this;
}
-void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
+void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f)
{
#if USE(WXGC)
m_transform.Set(a, b, c, d, e, f);
#endif
}
-void AffineTransform::map(double x, double y, double *x2, double *y2) const
-{
+void TransformationMatrix::map(double x, double y, double *x2, double *y2) const
+{
notImplemented();
}
-IntRect AffineTransform::mapRect(const IntRect &rect) const
+IntRect TransformationMatrix::mapRect(const IntRect &rect) const
{
- notImplemented();
+#if USE(WXGC)
+ double x, y, width, height;
+ x = rect.x();
+ y = rect.y();
+ width = rect.width();
+ height = rect.height();
+
+ m_transform.TransformPoint(&x, &y);
+ m_transform.TransformDistance(&width, &height);
+ return IntRect(x, y, width, height);
+#endif
return IntRect();
}
-FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const
{
- notImplemented();
+#if USE(WXGC)
+ double x, y, width, height;
+ x = rect.x();
+ y = rect.y();
+ width = rect.width();
+ height = rect.height();
+
+ m_transform.TransformPoint(&x, &y);
+ m_transform.TransformDistance(&width, &height);
+ return FloatRect(x, y, width, height);
+#endif
return FloatRect();
}
-AffineTransform& AffineTransform::scale(double sx, double sy)
+TransformationMatrix& TransformationMatrix::scale(double sx, double sy)
{
#if USE(WXGC)
- m_transform.Scale((wxDouble)sx, (wxDouble)sy);
+ m_transform.Scale((wxDouble)sx, (wxDouble)sy);
#endif
- return *this;
+ return *this;
}
-void AffineTransform::reset()
+void TransformationMatrix::reset()
{
notImplemented();
}
-AffineTransform& AffineTransform::rotate(double d)
-{
+TransformationMatrix& TransformationMatrix::rotate(double d)
+{
#if USE(WXGC)
- m_transform.Rotate((wxDouble)d);
+ m_transform.Rotate((wxDouble)d);
#endif
- return *this;
+ return *this;
}
-AffineTransform& AffineTransform::translate(double tx, double ty)
-{
+TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
+{
#if USE(WXGC)
- m_transform.Translate((wxDouble)tx, (wxDouble)ty);
+ m_transform.Translate((wxDouble)tx, (wxDouble)ty);
#endif
- return *this;
+ return *this;
}
-AffineTransform& AffineTransform::shear(double sx, double sy)
-{
- notImplemented();
- return *this;
+TransformationMatrix& TransformationMatrix::shear(double sx, double sy)
+{
+ notImplemented();
+ return *this;
}
-AffineTransform& AffineTransform::operator*=(const AffineTransform& other)
-{
+TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other)
+{
notImplemented();
- return *this;
+ return *this;
}
-bool AffineTransform::operator== (const AffineTransform &other) const
+bool TransformationMatrix::operator== (const TransformationMatrix &other) const
{
#if USE(WXGC)
return m_transform.IsEqual((wxGraphicsMatrix)other);
@@ -145,26 +165,26 @@ bool AffineTransform::operator== (const AffineTransform &other) const
#endif
}
-AffineTransform AffineTransform::operator* (const AffineTransform &other)
+TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &other)
{
notImplemented();
return *this; //m_transform * other.m_transform;
}
-double AffineTransform::det() const
-{
- notImplemented();
+double TransformationMatrix::det() const
+{
+ notImplemented();
return 0;
}
#if USE(WXGC)
-AffineTransform::operator wxGraphicsMatrix() const
+TransformationMatrix::operator wxGraphicsMatrix() const
{
return m_transform;
}
#endif
-double AffineTransform::a() const
+double TransformationMatrix::a() const
{
double a = 0;
#if USE(WXGC)
@@ -173,12 +193,12 @@ double AffineTransform::a() const
return a;
}
-void AffineTransform::setA(double a)
+void TransformationMatrix::setA(double a)
{
setMatrix(a, b(), c(), d(), e(), f());
}
-double AffineTransform::b() const
+double TransformationMatrix::b() const
{
double b = 0;
#if USE(WXGC)
@@ -187,12 +207,12 @@ double AffineTransform::b() const
return b;
}
-void AffineTransform::setB(double b)
+void TransformationMatrix::setB(double b)
{
setMatrix(a(), b, c(), d(), e(), f());
}
-double AffineTransform::c() const
+double TransformationMatrix::c() const
{
double c = 0;
#if USE(WXGC)
@@ -201,12 +221,12 @@ double AffineTransform::c() const
return c;
}
-void AffineTransform::setC(double c)
+void TransformationMatrix::setC(double c)
{
setMatrix(a(), b(), c, d(), e(), f());
}
-double AffineTransform::d() const
+double TransformationMatrix::d() const
{
double d = 0;
#if USE(WXGC)
@@ -215,12 +235,12 @@ double AffineTransform::d() const
return d;
}
-void AffineTransform::setD(double d)
+void TransformationMatrix::setD(double d)
{
setMatrix(a(), b(), c(), d, e(), f());
}
-double AffineTransform::e() const
+double TransformationMatrix::e() const
{
double e = 0;
#if USE(WXGC)
@@ -229,12 +249,12 @@ double AffineTransform::e() const
return e;
}
-void AffineTransform::setE(double e)
+void TransformationMatrix::setE(double e)
{
setMatrix(a(), b(), c(), d(), e, f());
}
-double AffineTransform::f() const
+double TransformationMatrix::f() const
{
double f = 0;
#if USE(WXGC)
@@ -243,7 +263,7 @@ double AffineTransform::f() const
return f;
}
-void AffineTransform::setF(double f)
+void TransformationMatrix::setF(double f)
{
setMatrix(a(), b(), c(), d(), e(), f);
}