summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/AffineTransform.cpp194
-rw-r--r--WebCore/platform/graphics/AffineTransform.h140
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp438
-rw-r--r--WebCore/platform/graphics/BitmapImage.h258
-rw-r--r--WebCore/platform/graphics/Color.cpp306
-rw-r--r--WebCore/platform/graphics/Color.h156
-rw-r--r--WebCore/platform/graphics/DashArray.h39
-rw-r--r--WebCore/platform/graphics/FloatPoint.cpp52
-rw-r--r--WebCore/platform/graphics/FloatPoint.h151
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.cpp85
-rw-r--r--WebCore/platform/graphics/FloatPoint3D.h55
-rw-r--r--WebCore/platform/graphics/FloatRect.cpp122
-rw-r--r--WebCore/platform/graphics/FloatRect.h184
-rw-r--r--WebCore/platform/graphics/FloatSize.cpp44
-rw-r--r--WebCore/platform/graphics/FloatSize.h125
-rw-r--r--WebCore/platform/graphics/Font.cpp626
-rw-r--r--WebCore/platform/graphics/Font.h210
-rw-r--r--WebCore/platform/graphics/FontCache.cpp425
-rw-r--r--WebCore/platform/graphics/FontCache.h95
-rw-r--r--WebCore/platform/graphics/FontData.cpp35
-rw-r--r--WebCore/platform/graphics/FontData.h60
-rw-r--r--WebCore/platform/graphics/FontDescription.cpp101
-rw-r--r--WebCore/platform/graphics/FontDescription.h139
-rw-r--r--WebCore/platform/graphics/FontFallbackList.cpp134
-rw-r--r--WebCore/platform/graphics/FontFallbackList.h79
-rw-r--r--WebCore/platform/graphics/FontFamily.cpp59
-rw-r--r--WebCore/platform/graphics/FontFamily.h88
-rw-r--r--WebCore/platform/graphics/FontRenderingMode.h37
-rw-r--r--WebCore/platform/graphics/FontSelector.h47
-rw-r--r--WebCore/platform/graphics/FontTraitsMask.h70
-rw-r--r--WebCore/platform/graphics/GeneratedImage.cpp68
-rw-r--r--WebCore/platform/graphics/GeneratedImage.h77
-rw-r--r--WebCore/platform/graphics/Generator.h45
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h182
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.cpp384
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.h177
-rw-r--r--WebCore/platform/graphics/GlyphWidthMap.cpp79
-rw-r--r--WebCore/platform/graphics/GlyphWidthMap.h74
-rw-r--r--WebCore/platform/graphics/Gradient.cpp149
-rw-r--r--WebCore/platform/graphics/Gradient.h121
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp507
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h381
-rw-r--r--WebCore/platform/graphics/GraphicsContextPrivate.h112
-rw-r--r--WebCore/platform/graphics/GraphicsTypes.cpp189
-rw-r--r--WebCore/platform/graphics/GraphicsTypes.h80
-rw-r--r--WebCore/platform/graphics/Icon.h86
-rw-r--r--WebCore/platform/graphics/Image.cpp198
-rw-r--r--WebCore/platform/graphics/Image.h186
-rw-r--r--WebCore/platform/graphics/ImageBuffer.h85
-rw-r--r--WebCore/platform/graphics/ImageObserver.h48
-rw-r--r--WebCore/platform/graphics/ImageSource.h127
-rw-r--r--WebCore/platform/graphics/IntPoint.h180
-rw-r--r--WebCore/platform/graphics/IntRect.cpp107
-rw-r--r--WebCore/platform/graphics/IntRect.h210
-rw-r--r--WebCore/platform/graphics/IntSize.h157
-rw-r--r--WebCore/platform/graphics/IntSizeHash.h46
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp272
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h137
-rw-r--r--WebCore/platform/graphics/Path.cpp276
-rw-r--r--WebCore/platform/graphics/Path.h135
-rw-r--r--WebCore/platform/graphics/PathTraversalState.cpp207
-rw-r--r--WebCore/platform/graphics/PathTraversalState.h72
-rw-r--r--WebCore/platform/graphics/Pattern.cpp46
-rw-r--r--WebCore/platform/graphics/Pattern.h82
-rw-r--r--WebCore/platform/graphics/Pen.cpp77
-rw-r--r--WebCore/platform/graphics/Pen.h72
-rw-r--r--WebCore/platform/graphics/SegmentedFontData.cpp79
-rw-r--r--WebCore/platform/graphics/SegmentedFontData.h75
-rw-r--r--WebCore/platform/graphics/SimpleFontData.cpp153
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h202
-rw-r--r--WebCore/platform/graphics/StringTruncator.cpp198
-rw-r--r--WebCore/platform/graphics/StringTruncator.h46
-rw-r--r--WebCore/platform/graphics/TextRun.h126
-rw-r--r--WebCore/platform/graphics/UnitBezier.h123
-rw-r--r--WebCore/platform/graphics/WidthIterator.cpp234
-rw-r--r--WebCore/platform/graphics/WidthIterator.h56
-rw-r--r--WebCore/platform/graphics/android/AffineTransformAndroid.cpp218
-rw-r--r--WebCore/platform/graphics/android/FontAndroid.cpp208
-rw-r--r--WebCore/platform/graphics/android/FontCacheAndroid.cpp134
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.cpp78
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.h57
-rw-r--r--WebCore/platform/graphics/android/FontDataAndroid.cpp122
-rw-r--r--WebCore/platform/graphics/android/FontPlatformData.h72
-rw-r--r--WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp176
-rw-r--r--WebCore/platform/graphics/android/GlyphMapAndroid.cpp70
-rw-r--r--WebCore/platform/graphics/android/GradientAndroid.cpp116
-rw-r--r--WebCore/platform/graphics/android/GraphicsContextAndroid.cpp1118
-rw-r--r--WebCore/platform/graphics/android/ImageAndroid.cpp297
-rw-r--r--WebCore/platform/graphics/android/ImageBufferAndroid.cpp216
-rw-r--r--WebCore/platform/graphics/android/ImageBufferData.h40
-rw-r--r--WebCore/platform/graphics/android/ImageSourceAndroid.cpp361
-rw-r--r--WebCore/platform/graphics/android/PathAndroid.cpp268
-rw-r--r--WebCore/platform/graphics/android/PatternAndroid.cpp54
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.cpp77
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.h169
-rw-r--r--WebCore/platform/graphics/android/SkBitmapRef.h62
-rw-r--r--WebCore/platform/graphics/android/android_graphics.cpp228
-rw-r--r--WebCore/platform/graphics/android/android_graphics.h89
-rw-r--r--WebCore/platform/graphics/cairo/AffineTransformCairo.cpp281
-rw-r--r--WebCore/platform/graphics/cairo/CairoPath.h45
-rw-r--r--WebCore/platform/graphics/cairo/FontCairo.cpp105
-rw-r--r--WebCore/platform/graphics/cairo/GradientCairo.cpp74
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp1104
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h101
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp224
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferData.h44
-rw-r--r--WebCore/platform/graphics/cairo/ImageCairo.cpp187
-rw-r--r--WebCore/platform/graphics/cairo/ImageSourceCairo.cpp229
-rw-r--r--WebCore/platform/graphics/cairo/PathCairo.cpp285
-rw-r--r--WebCore/platform/graphics/cairo/PatternCairo.cpp50
-rw-r--r--WebCore/platform/graphics/cairo/rgb24-hacks.txt32
-rw-r--r--WebCore/platform/graphics/cairo/scale-removal.txt13
-rw-r--r--WebCore/platform/graphics/cg/AffineTransformCG.cpp216
-rw-r--r--WebCore/platform/graphics/cg/ColorCG.cpp96
-rw-r--r--WebCore/platform/graphics/cg/FloatPointCG.cpp47
-rw-r--r--WebCore/platform/graphics/cg/FloatRectCG.cpp47
-rw-r--r--WebCore/platform/graphics/cg/FloatSizeCG.cpp47
-rw-r--r--WebCore/platform/graphics/cg/GradientCG.cpp82
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp1144
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h83
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferCG.cpp275
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferData.h42
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp312
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp225
-rw-r--r--WebCore/platform/graphics/cg/IntPointCG.cpp46
-rw-r--r--WebCore/platform/graphics/cg/IntRectCG.cpp51
-rw-r--r--WebCore/platform/graphics/cg/IntSizeCG.cpp46
-rw-r--r--WebCore/platform/graphics/cg/PDFDocumentImage.cpp179
-rw-r--r--WebCore/platform/graphics/cg/PDFDocumentImage.h75
-rw-r--r--WebCore/platform/graphics/cg/PathCG.cpp291
-rw-r--r--WebCore/platform/graphics/cg/PatternCG.cpp77
-rw-r--r--WebCore/platform/graphics/filters/FEBlend.cpp72
-rw-r--r--WebCore/platform/graphics/filters/FEBlend.h64
-rw-r--r--WebCore/platform/graphics/filters/FEColorMatrix.cpp72
-rw-r--r--WebCore/platform/graphics/filters/FEColorMatrix.h64
-rw-r--r--WebCore/platform/graphics/filters/FEComponentTransfer.cpp96
-rw-r--r--WebCore/platform/graphics/filters/FEComponentTransfer.h99
-rw-r--r--WebCore/platform/graphics/filters/FEComposite.cpp108
-rw-r--r--WebCore/platform/graphics/filters/FEComposite.h81
-rw-r--r--WebCore/platform/graphics/gtk/ColorGtk.cpp35
-rw-r--r--WebCore/platform/graphics/gtk/FontCacheGtk.cpp84
-rw-r--r--WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp73
-rw-r--r--WebCore/platform/graphics/gtk/FontCustomPlatformData.h50
-rw-r--r--WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp49
-rw-r--r--WebCore/platform/graphics/gtk/FontGtk.cpp371
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformData.h132
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp210
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp229
-rw-r--r--WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp65
-rw-r--r--WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp98
-rw-r--r--WebCore/platform/graphics/gtk/IconGtk.cpp125
-rw-r--r--WebCore/platform/graphics/gtk/ImageGtk.cpp52
-rw-r--r--WebCore/platform/graphics/gtk/IntPointGtk.cpp41
-rw-r--r--WebCore/platform/graphics/gtk/IntRectGtk.cpp41
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp622
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h135
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp141
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp142
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp312
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.h83
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.h50
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm169
-rw-r--r--WebCore/platform/graphics/mac/CoreTextController.cpp533
-rw-r--r--WebCore/platform/graphics/mac/CoreTextController.h114
-rw-r--r--WebCore/platform/graphics/mac/FloatPointMac.mm45
-rw-r--r--WebCore/platform/graphics/mac/FloatRectMac.mm45
-rw-r--r--WebCore/platform/graphics/mac/FloatSizeMac.mm45
-rw-r--r--WebCore/platform/graphics/mac/FontCacheMac.mm202
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.cpp84
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.h53
-rw-r--r--WebCore/platform/graphics/mac/FontMac.mm122
-rw-r--r--WebCore/platform/graphics/mac/FontMacATSUI.mm623
-rw-r--r--WebCore/platform/graphics/mac/FontMacCoreText.cpp102
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformData.h126
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformDataMac.mm107
-rw-r--r--WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp91
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm165
-rw-r--r--WebCore/platform/graphics/mac/IconMac.mm84
-rw-r--r--WebCore/platform/graphics/mac/ImageMac.mm125
-rw-r--r--WebCore/platform/graphics/mac/IntPointMac.mm44
-rw-r--r--WebCore/platform/graphics/mac/IntRectMac.mm49
-rw-r--r--WebCore/platform/graphics/mac/IntSizeMac.mm44
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h149
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm1024
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm435
-rw-r--r--WebCore/platform/graphics/qt/AffineTransformQt.cpp202
-rw-r--r--WebCore/platform/graphics/qt/ColorQt.cpp48
-rw-r--r--WebCore/platform/graphics/qt/FloatPointQt.cpp48
-rw-r--r--WebCore/platform/graphics/qt/FloatRectQt.cpp49
-rw-r--r--WebCore/platform/graphics/qt/FontCacheQt.cpp56
-rw-r--r--WebCore/platform/graphics/qt/FontCustomPlatformData.cpp56
-rw-r--r--WebCore/platform/graphics/qt/FontCustomPlatformData.h45
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformData.h37
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp706
-rw-r--r--WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp31
-rw-r--r--WebCore/platform/graphics/qt/GradientQt.cpp77
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp1146
-rw-r--r--WebCore/platform/graphics/qt/IconQt.cpp68
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferData.h48
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp115
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp308
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.h99
-rw-r--r--WebCore/platform/graphics/qt/ImageQt.cpp171
-rw-r--r--WebCore/platform/graphics/qt/ImageSourceQt.cpp174
-rw-r--r--WebCore/platform/graphics/qt/IntPointQt.cpp48
-rw-r--r--WebCore/platform/graphics/qt/IntRectQt.cpp48
-rw-r--r--WebCore/platform/graphics/qt/IntSizeQt.cpp49
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp533
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h159
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp278
-rw-r--r--WebCore/platform/graphics/qt/PatternQt.cpp46
-rw-r--r--WebCore/platform/graphics/qt/SimpleFontDataQt.cpp55
-rw-r--r--WebCore/platform/graphics/qt/StillImageQt.cpp65
-rw-r--r--WebCore/platform/graphics/qt/StillImageQt.h59
-rw-r--r--WebCore/platform/graphics/win/ColorSafari.cpp71
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp361
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp525
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp235
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.h56
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp61
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h49
-rw-r--r--WebCore/platform/graphics/win/FontDatabase.cpp150
-rw-r--r--WebCore/platform/graphics/win/FontDatabase.h38
-rw-r--r--WebCore/platform/graphics/win/FontPlatformData.h147
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp134
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp89
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataWin.cpp92
-rw-r--r--WebCore/platform/graphics/win/FontWin.cpp101
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp59
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp72
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp366
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp124
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp126
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp84
-rw-r--r--WebCore/platform/graphics/win/ImageCGWin.cpp85
-rw-r--r--WebCore/platform/graphics/win/ImageCairoWin.cpp89
-rw-r--r--WebCore/platform/graphics/win/ImageWin.cpp58
-rw-r--r--WebCore/platform/graphics/win/IntPointWin.cpp56
-rw-r--r--WebCore/platform/graphics/win/IntRectWin.cpp43
-rw-r--r--WebCore/platform/graphics/win/IntSizeWin.cpp44
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp483
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h128
-rw-r--r--WebCore/platform/graphics/win/OpenTypeUtilities.cpp387
-rw-r--r--WebCore/platform/graphics/win/OpenTypeUtilities.h41
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.cpp875
-rw-r--r--WebCore/platform/graphics/win/QTMovieWin.h97
-rw-r--r--WebCore/platform/graphics/win/QTMovieWinTimer.cpp141
-rw-r--r--WebCore/platform/graphics/win/QTMovieWinTimer.h39
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp141
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp131
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataWin.cpp206
-rw-r--r--WebCore/platform/graphics/win/UniscribeController.cpp434
-rw-r--r--WebCore/platform/graphics/win/UniscribeController.h82
-rw-r--r--WebCore/platform/graphics/wx/AffineTransformWx.cpp251
-rw-r--r--WebCore/platform/graphics/wx/ColorWx.cpp44
-rw-r--r--WebCore/platform/graphics/wx/FloatRectWx.cpp47
-rwxr-xr-xWebCore/platform/graphics/wx/FontCacheWx.cpp72
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformData.h111
-rwxr-xr-xWebCore/platform/graphics/wx/FontPlatformDataWx.cpp107
-rw-r--r--WebCore/platform/graphics/wx/FontWx.cpp78
-rwxr-xr-xWebCore/platform/graphics/wx/GlyphMapWx.cpp59
-rw-r--r--WebCore/platform/graphics/wx/GradientWx.cpp50
-rw-r--r--WebCore/platform/graphics/wx/GraphicsContextWx.cpp503
-rw-r--r--WebCore/platform/graphics/wx/ImageBufferData.h43
-rw-r--r--WebCore/platform/graphics/wx/ImageBufferWx.cpp79
-rw-r--r--WebCore/platform/graphics/wx/ImageSourceWx.cpp244
-rw-r--r--WebCore/platform/graphics/wx/ImageWx.cpp210
-rw-r--r--WebCore/platform/graphics/wx/IntPointWx.cpp45
-rw-r--r--WebCore/platform/graphics/wx/IntRectWx.cpp45
-rw-r--r--WebCore/platform/graphics/wx/PathWx.cpp180
-rw-r--r--WebCore/platform/graphics/wx/PenWx.cpp77
-rwxr-xr-xWebCore/platform/graphics/wx/SimpleFontDataWx.cpp96
272 files changed, 43703 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/AffineTransform.cpp b/WebCore/platform/graphics/AffineTransform.cpp
new file mode 100644
index 0000000..fdeba44
--- /dev/null
+++ b/WebCore/platform/graphics/AffineTransform.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, 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 "AffineTransform.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+static void affineTransformDecompose(const AffineTransform& matrix, double sr[9])
+{
+ AffineTransform m(matrix);
+
+ // Compute scaling factors
+ double sx = sqrt(m.a() * m.a() + m.b() * m.b());
+ double sy = sqrt(m.c() * m.c() + m.d() * m.d());
+
+ /* Compute cross product of transformed unit vectors. If negative,
+ one axis was flipped. */
+
+ if (m.a() * m.d() - m.c() * m.b() < 0.0) {
+ // Flip axis with minimum unit vector dot product
+
+ if (m.a() < m.d())
+ sx = -sx;
+ else
+ sy = -sy;
+ }
+
+ // Remove scale from matrix
+
+ m.scale(1.0 / sx, 1.0 / sy);
+
+ // Compute rotation
+
+ double angle = atan2(m.b(), m.a());
+
+ // Remove rotation from matrix
+
+ m.rotate(rad2deg(-angle));
+
+ // Return results
+
+ sr[0] = sx; sr[1] = sy; sr[2] = angle;
+ sr[3] = m.a(); sr[4] = m.b();
+ sr[5] = m.c(); sr[6] = m.d();
+ sr[7] = m.e(); sr[8] = m.f();
+}
+
+static void affineTransformCompose(AffineTransform& m, const double sr[9])
+{
+ m.setA(sr[3]);
+ m.setB(sr[4]);
+ m.setC(sr[5]);
+ m.setD(sr[6]);
+ m.setE(sr[7]);
+ m.setF(sr[8]);
+ m.rotate(rad2deg(sr[2]));
+ m.scale(sr[0], sr[1]);
+}
+
+bool AffineTransform::isInvertible() const
+{
+ return det() != 0.0;
+}
+
+AffineTransform& AffineTransform::multiply(const AffineTransform& other)
+{
+ return (*this) *= other;
+}
+
+AffineTransform& AffineTransform::scale(double s)
+{
+ return scale(s, s);
+}
+
+AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
+{
+ return scale(sx, sy);
+}
+
+AffineTransform& AffineTransform::rotateFromVector(double x, double y)
+{
+ return rotate(rad2deg(atan2(y, x)));
+}
+
+AffineTransform& AffineTransform::flipX()
+{
+ return scale(-1.0f, 1.0f);
+}
+
+AffineTransform& AffineTransform::flipY()
+{
+ return scale(1.0f, -1.0f);
+}
+
+AffineTransform& AffineTransform::skew(double angleX, double angleY)
+{
+ return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
+}
+
+AffineTransform& AffineTransform::skewX(double angle)
+{
+ return shear(tan(deg2rad(angle)), 0.0f);
+}
+
+AffineTransform& AffineTransform::skewY(double angle)
+{
+ return shear(0.0f, tan(deg2rad(angle)));
+}
+
+AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
+{
+ AffineTransform 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
+{
+ 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
+{
+ double x2, y2;
+ map(point.x(), point.y(), &x2, &y2);
+
+ return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
+}
+
+void AffineTransform::blend(const AffineTransform& from, double progress)
+{
+ double srA[9], srB[9];
+
+ affineTransformDecompose(from, srA);
+ affineTransformDecompose(*this, srB);
+
+ // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
+ if ((srA[0] < 0.0 && srB[1] < 0.0) || (srA[1] < 0.0 && srB[0] < 0.0)) {
+ srA[0] = -srA[0];
+ srA[1] = -srA[1];
+ srA[2] += srA[2] < 0 ? piDouble : -piDouble;
+ }
+
+ // Don't rotate the long way around.
+ srA[2] = fmod(srA[2], 2.0 * piDouble);
+ srB[2] = fmod(srB[2], 2.0 * piDouble);
+
+ if (fabs(srA[2] - srB[2]) > piDouble) {
+ if (srA[2] > srB[2])
+ srA[2] -= piDouble * 2.0;
+ else
+ srB[2] -= piDouble * 2.0;
+ }
+
+ for (int i = 0; i < 9; i++)
+ srA[i] = srA[i] + progress * (srB[i] - srA[i]);
+
+ affineTransformCompose(*this, srA);
+}
+
+}
diff --git a/WebCore/platform/graphics/AffineTransform.h b/WebCore/platform/graphics/AffineTransform.h
new file mode 100644
index 0000000..37c6033
--- /dev/null
+++ b/WebCore/platform/graphics/AffineTransform.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AffineTransform_h
+#define AffineTransform_h
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGAffineTransform.h>
+typedef CGAffineTransform PlatformAffineTransform;
+#elif PLATFORM(QT)
+#include <QMatrix>
+typedef QMatrix PlatformAffineTransform;
+#elif PLATFORM(CAIRO)
+#include <cairo.h>
+typedef cairo_matrix_t PlatformAffineTransform;
+#elif PLATFORM(SGL)
+#include "SkMatrix.h"
+typedef SkMatrix PlatformAffineTransform;
+#elif PLATFORM(SKIA)
+#include "SkMatrix.h"
+typedef SkMatrix PlatformAffineTransform;
+#elif PLATFORM(WX) && USE(WXGC)
+#include <wx/defs.h>
+#include <wx/graphics.h>
+typedef wxGraphicsMatrix PlatformAffineTransform;
+#endif
+
+namespace WebCore {
+
+class IntPoint;
+class IntRect;
+class FloatPoint;
+class FloatRect;
+
+class AffineTransform {
+public:
+ AffineTransform();
+ AffineTransform(double a, double b, double c, double d, double e, double f);
+#if !PLATFORM(WX) || USE(WXGC)
+ AffineTransform(const PlatformAffineTransform&);
+#endif
+
+ void setMatrix(double a, double b, double c, double d, double e, double f);
+ void map(double x, double y, double *x2, double *y2) const;
+
+ // Rounds the mapped point to the nearest integer value.
+ IntPoint mapPoint(const IntPoint&) const;
+
+ FloatPoint mapPoint(const FloatPoint&) const;
+
+ // Rounds the resulting mapped rectangle out. This is helpful for bounding
+ // box computations but may not be what is wanted in other contexts.
+ IntRect mapRect(const IntRect&) const;
+
+ FloatRect mapRect(const FloatRect&) const;
+
+ bool isIdentity() const;
+
+ double a() const;
+ void setA(double a);
+
+ double b() const;
+ void setB(double b);
+
+ double c() const;
+ void setC(double c);
+
+ double d() const;
+ void setD(double d);
+
+ double e() const;
+ void setE(double e);
+
+ double f() const;
+ void setF(double f);
+
+ 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);
+
+ double det() const;
+ bool isInvertible() const;
+ AffineTransform inverse() const;
+
+ void blend(const AffineTransform& from, double progress);
+
+#if !PLATFORM(WX) || USE(WXGC)
+ operator PlatformAffineTransform() const;
+#endif
+
+ bool operator==(const AffineTransform&) const;
+ bool operator!=(const AffineTransform& other) const { return !(*this == other); }
+ AffineTransform& operator*=(const AffineTransform&);
+ AffineTransform operator*(const AffineTransform&);
+
+private:
+#if !PLATFORM(WX) || USE(WXGC)
+ PlatformAffineTransform m_transform;
+#endif
+};
+
+AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest);
+
+} // namespace WebCore
+
+#endif // AffineTransform_h
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
new file mode 100644
index 0000000..4b21de0
--- /dev/null
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006, 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 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 "BitmapImage.h"
+
+#include "FloatRect.h"
+#include "ImageObserver.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include "SystemTime.h"
+#include "Timer.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;
+
+BitmapImage::BitmapImage(ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_desiredFrameStartTime(0)
+ , m_isSolidColor(false)
+ , m_animationFinished(false)
+ , m_allDataReceived(false)
+ , m_haveSize(false)
+ , m_sizeAvailable(false)
+ , m_hasUniformFrameSize(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(false)
+ , m_frameCount(0)
+{
+ initPlatformData();
+}
+
+BitmapImage::~BitmapImage()
+{
+ invalidatePlatformData();
+ stopAnimation();
+}
+
+void BitmapImage::destroyDecodedData(bool incremental, bool preserveNearbyFrames)
+{
+ // 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
+ }
+ }
+}
+
+void BitmapImage::cacheFrame(size_t index)
+{
+ size_t numFrames = frameCount();
+ ASSERT(m_decodedSize == 0 || numFrames > 1);
+
+ if (m_frames.size() < numFrames)
+ m_frames.grow(numFrames);
+
+ m_frames[index].m_frame = m_source.createFrameAtIndex(index);
+ if (numFrames == 1 && m_frames[index].m_frame)
+ checkForSolidColor();
+
+ m_frames[index].m_haveMetadata = true;
+ m_frames[index].m_isComplete = m_source.frameIsCompleteAtIndex(index);
+ if (repetitionCount(false) != cAnimationNone)
+ 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;
+ if (imageObserver())
+ imageObserver()->decodedSizeChanged(this, sizeChange);
+ }
+}
+
+IntSize BitmapImage::size() const
+{
+ if (m_sizeAvailable && !m_haveSize) {
+ m_size = m_source.size();
+ m_haveSize = true;
+ }
+ return m_size;
+}
+
+IntSize BitmapImage::currentFrameSize() const
+{
+ if (!m_currentFrame || m_hasUniformFrameSize)
+ return size();
+ return m_source.frameSizeAtIndex(m_currentFrame);
+}
+
+bool BitmapImage::dataChanged(bool allDataReceived)
+{
+ destroyDecodedData(true);
+
+ // Feed all the data we've seen so far to the image decoder.
+ m_allDataReceived = allDataReceived;
+ m_source.setData(m_data.get(), allDataReceived);
+
+ // Clear the frame count.
+ m_haveFrameCount = false;
+
+ m_hasUniformFrameSize = true;
+
+ // Image properties will not be available until the first frame of the file
+ // reaches kCGImageStatusIncomplete.
+ return isSizeAvailable();
+}
+
+size_t BitmapImage::frameCount()
+{
+ if (!m_haveFrameCount) {
+ m_haveFrameCount = true;
+ m_frameCount = m_source.frameCount();
+ }
+ return m_frameCount;
+}
+
+bool BitmapImage::isSizeAvailable()
+{
+ if (m_sizeAvailable)
+ return true;
+
+ m_sizeAvailable = m_source.isSizeAvailable();
+
+ return m_sizeAvailable;
+}
+
+NativeImagePtr BitmapImage::frameAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index >= m_frames.size() || !m_frames[index].m_frame)
+ cacheFrame(index);
+
+ return m_frames[index].m_frame;
+}
+
+bool BitmapImage::frameIsCompleteAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return true;
+
+ if (index >= m_frames.size() || !m_frames[index].m_haveMetadata)
+ cacheFrame(index);
+
+ return m_frames[index].m_isComplete;
+}
+
+float BitmapImage::frameDurationAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index >= m_frames.size() || !m_frames[index].m_haveMetadata)
+ cacheFrame(index);
+
+ return m_frames[index].m_duration;
+}
+
+bool BitmapImage::frameHasAlphaAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return true;
+
+ if (index >= m_frames.size() || !m_frames[index].m_haveMetadata)
+ cacheFrame(index);
+
+ return m_frames[index].m_hasAlpha;
+}
+
+int BitmapImage::repetitionCount(bool imageKnownToBeComplete)
+{
+ if ((m_repetitionCountStatus == Unknown) || ((m_repetitionCountStatus == Uncertain) && imageKnownToBeComplete)) {
+ // Snag the repetition count. If |imageKnownToBeComplete| is false, the
+ // repetition count may not be accurate yet for GIFs; in this case the
+ // decoder will default to cAnimationLoopOnce, and we'll try and read
+ // the count again once the whole image is decoded.
+ m_repetitionCount = m_source.repetitionCount();
+ m_repetitionCountStatus = (imageKnownToBeComplete || m_repetitionCount == cAnimationNone) ? Certain : Uncertain;
+ }
+ return m_repetitionCount;
+}
+
+bool BitmapImage::shouldAnimate()
+{
+ return (repetitionCount(false) != cAnimationNone && !m_animationFinished && imageObserver());
+}
+
+void BitmapImage::startAnimation(bool catchUpIfNecessary)
+{
+ if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
+ return;
+
+ // Determine time for next frame to start. By ignoring paint and timer lag
+ // in this calculation, we make the animation appear to run at its desired
+ // rate regardless of how fast it's being repainted.
+ const double currentDuration = frameDurationAtIndex(m_currentFrame);
+ const double time = currentTime();
+ if (m_desiredFrameStartTime == 0) {
+ 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.
+ 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))
+ return;
+
+ // Don't advance past the last frame if we haven't decoded the whole image
+ // yet and our repetition count is potentially unset. The repetition count
+ // in a GIF can potentially come after all the rest of the image data, so
+ // wait on it.
+ if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
+ return;
+
+ // The image may load more slowly than it's supposed to animate, so that by
+ // the time we reach the end of the first repetition, we're well behind.
+ // Clamp the desired frame start time in this case, so that we don't skip
+ // frames (or whole iterations) trying to "catch up". This is a tradeoff:
+ // It guarantees users see the whole animation the second time through and
+ // don't miss any repetitions, and is closer to what other browsers do; on
+ // the other hand, it makes animations "less accurate" for pages that try to
+ // sync an image and some other resource (e.g. audio), especially if users
+ // switch tabs (and thus stop drawing the animation, which will pause it)
+ // during that initial loop, then switch back later.
+ if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time)
+ m_desiredFrameStartTime = time;
+
+ if (!catchUpIfNecessary || time < m_desiredFrameStartTime) {
+ // Haven't yet reached time for next frame to start; delay until then.
+ m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation);
+ m_frameTimer->startOneShot(std::max(m_desiredFrameStartTime - time, 0.));
+ } else {
+ // We've already reached or passed the time for the next frame to start.
+ // See if we've also passed the time for frames after that to start, in
+ // case we need to skip some frames entirely. Remember not to advance
+ // to an incomplete frame.
+ for (size_t frameAfterNext = (nextFrame + 1) % frameCount(); frameIsCompleteAtIndex(frameAfterNext); frameAfterNext = (nextFrame + 1) % frameCount()) {
+ // Should we skip the next frame?
+ double frameAfterNextStartTime = m_desiredFrameStartTime + frameDurationAtIndex(nextFrame);
+ if (time < frameAfterNextStartTime)
+ break;
+
+ // Yes; skip over it without notifying our observers.
+ if (!internalAdvanceAnimation(true))
+ return;
+ m_desiredFrameStartTime = frameAfterNextStartTime;
+ nextFrame = frameAfterNext;
+ }
+
+ // Draw the next frame immediately. Note that m_desiredFrameStartTime
+ // may be in the past, meaning the next time through this function we'll
+ // kick off the next advancement sooner than this frame's duration would
+ // suggest.
+ if (internalAdvanceAnimation(false)) {
+ // The image region has been marked dirty, but once we return to our
+ // caller, draw() will clear it, and nothing will cause the
+ // animation to advance again. We need to start the timer for the
+ // next frame running, or the animation can hang. (Compare this
+ // with when advanceAnimation() is called, and the region is dirtied
+ // while draw() is not in the callstack, meaning draw() gets called
+ // to update the region and thus startAnimation() is reached again.)
+ // NOTE: For large images with slow or heavily-loaded systems,
+ // throwing away data as we go (see destroyDecodedData()) means we
+ // can spend so much time re-decoding data above that by the time we
+ // reach here we're behind again. If we let startAnimation() run
+ // the catch-up code again, we can get long delays without painting
+ // as we race the timer, or even infinite recursion. In this
+ // situation the best we can do is to simply change frames as fast
+ // as possible, so force startAnimation() to set a zero-delay timer
+ // and bail out if we're not caught up.
+ startAnimation(false);
+ }
+ }
+}
+
+void BitmapImage::stopAnimation()
+{
+ // This timer is used to animate all occurrences of this image. Don't invalidate
+ // the timer unless all renderers have stopped drawing.
+ delete m_frameTimer;
+ m_frameTimer = 0;
+}
+
+void BitmapImage::resetAnimation()
+{
+ stopAnimation();
+ m_currentFrame = 0;
+ 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();
+}
+
+void BitmapImage::advanceAnimation(Timer<BitmapImage>* timer)
+{
+ internalAdvanceAnimation(false);
+ // At this point the image region has been marked dirty, and if it's
+ // onscreen, we'll soon make a call to draw(), which will call
+ // startAnimation() again to keep the animation moving.
+}
+
+bool BitmapImage::internalAdvanceAnimation(bool skippingFrames)
+{
+ // Stop the animation.
+ stopAnimation();
+
+ // See if anyone is still paying attention to this animation. If not, we don't
+ // advance and will remain suspended at the current frame until the animation is resumed.
+ if (!skippingFrames && imageObserver()->shouldPauseAnimation(this))
+ return false;
+
+ m_currentFrame++;
+ 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 = 0;
+ }
+
+ 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);
+ }
+}
+
+}
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
new file mode 100644
index 0000000..c5f2a72
--- /dev/null
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BitmapImage_h
+#define BitmapImage_h
+
+#include "Image.h"
+#include "Color.h"
+#include "IntSize.h"
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+#ifdef __OBJC__
+@class NSImage;
+#else
+class NSImage;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct HBITMAP__ *HBITMAP;
+#endif
+
+#if PLATFORM(SGL)
+class SkBitmap;
+class SkBitmapRef;
+#endif
+
+namespace WebCore {
+ struct FrameData;
+}
+
+// This complicated-looking declaration tells the FrameData Vector that it should copy without
+// invoking our constructor or destructor. This allows us to have a vector even for a struct
+// that's not copyable.
+namespace WTF {
+ template<> class VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits {};
+}
+
+namespace WebCore {
+
+template <typename T> class Timer;
+
+// ================================================
+// FrameData Class
+// ================================================
+
+struct FrameData : Noncopyable {
+ FrameData()
+ : m_frame(0)
+ , m_haveMetadata(false)
+ , m_isComplete(false)
+ , m_duration(0)
+ , m_hasAlpha(true)
+ {
+ }
+
+ ~FrameData()
+ {
+ clear();
+ }
+
+ void clear();
+
+ NativeImagePtr m_frame;
+ bool m_haveMetadata;
+ bool m_isComplete;
+ float m_duration;
+ bool m_hasAlpha;
+};
+
+// =================================================
+// BitmapImage Class
+// =================================================
+
+class BitmapImage : public Image {
+ friend class GeneratedImage;
+ friend class GraphicsContext;
+public:
+ static PassRefPtr<BitmapImage> create(NativeImagePtr nativeImage, ImageObserver* observer = 0)
+ {
+ return adoptRef(new BitmapImage(nativeImage, observer));
+ }
+ static PassRefPtr<BitmapImage> create(ImageObserver* observer = 0)
+ {
+ return adoptRef(new BitmapImage(observer));
+ }
+ ~BitmapImage();
+
+ virtual bool isBitmapImage() const { return true; }
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+
+ virtual IntSize size() const;
+ IntSize currentFrameSize() const;
+
+ virtual bool dataChanged(bool allDataReceived);
+
+ // 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
+ // automatically pause once all observers no longer want to render the image anywhere.
+ virtual void stopAnimation();
+ virtual void resetAnimation();
+
+ virtual unsigned decodedSize() const { return m_decodedSize; }
+
+#if PLATFORM(MAC)
+ // Accessors for native image formats.
+ virtual NSImage* getNSImage();
+ virtual CFDataRef getTIFFRepresentation();
+#endif
+
+#if PLATFORM(CG)
+ virtual CGImageRef getCGImageRef();
+#endif
+
+#if PLATFORM(WIN)
+ virtual bool getHBITMAP(HBITMAP);
+ virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE);
+#endif
+
+#if PLATFORM(SGL)
+// virtual SkBitmapRef* getBitmap();
+ virtual void setURL(const String& str);
+#endif
+
+ virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); }
+
+protected:
+ enum RepetitionCountStatus {
+ Unknown, // We haven't checked the source's repetition count.
+ Uncertain, // We have a repetition count, but it might be wrong (some GIFs have a count after the image data, and will report "loop once" until all data has been decoded).
+ Certain, // The repetition count is known to be correct.
+ };
+
+ BitmapImage(NativeImagePtr, ImageObserver* = 0);
+ BitmapImage(ImageObserver* = 0);
+
+#if PLATFORM(WIN)
+ virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator);
+#endif
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
+#if PLATFORM(QT) || PLATFORM(WX)
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
+#endif
+ size_t currentFrame() const { return m_currentFrame; }
+ size_t frameCount();
+ NativeImagePtr frameAtIndex(size_t);
+ bool frameIsCompleteAtIndex(size_t);
+ float frameDurationAtIndex(size_t);
+ bool frameHasAlphaAtIndex(size_t);
+
+ // 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);
+
+ // Whether or not size is available yet.
+ bool isSizeAvailable();
+
+ // Animation.
+ int repetitionCount(bool imageKnownToBeComplete); // |imageKnownToBeComplete| should be set if the caller knows the entire image has been decoded.
+ bool shouldAnimate();
+ virtual void startAnimation(bool catchUpIfNecessary = true);
+ void advanceAnimation(Timer<BitmapImage>*);
+
+ // Function that does the real work of advancing the animation. When
+ // skippingFrames is true, we're in the middle of a loop trying to skip over
+ // a bunch of animation frames, so we should not do things like decode each
+ // one or notify our observers.
+ // Returns whether the animation was advanced.
+ bool internalAdvanceAnimation(bool skippingFrames);
+
+ // Helper for internalAdvanceAnimation().
+ void notifyObserverAndTrimDecodedData();
+
+ // Handle platform-specific data
+ void initPlatformData();
+ void invalidatePlatformData();
+
+ // Checks to see if the image is a 1x1 solid color. We optimize these images and just do a fill rect instead.
+ void checkForSolidColor();
+
+ virtual bool mayFillWithSolidColor() const { return m_isSolidColor && m_currentFrame == 0; }
+ virtual Color solidColor() const { return m_solidColor; }
+
+ ImageSource m_source;
+ mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image).
+
+ size_t m_currentFrame; // The index of the current frame of animation.
+ Vector<FrameData> m_frames; // An array of the cached frames of the animation. We have to ref frames to pin them in the cache.
+
+ Timer<BitmapImage>* m_frameTimer;
+ int m_repetitionCount; // How many total animation loops we should do. This will be cAnimationNone if this image type is incapable of animation.
+ RepetitionCountStatus m_repetitionCountStatus;
+ int m_repetitionsComplete; // How many repetitions we've finished.
+ double m_desiredFrameStartTime; // The system time at which we hope to see the next call to startAnimation().
+
+#if PLATFORM(MAC)
+ mutable RetainPtr<NSImage> m_nsImage; // A cached NSImage of frame 0. Only built lazily if someone actually queries for one.
+ mutable RetainPtr<CFDataRef> m_tiffRep; // Cached TIFF rep for frame 0. Only built lazily if someone queries for one.
+#endif
+
+ Color m_solidColor; // If we're a 1x1 solid color, this is the color to use to fill.
+ bool m_isSolidColor; // Whether or not we are a 1x1 solid image.
+
+ bool m_animationFinished; // Whether or not we've completed the entire animation.
+
+ bool m_allDataReceived; // Whether or not we've received all our data.
+
+ mutable bool m_haveSize; // Whether or not our |m_size| member variable has the final overall image size yet.
+ bool m_sizeAvailable; // Whether or not we can obtain the size of the first image frame yet from ImageIO.
+ mutable bool m_hasUniformFrameSize;
+
+ unsigned m_decodedSize; // The current size of all decoded frames.
+
+ mutable bool m_haveFrameCount;
+ size_t m_frameCount;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp
new file mode 100644
index 0000000..3ff589d
--- /dev/null
+++ b/WebCore/platform/graphics/Color.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 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 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"
+
+#include "PlatformString.h"
+#include <math.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+
+#include "ColorData.c"
+
+using namespace std;
+using namespace WTF;
+
+namespace WebCore {
+
+const RGBA32 lightenedBlack = 0xFF545454;
+const RGBA32 darkenedWhite = 0xFFABABAB;
+
+RGBA32 makeRGB(int r, int g, int b)
+{
+ return 0xFF000000 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255));
+}
+
+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)
+{
+ // 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));
+}
+
+RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a)
+{
+ return colorFloatToRGBAByte(a) << 24 | colorFloatToRGBAByte(r) << 16 | colorFloatToRGBAByte(g) << 8 | colorFloatToRGBAByte(b);
+}
+
+RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha)
+{
+ RGBA32 rgbOnly = color & 0x00FFFFFF;
+ RGBA32 rgba = rgbOnly | colorFloatToRGBAByte(overrideAlpha) << 24;
+ return rgba;
+}
+
+static double calcHue(double temp1, double temp2, double hueVal)
+{
+ if (hueVal < 0.0)
+ hueVal++;
+ else if (hueVal > 1.0)
+ hueVal--;
+ if (hueVal * 6.0 < 1.0)
+ return temp1 + (temp2 - temp1) * hueVal * 6.0;
+ if (hueVal * 2.0 < 1.0)
+ return temp2;
+ if (hueVal * 3.0 < 2.0)
+ return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hueVal) * 6.0;
+ return temp1;
+}
+
+// Explanation of this algorithm can be found in the CSS3 Color Module
+// specification at http://www.w3.org/TR/css3-color/#hsl-color with further
+// explanation available at http://en.wikipedia.org/wiki/HSL_color_space
+
+// all values are in the range of 0 to 1.0
+RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double alpha)
+{
+ const double scaleFactor = nextafter(256.0, 0.0);
+
+ if (!saturation) {
+ int greyValue = static_cast<int>(lightness * scaleFactor);
+ return makeRGBA(greyValue, greyValue, greyValue, static_cast<int>(alpha * scaleFactor));
+ }
+
+ double temp2 = lightness < 0.5 ? lightness * (1.0 + saturation) : lightness + saturation - lightness * saturation;
+ double temp1 = 2.0 * lightness - temp2;
+
+ return makeRGBA(static_cast<int>(calcHue(temp1, temp2, hue + 1.0 / 3.0) * scaleFactor),
+ static_cast<int>(calcHue(temp1, temp2, hue) * scaleFactor),
+ static_cast<int>(calcHue(temp1, temp2, hue - 1.0 / 3.0) * scaleFactor),
+ static_cast<int>(alpha * scaleFactor));
+}
+
+// originally moved here from the CSS parser
+bool Color::parseHexColor(const String& name, RGBA32& rgb)
+{
+ unsigned length = name.length();
+ if (length != 3 && length != 6)
+ return false;
+ unsigned value = 0;
+ for (unsigned i = 0; i < length; ++i) {
+ if (!isASCIIHexDigit(name[i]))
+ return false;
+ value <<= 4;
+ value |= toASCIIHexValue(name[i]);
+ }
+ if (length == 6) {
+ rgb = 0xFF000000 | value;
+ return true;
+ }
+ // #abc converts to #aabbcc
+ rgb = 0xFF000000
+ | (value & 0xF00) << 12 | (value & 0xF00) << 8
+ | (value & 0xF0) << 8 | (value & 0xF0) << 4
+ | (value & 0xF) << 4 | (value & 0xF);
+ return true;
+}
+
+int differenceSquared(const Color& c1, const Color& c2)
+{
+ int dR = c1.red() - c2.red();
+ int dG = c1.green() - c2.green();
+ int dB = c1.blue() - c2.blue();
+ return dR * dR + dG * dG + dB * dB;
+}
+
+Color::Color(const String& name)
+{
+ if (name.startsWith("#"))
+ m_valid = parseHexColor(name.substring(1), m_color);
+ else
+ setNamedColor(name);
+}
+
+Color::Color(const char* name)
+{
+ if (name[0] == '#')
+ m_valid = parseHexColor(&name[1], m_color);
+ else {
+ const NamedColor* foundColor = findColor(name, strlen(name));
+ m_color = foundColor ? foundColor->RGBValue : 0;
+ m_color |= 0xFF000000;
+ m_valid = foundColor;
+ }
+}
+
+String Color::name() const
+{
+ if (alpha() < 0xFF)
+ return String::format("#%02X%02X%02X%02X", red(), green(), blue(), alpha());
+ return String::format("#%02X%02X%02X", red(), green(), blue());
+}
+
+static inline const NamedColor* findNamedColor(const String& name)
+{
+ char buffer[64]; // easily big enough for the longest color name
+ unsigned length = name.length();
+ if (length > sizeof(buffer) - 1)
+ return 0;
+ for (unsigned i = 0; i < length; ++i) {
+ UChar c = name[i];
+ if (!c || c > 0x7F)
+ return 0;
+ buffer[i] = toASCIILower(static_cast<char>(c));
+ }
+ buffer[length] = '\0';
+ return findColor(buffer, length);
+}
+
+void Color::setNamedColor(const String& name)
+{
+ const NamedColor* foundColor = findNamedColor(name);
+ m_color = foundColor ? foundColor->RGBValue : 0;
+ m_color |= 0xFF000000;
+ m_valid = foundColor;
+}
+
+Color Color::light() const
+{
+ // Hardcode this common case for speed.
+ if (m_color == black)
+ return lightenedBlack;
+
+ const float scaleFactor = nextafterf(256.0f, 0.0f);
+
+ float r, g, b, a;
+ getRGBA(r, g, b, a);
+
+ float v = max(r, max(g, b));
+
+ if (v == 0.0f)
+ // Lightened black with alpha.
+ return Color(0x54, 0x54, 0x54, alpha());
+
+ float multiplier = min(1.0f, v + 0.33f) / v;
+
+ return Color(static_cast<int>(multiplier * r * scaleFactor),
+ static_cast<int>(multiplier * g * scaleFactor),
+ static_cast<int>(multiplier * b * scaleFactor),
+ alpha());
+}
+
+Color Color::dark() const
+{
+ // Hardcode this common case for speed.
+ if (m_color == white)
+ return darkenedWhite;
+
+ const float scaleFactor = nextafterf(256.0f, 0.0f);
+
+ float r, g, b, a;
+ getRGBA(r, g, b, a);
+
+ float v = max(r, max(g, b));
+ float multiplier = max(0.0f, (v - 0.33f) / v);
+
+ return Color(static_cast<int>(multiplier * r * scaleFactor),
+ static_cast<int>(multiplier * g * scaleFactor),
+ static_cast<int>(multiplier * b * scaleFactor),
+ alpha());
+}
+
+static int blendComponent(int c, int a)
+{
+ // We use white.
+ float alpha = a / 255.0f;
+ int whiteBlend = 255 - a;
+ c -= whiteBlend;
+ return static_cast<int>(c / alpha);
+}
+
+const int cStartAlpha = 153; // 60%
+const int cEndAlpha = 204; // 80%;
+const int cAlphaIncrement = 17; // Increments in between.
+
+Color Color::blend(const Color& source) const
+{
+ if (!alpha() || !source.hasAlpha())
+ return source;
+
+ if (!source.alpha())
+ return *this;
+
+ int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha();
+ int a = d / 255;
+ int r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d;
+ int g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d;
+ int b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d;
+ return Color(r, g, b, a);
+}
+
+Color Color::blendWithWhite() const
+{
+ // If the color contains alpha already, we leave it alone.
+ if (hasAlpha())
+ return *this;
+
+ Color newColor;
+ for (int alpha = cStartAlpha; alpha <= cEndAlpha; alpha += cAlphaIncrement) {
+ // We have a solid color. Convert to an equivalent color that looks the same when blended with white
+ // at the current alpha. Try using less transparency if the numbers end up being negative.
+ int r = blendComponent(red(), alpha);
+ int g = blendComponent(green(), alpha);
+ int b = blendComponent(blue(), alpha);
+
+ newColor = Color(r, g, b, alpha);
+
+ if (r >= 0 && g >= 0 && b >= 0)
+ break;
+ }
+ return newColor;
+}
+
+void Color::getRGBA(float& r, float& g, float& b, float& a) const
+{
+ r = red() / 255.0f;
+ g = green() / 255.0f;
+ b = blue() / 255.0f;
+ a = alpha() / 255.0f;
+}
+
+void Color::getRGBA(double& r, double& g, double& b, double& a) const
+{
+ r = red() / 255.0;
+ g = green() / 255.0;
+ b = blue() / 255.0;
+ a = alpha() / 255.0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h
new file mode 100644
index 0000000..61fc74c
--- /dev/null
+++ b/WebCore/platform/graphics/Color.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2003-6 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Color_h
+#define Color_h
+
+#include <wtf/Platform.h>
+
+#if PLATFORM(CG)
+typedef struct CGColor* CGColorRef;
+#endif
+
+#if PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QColor;
+QT_END_NAMESPACE
+#endif
+
+#if PLATFORM(GTK)
+typedef struct _GdkColor GdkColor;
+#endif
+
+#if PLATFORM(WX)
+class wxColour;
+#endif
+
+namespace WebCore {
+
+class String;
+class Color;
+
+typedef unsigned RGBA32; // RGBA quadruplet
+
+RGBA32 makeRGB(int r, int g, int b);
+RGBA32 makeRGBA(int r, int g, int b, int a);
+
+RGBA32 colorWithOverrideAlpha(RGBA32 color, float overrideAlpha);
+RGBA32 makeRGBA32FromFloats(float r, float g, float b, float a);
+RGBA32 makeRGBAFromHSLA(double h, double s, double l, double a);
+
+int differenceSquared(const Color&, const Color&);
+
+class Color {
+public:
+ Color() : m_color(0), m_valid(false) { }
+ Color(RGBA32 col) : m_color(col), m_valid(true) { }
+ Color(int r, int g, int b) : m_color(makeRGB(r, g, b)), m_valid(true) { }
+ Color(int r, int g, int b, int a) : m_color(makeRGBA(r, g, b, a)), m_valid(true) { }
+ // Color is currently limited to 32bit RGBA, perhaps some day we'll support better colors
+ Color(float r, float g, float b, float a) : m_color(makeRGBA32FromFloats(r, g, b, a)), m_valid(true) { }
+ explicit Color(const String&);
+ explicit Color(const char*);
+
+ String name() const;
+ void setNamedColor(const String&);
+
+ bool isValid() const { return m_valid; }
+
+ bool hasAlpha() const { return alpha() < 255; }
+
+ int red() const { return (m_color >> 16) & 0xFF; }
+ int green() const { return (m_color >> 8) & 0xFF; }
+ int blue() const { return m_color & 0xFF; }
+ int alpha() const { return (m_color >> 24) & 0xFF; }
+
+ RGBA32 rgb() const { return m_color; } // Preserve the alpha.
+ void setRGB(int r, int g, int b) { m_color = makeRGB(r, g, b); m_valid = true; }
+ void setRGB(RGBA32 rgb) { m_color = rgb; m_valid = true; }
+ void getRGBA(float& r, float& g, float& b, float& a) const;
+ void getRGBA(double& r, double& g, double& b, double& a) const;
+
+ Color light() const;
+ Color dark() const;
+
+ Color blend(const Color&) const;
+ Color blendWithWhite() const;
+
+#if PLATFORM(QT)
+ Color(const QColor&);
+ operator QColor() const;
+#endif
+
+#if PLATFORM(GTK)
+ Color(const GdkColor&);
+ // We can't sensibly go back to GdkColor without losing the alpha value
+#endif
+
+#if PLATFORM(WX)
+ Color(const wxColour&);
+ operator wxColour() const;
+#endif
+
+#if PLATFORM(CG)
+ Color(CGColorRef);
+#endif
+
+ static bool parseHexColor(const String& name, RGBA32& rgb);
+
+ static const RGBA32 black = 0xFF000000;
+ static const RGBA32 white = 0xFFFFFFFF;
+ static const RGBA32 darkGray = 0xFF808080;
+ static const RGBA32 gray = 0xFFA0A0A0;
+ static const RGBA32 lightGray = 0xFFC0C0C0;
+ static const RGBA32 transparent = 0x00000000;
+
+#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
+ static const RGBA32 tap = 0x4D1A1A1A;
+#endif
+
+private:
+ RGBA32 m_color;
+ bool m_valid;
+};
+
+inline bool operator==(const Color& a, const Color& b)
+{
+ return a.rgb() == b.rgb() && a.isValid() == b.isValid();
+}
+
+inline bool operator!=(const Color& a, const Color& b)
+{
+ return !(a == b);
+}
+
+Color focusRingColor();
+
+#if PLATFORM(CG)
+CGColorRef cgColor(const Color&);
+#endif
+
+} // namespace WebCore
+
+#endif // Color_h
diff --git a/WebCore/platform/graphics/DashArray.h b/WebCore/platform/graphics/DashArray.h
new file mode 100644
index 0000000..46b84a4
--- /dev/null
+++ b/WebCore/platform/graphics/DashArray.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DashArray_h
+#define DashArray_h
+
+#include <wtf/Vector.h>
+
+#if PLATFORM(CG)
+typedef Vector<CGFloat> DashArray;
+#elif PLATFORM(CAIRO)
+typedef Vector<double> DashArray;
+#else
+typedef Vector<float> DashArray;
+#endif
+
+#endif // DashArray_h
diff --git a/WebCore/platform/graphics/FloatPoint.cpp b/WebCore/platform/graphics/FloatPoint.cpp
new file mode 100644
index 0000000..3ca0361
--- /dev/null
+++ b/WebCore/platform/graphics/FloatPoint.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatPoint.h"
+
+#include "AffineTransform.h"
+#include "FloatConversion.h"
+#include "IntPoint.h"
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y())
+{
+}
+
+FloatPoint FloatPoint::matrixTransform(const AffineTransform& transform) const
+{
+ double newX, newY;
+ transform.map(static_cast<double>(m_x), static_cast<double>(m_y), &newX, &newY);
+ return narrowPrecision(newX, newY);
+}
+
+FloatPoint FloatPoint::narrowPrecision(double x, double y)
+{
+ return FloatPoint(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y));
+}
+
+}
diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h
new file mode 100644
index 0000000..6b3c769
--- /dev/null
+++ b/WebCore/platform/graphics/FloatPoint.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FloatPoint_h
+#define FloatPoint_h
+
+#include "FloatSize.h"
+#include <wtf/Platform.h>
+
+#if PLATFORM(CG)
+typedef struct CGPoint CGPoint;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGPoint NSPoint;
+#else
+typedef struct _NSPoint NSPoint;
+#endif
+#endif
+
+#if PLATFORM(QT)
+#include "qglobal.h"
+QT_BEGIN_NAMESPACE
+class QPointF;
+QT_END_NAMESPACE
+#endif
+
+#if PLATFORM(SYMBIAN)
+class TPoint;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkPoint;
+#endif
+
+namespace WebCore {
+
+class AffineTransform;
+class IntPoint;
+
+class FloatPoint {
+public:
+ FloatPoint() : m_x(0), m_y(0) { }
+ FloatPoint(float x, float y) : m_x(x), m_y(y) { }
+ FloatPoint(const IntPoint&);
+
+ static FloatPoint narrowPrecision(double x, double y);
+
+ float x() const { return m_x; }
+ float y() const { return m_y; }
+
+ void setX(float x) { m_x = x; }
+ void setY(float y) { m_y = y; }
+ void move(float dx, float dy) { m_x += dx; m_y += dy; }
+
+#if PLATFORM(CG)
+ FloatPoint(const CGPoint&);
+ operator CGPoint() const;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ FloatPoint(const NSPoint&);
+ operator NSPoint() const;
+#endif
+
+#if PLATFORM(QT)
+ FloatPoint(const QPointF&);
+ operator QPointF() const;
+#endif
+
+#if PLATFORM(SYMBIAN)
+ operator TPoint() const;
+ FloatPoint(const TPoint&);
+#endif
+
+#if PLATFORM(SKIA)
+ operator SkPoint() const;
+ FloatPoint(const SkPoint&);
+#endif
+
+ FloatPoint matrixTransform(const AffineTransform&) const;
+
+private:
+ float m_x, m_y;
+};
+
+
+inline FloatPoint& operator+=(FloatPoint& a, const FloatSize& b)
+{
+ a.move(b.width(), b.height());
+ return a;
+}
+
+inline FloatPoint& operator-=(FloatPoint& a, const FloatSize& b)
+{
+ a.move(-b.width(), -b.height());
+ return a;
+}
+
+inline FloatPoint operator+(const FloatPoint& a, const FloatSize& b)
+{
+ return FloatPoint(a.x() + b.width(), a.y() + b.height());
+}
+
+inline FloatSize operator-(const FloatPoint& a, const FloatPoint& b)
+{
+ return FloatSize(a.x() - b.x(), a.y() - b.y());
+}
+
+inline FloatPoint operator-(const FloatPoint& a, const FloatSize& b)
+{
+ return FloatPoint(a.x() - b.width(), a.y() - b.height());
+}
+
+inline bool operator==(const FloatPoint& a, const FloatPoint& b)
+{
+ return a.x() == b.x() && a.y() == b.y();
+}
+
+inline bool operator!=(const FloatPoint& a, const FloatPoint& b)
+{
+ return a.x() != b.x() || a.y() != b.y();
+}
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/FloatPoint3D.cpp b/WebCore/platform/graphics/FloatPoint3D.cpp
new file mode 100644
index 0000000..ec52d40
--- /dev/null
+++ b/WebCore/platform/graphics/FloatPoint3D.cpp
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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"
+
+#if ENABLE(SVG)
+#include <math.h>
+#include "FloatPoint3D.h"
+
+namespace WebCore {
+
+FloatPoint3D::FloatPoint3D()
+ : m_x(0.f)
+ , m_y(0.f)
+ , m_z(0.f)
+{
+}
+
+FloatPoint3D::FloatPoint3D(float x, float y, float z)
+ : m_x(x)
+ , m_y(y)
+ , m_z(z)
+{
+}
+
+float FloatPoint3D::x() const
+{
+ 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;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h
new file mode 100644
index 0000000..55f70e7
--- /dev/null
+++ b/WebCore/platform/graphics/FloatPoint3D.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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 FloatPoint3D_h
+#define FloatPoint3D_h
+
+#if ENABLE(SVG)
+
+namespace WebCore {
+
+class FloatPoint3D {
+public:
+ FloatPoint3D();
+ FloatPoint3D(float x, float y, float z);
+
+ float x() const;
+ void setX(float x);
+
+ float y() const;
+ void setY(float y);
+
+ float z() const;
+ void setZ(float z);
+
+ void normalize();
+
+private:
+ float m_x;
+ float m_y;
+ float m_z;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+
+#endif // FloatPoint3D_h
diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp
new file mode 100644
index 0000000..ec7b3fa
--- /dev/null
+++ b/WebCore/platform/graphics/FloatRect.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatRect.h"
+
+#include "FloatConversion.h"
+#include "IntRect.h"
+#include <algorithm>
+#include <math.h>
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+FloatRect::FloatRect(const IntRect& r) : m_location(r.location()), m_size(r.size())
+{
+}
+
+FloatRect FloatRect::narrowPrecision(double x, double y, double width, double height)
+{
+ return FloatRect(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), narrowPrecisionToFloat(width), narrowPrecisionToFloat(height));
+}
+
+bool FloatRect::intersects(const FloatRect& other) const
+{
+ // Checking emptiness handles negative widths as well as zero.
+ return !isEmpty() && !other.isEmpty()
+ && x() < other.right() && other.x() < right()
+ && y() < other.bottom() && other.y() < bottom();
+}
+
+bool FloatRect::contains(const FloatRect& other) const
+{
+ return x() <= other.x() && right() >= other.right()
+ && y() <= other.y() && bottom() >= other.bottom();
+}
+
+void FloatRect::intersect(const FloatRect& other)
+{
+ float l = max(x(), other.x());
+ float t = max(y(), other.y());
+ float r = min(right(), other.right());
+ float b = min(bottom(), other.bottom());
+
+ // Return a clean empty rectangle for non-intersecting cases.
+ if (l >= r || t >= b) {
+ l = 0;
+ t = 0;
+ r = 0;
+ b = 0;
+ }
+
+ m_location.setX(l);
+ m_location.setY(t);
+ m_size.setWidth(r - l);
+ m_size.setHeight(b - t);
+}
+
+void FloatRect::unite(const FloatRect& other)
+{
+ // Handle empty special cases first.
+ if (other.isEmpty())
+ return;
+ if (isEmpty()) {
+ *this = other;
+ return;
+ }
+
+ float l = min(x(), other.x());
+ float t = min(y(), other.y());
+ float r = max(right(), other.right());
+ float b = max(bottom(), other.bottom());
+
+ m_location.setX(l);
+ m_location.setY(t);
+ m_size.setWidth(r - l);
+ m_size.setHeight(b - t);
+}
+
+void FloatRect::scale(float s)
+{
+ m_location.setX(x() * s);
+ m_location.setY(y() * s);
+ m_size.setWidth(width() * s);
+ m_size.setHeight(height() * s);
+}
+
+IntRect enclosingIntRect(const FloatRect& rect)
+{
+ int l = static_cast<int>(floorf(rect.x()));
+ int t = static_cast<int>(floorf(rect.y()));
+ int r = static_cast<int>(ceilf(rect.right()));
+ int b = static_cast<int>(ceilf(rect.bottom()));
+ return IntRect(l, t, r - l, b - t);
+}
+
+}
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
new file mode 100644
index 0000000..11e3791
--- /dev/null
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FloatRect_h
+#define FloatRect_h
+
+#include "FloatPoint.h"
+
+#if PLATFORM(CG)
+typedef struct CGRect CGRect;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGRect NSRect;
+#else
+typedef struct _NSRect NSRect;
+#endif
+#endif
+
+#if PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QRectF;
+QT_END_NAMESPACE
+#endif
+
+#if PLATFORM(WX) && USE(WXGC)
+class wxRect2DDouble;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkRect;
+#endif
+
+namespace WebCore {
+
+class IntRect;
+
+class FloatRect {
+public:
+ FloatRect() { }
+ FloatRect(const FloatPoint& location, const FloatSize& size)
+ : m_location(location), m_size(size) { }
+ FloatRect(float x, float y, float width, float height)
+ : m_location(FloatPoint(x, y)), m_size(FloatSize(width, height)) { }
+ FloatRect(const IntRect&);
+
+ static FloatRect narrowPrecision(double x, double y, double width, double height);
+
+ FloatPoint location() const { return m_location; }
+ FloatSize size() const { return m_size; }
+
+ void setLocation(const FloatPoint& location) { m_location = location; }
+ void setSize(const FloatSize& size) { m_size = size; }
+
+ float x() const { return m_location.x(); }
+ float y() const { return m_location.y(); }
+ float width() const { return m_size.width(); }
+ float height() const { return m_size.height(); }
+
+ void setX(float x) { m_location.setX(x); }
+ void setY(float y) { m_location.setY(y); }
+ void setWidth(float width) { m_size.setWidth(width); }
+ void setHeight(float height) { m_size.setHeight(height); }
+
+ bool isEmpty() const { return m_size.isEmpty(); }
+
+ float right() const { return x() + width(); }
+ float bottom() const { return y() + height(); }
+
+ void move(const FloatSize& delta) { m_location += delta; }
+ void move(float dx, float dy) { m_location.move(dx, dy); }
+
+ bool intersects(const FloatRect&) const;
+ bool contains(const FloatRect&) const;
+
+ void intersect(const FloatRect&);
+ void unite(const FloatRect&);
+
+ // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version
+ // is really checking for containment of 1x1 rect, but that doesn't make sense with floats.
+ bool contains(float px, float py) const
+ { return px >= x() && px <= right() && py >= y() && py <= bottom(); }
+ bool contains(const FloatPoint& point) const { return contains(point.x(), point.y()); }
+
+
+ void inflateX(float dx) {
+ m_location.setX(m_location.x() - dx);
+ m_size.setWidth(m_size.width() + dx + dx);
+ }
+ void inflateY(float dy) {
+ m_location.setY(m_location.y() - dy);
+ m_size.setHeight(m_size.height() + dy + dy);
+ }
+ void inflate(float d) { inflateX(d); inflateY(d); }
+ void scale(float s);
+
+#if PLATFORM(CG)
+ FloatRect(const CGRect&);
+ operator CGRect() const;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ FloatRect(const NSRect&);
+ operator NSRect() const;
+#endif
+
+#if PLATFORM(QT)
+ FloatRect(const QRectF&);
+ operator QRectF() const;
+#endif
+#if PLATFORM(SYMBIAN)
+ FloatRect(const TRect&);
+ operator TRect() const;
+ TRect rect() const;
+#endif
+
+#if PLATFORM(WX) && USE(WXGC)
+ FloatRect(const wxRect2DDouble&);
+ operator wxRect2DDouble() const;
+#endif
+
+#if PLATFORM(SKIA)
+ FloatRect(const SkRect&);
+ operator SkRect() const;
+#endif
+
+private:
+ FloatPoint m_location;
+ FloatSize m_size;
+};
+
+inline FloatRect intersection(const FloatRect& a, const FloatRect& b)
+{
+ FloatRect c = a;
+ c.intersect(b);
+ return c;
+}
+
+inline FloatRect unionRect(const FloatRect& a, const FloatRect& b)
+{
+ FloatRect c = a;
+ c.unite(b);
+ return c;
+}
+
+inline bool operator==(const FloatRect& a, const FloatRect& b)
+{
+ return a.location() == b.location() && a.size() == b.size();
+}
+
+inline bool operator!=(const FloatRect& a, const FloatRect& b)
+{
+ return a.location() != b.location() || a.size() != b.size();
+}
+
+IntRect enclosingIntRect(const FloatRect&);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/FloatSize.cpp b/WebCore/platform/graphics/FloatSize.cpp
new file mode 100644
index 0000000..86fa4c0
--- /dev/null
+++ b/WebCore/platform/graphics/FloatSize.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatSize.h"
+
+#include "FloatConversion.h"
+#include "IntSize.h"
+
+namespace WebCore {
+
+FloatSize::FloatSize(const IntSize& size) : m_width(size.width()), m_height(size.height())
+{
+}
+
+FloatSize FloatSize::narrowPrecision(double width, double height)
+{
+ return FloatSize(narrowPrecisionToFloat(width), narrowPrecisionToFloat(height));
+}
+
+}
diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h
new file mode 100644
index 0000000..cf1e1c5
--- /dev/null
+++ b/WebCore/platform/graphics/FloatSize.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FloatSize_h
+#define FloatSize_h
+
+#include <wtf/Platform.h>
+
+#if PLATFORM(CG)
+typedef struct CGSize CGSize;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGSize NSSize;
+#else
+typedef struct _NSSize NSSize;
+#endif
+#endif
+
+namespace WebCore {
+
+class IntSize;
+
+class FloatSize {
+public:
+ FloatSize() : m_width(0), m_height(0) { }
+ FloatSize(float width, float height) : m_width(width), m_height(height) { }
+ FloatSize(const IntSize&);
+
+ static FloatSize narrowPrecision(double width, double height);
+
+ float width() const { return m_width; }
+ float height() const { return m_height; }
+
+ void setWidth(float width) { m_width = width; }
+ void setHeight(float height) { m_height = height; }
+
+ bool isEmpty() const { return m_width <= 0 || m_height <= 0; }
+
+ FloatSize expandedTo(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;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ explicit FloatSize(const NSSize &); // don't do this implicitly since it's lossy
+ operator NSSize() const;
+#endif
+
+private:
+ float m_width, m_height;
+};
+
+inline FloatSize& operator+=(FloatSize& a, const FloatSize& b)
+{
+ a.setWidth(a.width() + b.width());
+ a.setHeight(a.height() + b.height());
+ return a;
+}
+
+inline FloatSize& operator-=(FloatSize& a, const FloatSize& b)
+{
+ a.setWidth(a.width() - b.width());
+ a.setHeight(a.height() - b.height());
+ return a;
+}
+
+inline FloatSize operator+(const FloatSize& a, const FloatSize& b)
+{
+ return FloatSize(a.width() + b.width(), a.height() + b.height());
+}
+
+inline FloatSize operator-(const FloatSize& a, const FloatSize& b)
+{
+ return FloatSize(a.width() - b.width(), a.height() - b.height());
+}
+
+inline FloatSize operator-(const FloatSize& size)
+{
+ return FloatSize(-size.width(), -size.height());
+}
+
+inline bool operator==(const FloatSize& a, const FloatSize& b)
+{
+ return a.width() == b.width() && a.height() == b.height();
+}
+
+inline bool operator!=(const FloatSize& a, const FloatSize& b)
+{
+ return a.width() != b.width() || a.height() != b.height();
+}
+
+} // namespace WebCore
+
+#endif // FloatSize_h
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp
new file mode 100644
index 0000000..138e322
--- /dev/null
+++ b/WebCore/platform/graphics/Font.cpp
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006 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 "Font.h"
+
+#include "CharacterNames.h"
+#include "FloatRect.h"
+#include "FontCache.h"
+#include "FontFallbackList.h"
+#include "IntPoint.h"
+#include "GlyphBuffer.h"
+#include "WidthIterator.h"
+#include <wtf/MathExtras.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+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 /*?*/,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+Font::CodePath Font::s_codePath = Auto;
+
+// ============================================================================================
+// Font Implementation (Cross-Platform Portion)
+// ============================================================================================
+
+Font::Font()
+ : m_pageZero(0)
+ , m_cachedPrimaryFont(0)
+ , m_letterSpacing(0)
+ , m_wordSpacing(0)
+ , m_isPlatformFont(false)
+{
+}
+
+Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
+ : m_fontDescription(fd)
+ , m_pageZero(0)
+ , m_cachedPrimaryFont(0)
+ , m_letterSpacing(letterSpacing)
+ , m_wordSpacing(wordSpacing)
+ , m_isPlatformFont(false)
+{
+}
+
+Font::Font(const FontPlatformData& fontData, bool isPrinterFont)
+ : m_fontList(FontFallbackList::create())
+ , m_pageZero(0)
+ , m_cachedPrimaryFont(0)
+ , m_letterSpacing(0)
+ , m_wordSpacing(0)
+ , m_isPlatformFont(true)
+{
+ m_fontDescription.setUsePrinterFont(isPrinterFont);
+ m_fontList->setPlatformFont(fontData);
+}
+
+Font::Font(const Font& other)
+ : m_fontDescription(other.m_fontDescription)
+ , m_fontList(other.m_fontList)
+ , m_pages(other.m_pages)
+ , m_pageZero(other.m_pageZero)
+ , m_cachedPrimaryFont(other.m_cachedPrimaryFont)
+ , m_letterSpacing(other.m_letterSpacing)
+ , m_wordSpacing(other.m_wordSpacing)
+ , m_isPlatformFont(other.m_isPlatformFont)
+{
+}
+
+Font& Font::operator=(const Font& other)
+{
+ m_fontDescription = other.m_fontDescription;
+ m_fontList = other.m_fontList;
+ m_pages = other.m_pages;
+ m_pageZero = other.m_pageZero;
+ m_cachedPrimaryFont = other.m_cachedPrimaryFont;
+ m_letterSpacing = other.m_letterSpacing;
+ m_wordSpacing = other.m_wordSpacing;
+ m_isPlatformFont = other.m_isPlatformFont;
+ return *this;
+}
+
+Font::~Font()
+{
+}
+
+bool Font::operator==(const Font& other) const
+{
+ // Our FontData don't have to be checked, since checking the font description will be fine.
+ // FIXME: This does not work if the font was made with the FontPlatformData constructor.
+ if ((m_fontList && m_fontList->loadingCustomFonts()) ||
+ (other.m_fontList && other.m_fontList->loadingCustomFonts()))
+ return false;
+
+ FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
+ FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
+
+ return first == second
+ && m_fontDescription == other.m_fontDescription
+ && m_letterSpacing == other.m_letterSpacing
+ && m_wordSpacing == other.m_wordSpacing
+ && (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);
+ ASSERT(!m_cachedPrimaryFont);
+ m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' ');
+}
+
+const FontData* Font::fontDataAt(unsigned index) const
+{
+ ASSERT(m_fontList);
+ return m_fontList->fontDataAt(this, index);
+}
+
+const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const
+{
+ ASSERT(m_fontList);
+ return m_fontList->fontDataForCharacters(this, characters, length);
+}
+
+void Font::update(PassRefPtr<FontSelector> fontSelector) const
+{
+ // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
+ // being reasonably safe (because inherited fonts in the render tree pick up the new
+ // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
+ // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
+ // and could eventually be rectified by using RefPtrs for Fonts themselves.
+ if (!m_fontList)
+ m_fontList = FontFallbackList::create();
+ m_fontList->invalidate(fontSelector);
+ m_cachedPrimaryFont = 0;
+ m_pageZero = 0;
+ 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.
+ if (m_fontList && m_fontList->loadingCustomFonts())
+ return;
+
+ to = (to == -1 ? run.length() : to);
+
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont()) {
+ drawTextUsingSVGFont(context, run, point, from, to);
+ return;
+ }
+#endif
+
+ if (canUseGlyphCache(run))
+ drawSimpleText(context, run, point, from, to);
+ else
+ drawComplexText(context, run, point, from, to);
+}
+
+float Font::floatWidth(const TextRun& run) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return floatWidthUsingSVGFont(run);
+#endif
+
+ if (canUseGlyphCache(run))
+ return floatWidthForSimpleText(run, 0);
+ return floatWidthForComplexText(run);
+}
+
+float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
+#endif
+
+ charsConsumed = run.length();
+ glyphName = "";
+ if (canUseGlyphCache(run))
+ return floatWidthForSimpleText(run, 0);
+ return floatWidthForComplexText(run);
+}
+
+float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const
+{
+ WidthIterator it(this, run);
+ it.advance(run.length(), glyphBuffer);
+ return it.m_runWidthSoFar;
+}
+
+FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return selectionRectForTextUsingSVGFont(run, point, h, from, to);
+#endif
+
+ to = (to == -1 ? run.length() : to);
+ if (canUseGlyphCache(run))
+ return selectionRectForSimpleText(run, point, h, from, to);
+ return selectionRectForComplexText(run, point, h, from, to);
+}
+
+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::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+#if ENABLE(SVG_FONTS)
+ if (primaryFont()->isSVGFont())
+ return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
+#endif
+
+ 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;
+ }
+ }
+ }
+
+ return offset;
+}
+
+#if ENABLE(SVG_FONTS)
+bool Font::isSVGFont() const
+{
+ return primaryFont()->isSVGFont();
+}
+#endif
+
+FontSelector* Font::fontSelector() const
+{
+ return m_fontList ? m_fontList->fontSelector() : 0;
+}
+
+}
diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h
new file mode 100644
index 0000000..a99ce12
--- /dev/null
+++ b/WebCore/platform/graphics/Font.h
@@ -0,0 +1,210 @@
+/*
+ * 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, 2006, 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Font_h
+#define Font_h
+
+#include "TextRun.h"
+#include "FontDescription.h"
+#include <wtf/HashMap.h>
+
+#if PLATFORM(QT)
+#include <QtGui/qfont.h>
+#include <QtGui/qfontmetrics.h>
+#endif
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class FontData;
+class FontFallbackList;
+class FontPlatformData;
+class FontSelector;
+class GlyphBuffer;
+class GlyphPageTreeNode;
+class GraphicsContext;
+class IntPoint;
+class SimpleFontData;
+class SVGFontElement;
+
+struct GlyphData;
+
+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
+ ~Font();
+
+ Font(const Font&);
+ Font& operator=(const Font&);
+
+ bool operator==(const Font& other) const;
+ bool operator!=(const Font& other) const {
+ return !(*this == other);
+ }
+
+ const FontDescription& fontDescription() const { return m_fontDescription; }
+
+ int pixelSize() const { return fontDescription().computedPixelSize(); }
+ float size() const { return fontDescription().computedSize(); }
+
+ void update(PassRefPtr<FontSelector>) const;
+
+ void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const;
+
+ int width(const TextRun&) const;
+ float floatWidth(const TextRun&) const;
+ float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const;
+
+ int offsetForPosition(const TextRun&, int position, bool includePartialGlyphs) const;
+ FloatRect selectionRectForText(const TextRun&, const IntPoint&, int h, int from = 0, int to = -1) const;
+
+ bool isSmallCaps() const { return m_fontDescription.smallCaps(); }
+
+ 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(); }
+
+ FontRenderingMode renderingMode() const { return m_fontDescription.renderingMode(); }
+
+ FontFamily& firstFamily() { return m_fontDescription.firstFamily(); }
+ const FontFamily& family() const { return m_fontDescription.family(); }
+
+ 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 height() const { return ascent() + descent(); }
+ int lineSpacing() const;
+ int lineGap() const;
+ float xHeight() const;
+ unsigned unitsPerEm() const;
+ int spaceWidth() const;
+ int tabWidth() const { return 8 * spaceWidth(); }
+
+#if !PLATFORM(QT)
+ const SimpleFontData* primaryFont() const {
+ if (!m_cachedPrimaryFont)
+ cachePrimaryFont();
+ return m_cachedPrimaryFont;
+ }
+
+ const FontData* fontDataAt(unsigned) const;
+ const GlyphData& glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const;
+ // Used for complex text, and does not utilize the glyph map cache.
+ const FontData* fontDataForCharacters(const UChar*, int length) const;
+
+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;
+ float floatWidthUsingSVGFont(const TextRun&, int extraCharsAvailable, int& charsConsumed, String& glyphName) const;
+ FloatRect selectionRectForTextUsingSVGFont(const TextRun&, const IntPoint&, int h, int from, int to) const;
+ int offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const;
+#endif
+ 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;
+ 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.
+ enum CodePath { Auto, Simple, Complex };
+ static void setCodePath(CodePath);
+ static CodePath codePath();
+ static CodePath s_codePath;
+
+ static const uint8_t gRoundingHackCharacterTable[256];
+ static bool isRoundingHackCharacter(UChar32 c)
+ {
+ return (((c & ~0xFF) == 0 && gRoundingHackCharacterTable[c]));
+ }
+
+ 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; }
+
+#if ENABLE(SVG_FONTS)
+ bool isSVGFont() const;
+ SVGFontElement* svgFont() const;
+#endif
+
+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
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp
new file mode 100644
index 0000000..1c5a987
--- /dev/null
+++ b/WebCore/platform/graphics/FontCache.cpp
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "Font.h"
+#include "FontFallbackList.h"
+#include "FontPlatformData.h"
+#include "FontSelector.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+#include <wtf/ListHashSet.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+struct FontPlatformDataCacheKey {
+ FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false,
+ bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode)
+ : m_family(family)
+ , m_size(size)
+ , m_weight(weight)
+ , m_italic(italic)
+ , m_printerFont(isPrinterFont)
+ , m_renderingMode(renderingMode)
+ {
+ }
+
+ FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { }
+ bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); }
+
+ bool operator==(const FontPlatformDataCacheKey& other) const
+ {
+ return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size &&
+ m_weight == other.m_weight && m_italic == other.m_italic && m_printerFont == other.m_printerFont &&
+ m_renderingMode == other.m_renderingMode;
+ }
+
+ AtomicString m_family;
+ unsigned m_size;
+ unsigned m_weight;
+ bool m_italic;
+ bool m_printerFont;
+ FontRenderingMode m_renderingMode;
+
+private:
+ static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; }
+};
+
+inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
+{
+ unsigned hashCodes[4] = {
+ CaseFoldingHash::hash(fontKey.m_family),
+ fontKey.m_size,
+ fontKey.m_weight,
+ static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 | static_cast<unsigned>(fontKey.m_renderingMode)
+ };
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+}
+
+struct FontPlatformDataCacheKeyHash {
+ static unsigned hash(const FontPlatformDataCacheKey& font)
+ {
+ return computeHash(font);
+ }
+
+ static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> {
+ static const bool emptyValueIsZero = true;
+ static const FontPlatformDataCacheKey& emptyValue()
+ {
+ static FontPlatformDataCacheKey key(nullAtom);
+ return key;
+ }
+ static void constructDeletedValue(FontPlatformDataCacheKey& slot)
+ {
+ new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FontPlatformDataCacheKey& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache;
+
+static FontPlatformDataCache* gFontPlatformDataCache = 0;
+
+static const AtomicString& alternateFamilyName(const AtomicString& familyName)
+{
+ // Alias Courier <-> Courier New
+ static AtomicString courier("Courier"), 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");
+ if (equalIgnoringCase(familyName, times))
+ return timesNewRoman;
+ if (equalIgnoringCase(familyName, timesNewRoman))
+ return times;
+
+ // Alias Arial and Helvetica
+ static AtomicString arial("Arial"), helvetica("Helvetica");
+ if (equalIgnoringCase(familyName, arial))
+ return helvetica;
+ if (equalIgnoringCase(familyName, helvetica))
+ return arial;
+
+ return emptyAtom;
+}
+
+FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fontDescription,
+ const AtomicString& familyName,
+ bool checkingAlternateName)
+{
+ if (!gFontPlatformDataCache) {
+ gFontPlatformDataCache = new FontPlatformDataCache;
+ platformInit();
+ }
+
+ FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.weight(), fontDescription.italic(),
+ fontDescription.usePrinterFont(), fontDescription.renderingMode());
+ FontPlatformData* result = 0;
+ bool foundResult;
+ FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key);
+ if (it == gFontPlatformDataCache->end()) {
+ result = createFontPlatformData(fontDescription, familyName);
+ gFontPlatformDataCache->set(key, result);
+ foundResult = result;
+ } else {
+ result = it->second;
+ foundResult = true;
+ }
+
+ if (!foundResult && !checkingAlternateName) {
+ // We were unable to find a font. We have a small set of fonts that we alias to other names,
+ // e.g., Arial/Helvetica, Courier/Courier New, etc. Try looking up the font under the aliased name.
+ const AtomicString& alternateName = alternateFamilyName(familyName);
+ if (!alternateName.isEmpty())
+ result = getCachedFontPlatformData(fontDescription, alternateName, true);
+ if (result)
+ gFontPlatformDataCache->set(key, new FontPlatformData(*result)); // Cache the result under the old name.
+ }
+
+ return result;
+}
+
+struct FontDataCacheKeyHash {
+ static unsigned hash(const FontPlatformData& platformData)
+ {
+ return platformData.hash();
+ }
+
+ static bool equal(const FontPlatformData& a, const FontPlatformData& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = true;
+ static const FontPlatformData& emptyValue()
+ {
+ static FontPlatformData key;
+ return key;
+ }
+ static void constructDeletedValue(FontPlatformData& slot)
+ {
+ new (&slot) FontPlatformData(HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FontPlatformData& value)
+ {
+ return value.isHashTableDeletedValue();
+ }
+};
+
+typedef HashMap<FontPlatformData, pair<SimpleFontData*, unsigned>, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache;
+
+static FontDataCache* gFontDataCache = 0;
+
+const int cMaxInactiveFontData = 120; // Pretty Low Threshold
+const float cTargetInactiveFontData = 100;
+static ListHashSet<const SimpleFontData*>* gInactiveFontData = 0;
+
+SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* platformData)
+{
+ if (!platformData)
+ return 0;
+
+ if (!gFontDataCache) {
+ gFontDataCache = new FontDataCache;
+ gInactiveFontData = new ListHashSet<const SimpleFontData*>;
+ }
+
+ FontDataCache::iterator result = gFontDataCache->find(*platformData);
+ if (result == gFontDataCache->end()) {
+ pair<SimpleFontData*, unsigned> newValue(new SimpleFontData(*platformData), 1);
+ gFontDataCache->set(*platformData, newValue);
+ return newValue.first;
+ }
+ if (!result.get()->second.second++) {
+ ASSERT(gInactiveFontData->contains(result.get()->second.first));
+ gInactiveFontData->remove(result.get()->second.first);
+ }
+
+ return result.get()->second.first;
+}
+
+void FontCache::releaseFontData(const SimpleFontData* fontData)
+{
+ ASSERT(gFontDataCache);
+ ASSERT(!fontData->isCustomFont());
+
+ FontDataCache::iterator it = gFontDataCache->find(fontData->platformData());
+ ASSERT(it != gFontDataCache->end());
+
+ if (!--it->second.second) {
+ gInactiveFontData->add(fontData);
+ if (gInactiveFontData->size() > cMaxInactiveFontData)
+ purgeInactiveFontData(gInactiveFontData->size() - cTargetInactiveFontData);
+ }
+}
+
+void FontCache::purgeInactiveFontData(int count)
+{
+ if (!gInactiveFontData)
+ return;
+
+ static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData.
+ if (isPurging)
+ return;
+
+ isPurging = true;
+
+ ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontData->end();
+ ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontData->begin();
+ for (int i = 0; i < count && it != end; ++it, ++i) {
+ const SimpleFontData* fontData = *it.get();
+ gFontDataCache->remove(fontData->platformData());
+ delete fontData;
+ }
+
+ if (it == end) {
+ // Removed everything
+ gInactiveFontData->clear();
+ } else {
+ for (int i = 0; i < count; ++i)
+ gInactiveFontData->remove(gInactiveFontData->begin());
+ }
+
+ Vector<FontPlatformDataCacheKey> keysToRemove;
+ keysToRemove.reserveCapacity(gFontPlatformDataCache->size());
+ FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end();
+ for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) {
+ if (platformData->second && !gFontDataCache->contains(*platformData->second))
+ keysToRemove.append(platformData->first);
+ }
+
+ size_t keysToRemoveCount = keysToRemove.size();
+ for (size_t i = 0; i < keysToRemoveCount; ++i)
+ delete gFontPlatformDataCache->take(keysToRemove[i]);
+
+ isPurging = false;
+}
+
+size_t FontCache::fontDataCount()
+{
+ if (gFontDataCache)
+ return gFontDataCache->size();
+ return 0;
+}
+
+size_t FontCache::inactiveFontDataCount()
+{
+ if (gInactiveFontData)
+ return gInactiveFontData->size();
+ return 0;
+}
+
+const FontData* FontCache::getFontData(const Font& font, int& familyIndex, FontSelector* fontSelector)
+{
+ FontPlatformData* result = 0;
+
+ int startIndex = familyIndex;
+ const FontFamily* startFamily = &font.fontDescription().family();
+ for (int i = 0; startFamily && i < startIndex; i++)
+ startFamily = startFamily->next();
+ const FontFamily* currFamily = startFamily;
+ while (currFamily && !result) {
+ familyIndex++;
+ if (currFamily->family().length()) {
+ if (fontSelector) {
+ FontData* data = fontSelector->getFontData(font.fontDescription(), currFamily->family());
+ if (data)
+ return data;
+ }
+ result = getCachedFontPlatformData(font.fontDescription(), currFamily->family());
+ }
+ currFamily = currFamily->next();
+ }
+
+ if (!currFamily)
+ familyIndex = cAllFamiliesScanned;
+
+ if (!result)
+ // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform.
+ // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the
+ // Geeza Pro font.
+ result = getSimilarFontPlatformData(font);
+
+ if (!result && startIndex == 0) {
+ // If it's the primary font that we couldn't find, we try the following. In all other cases, we will
+ // just use per-character system fallback.
+
+ if (fontSelector) {
+ // Try the user's preferred standard font.
+ if (FontData* data = fontSelector->getFontData(font.fontDescription(), "-webkit-standard"))
+ return data;
+ }
+
+ // Still no result. Hand back our last resort fallback font.
+ result = getLastResortFallbackFont(font.fontDescription());
+ }
+
+ // Now that we have a result, we need to go from FontPlatformData -> FontData.
+ return getCachedFontData(result);
+}
+
+static HashSet<FontSelector*>* gClients;
+
+void FontCache::addClient(FontSelector* client)
+{
+ if (!gClients)
+ gClients = new HashSet<FontSelector*>;
+
+ ASSERT(!gClients->contains(client));
+ gClients->add(client);
+}
+
+void FontCache::removeClient(FontSelector* client)
+{
+ ASSERT(gClients);
+ ASSERT(gClients->contains(client));
+
+ gClients->remove(client);
+}
+
+static unsigned gGeneration = 0;
+
+unsigned FontCache::generation()
+{
+ return gGeneration;
+}
+
+void FontCache::invalidate()
+{
+ if (!gClients) {
+ ASSERT(!gFontPlatformDataCache);
+ return;
+ }
+
+ if (gFontPlatformDataCache) {
+ deleteAllValues(*gFontPlatformDataCache);
+ delete gFontPlatformDataCache;
+ gFontPlatformDataCache = new FontPlatformDataCache;
+ }
+
+ gGeneration++;
+
+ Vector<RefPtr<FontSelector> > clients;
+ size_t numClients = gClients->size();
+ clients.reserveCapacity(numClients);
+ HashSet<FontSelector*>::iterator end = gClients->end();
+ for (HashSet<FontSelector*>::iterator it = gClients->begin(); it != end; ++it)
+ clients.append(*it);
+
+ ASSERT(numClients == clients.size());
+ for (size_t i = 0; i < numClients; ++i)
+ clients[i]->fontCacheInvalidated();
+
+ purgeInactiveFontData();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h
new file mode 100644
index 0000000..816fe64
--- /dev/null
+++ b/WebCore/platform/graphics/FontCache.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Computer, 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 FontCache_h
+#define FontCache_h
+
+#include <limits.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+#if PLATFORM(WIN)
+#include <objidl.h>
+#include <mlang.h>
+#endif
+
+namespace WebCore
+{
+
+class AtomicString;
+class Font;
+class FontPlatformData;
+class FontData;
+class FontDescription;
+class FontSelector;
+class SimpleFontData;
+
+class FontCache {
+public:
+ static const FontData* getFontData(const Font&, int& familyIndex, FontSelector*);
+ static 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);
+
+ // Also implemented by the platform.
+ static void platformInit();
+
+#if PLATFORM(WIN)
+ static IMLangFontLink2* getFontLinkInterface();
+#endif
+
+ static 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&);
+
+ static void addClient(FontSelector*);
+ static void removeClient(FontSelector*);
+
+ static unsigned generation();
+ static void invalidate();
+
+ static size_t fontDataCount();
+ static size_t inactiveFontDataCount();
+ static void purgeInactiveFontData(int count = INT_MAX);
+
+private:
+ // These methods are implemented by each platform.
+ static FontPlatformData* getSimilarFontPlatformData(const Font&);
+ static FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family);
+
+ friend class SimpleFontData;
+ friend class FontFallbackList;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/FontData.cpp b/WebCore/platform/graphics/FontData.cpp
new file mode 100644
index 0000000..c40e13c
--- /dev/null
+++ b/WebCore/platform/graphics/FontData.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 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 "FontData.h"
+
+namespace WebCore {
+
+FontData::~FontData()
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/FontData.h b/WebCore/platform/graphics/FontData.h
new file mode 100644
index 0000000..cb79919
--- /dev/null
+++ b/WebCore/platform/graphics/FontData.h
@@ -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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontData_h
+#define FontData_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class SimpleFontData;
+
+class FontData : Noncopyable {
+public:
+ FontData()
+ : m_maxGlyphPageTreeLevel(0)
+ {
+ }
+
+ virtual ~FontData();
+
+ virtual const SimpleFontData* fontDataForCharacter(UChar32) const = 0;
+ virtual bool containsCharacters(const UChar*, int length) const = 0;
+ virtual bool isCustomFont() const = 0;
+ virtual bool isLoading() const = 0;
+ virtual bool isSegmented() const = 0;
+
+ void setMaxGlyphPageTreeLevel(unsigned level) const { m_maxGlyphPageTreeLevel = level; }
+ unsigned maxGlyphPageTreeLevel() const { return m_maxGlyphPageTreeLevel; }
+
+private:
+ mutable unsigned m_maxGlyphPageTreeLevel;
+};
+
+} // namespace WebCore
+
+#endif // FontData_h
diff --git a/WebCore/platform/graphics/FontDescription.cpp b/WebCore/platform/graphics/FontDescription.cpp
new file mode 100644
index 0000000..58ddf81
--- /dev/null
+++ b/WebCore/platform/graphics/FontDescription.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 Nicholas Shanks <contact@nickshanks.com>
+ * 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 "FontDescription.h"
+
+namespace WebCore {
+
+FontWeight FontDescription::lighterWeight(void) const
+{
+ // FIXME: Should actually return the CSS weight corresponding to next lightest
+ // weight of the currently used font family.
+ switch (m_weight) {
+ case FontWeight100:
+ case FontWeight200:
+ return FontWeight100;
+
+ case FontWeight300:
+ return FontWeight200;
+
+ case FontWeight400:
+ case FontWeight500:
+ return FontWeight300;
+
+ case FontWeight600:
+ case FontWeight700:
+ return FontWeight400;
+
+ case FontWeight800:
+ return FontWeight500;
+
+ case FontWeight900:
+ return FontWeight700;
+ }
+ ASSERT_NOT_REACHED();
+ return FontWeightNormal;
+}
+
+FontWeight FontDescription::bolderWeight(void) const
+{
+ // FIXME: Should actually return the CSS weight corresponding to next heaviest
+ // weight of the currently used font family.
+ switch (m_weight) {
+ case FontWeight100:
+ case FontWeight200:
+ return FontWeight300;
+
+ case FontWeight300:
+ return FontWeight400;
+
+ case FontWeight400:
+ case FontWeight500:
+ return FontWeight700;
+
+ case FontWeight600:
+ case FontWeight700:
+ return FontWeight800;
+
+ case FontWeight800:
+ case FontWeight900:
+ return FontWeight900;
+ }
+ ASSERT_NOT_REACHED();
+ return FontWeightNormal;
+}
+
+FontTraitsMask FontDescription::traitsMask() const
+{
+ return static_cast<FontTraitsMask>((m_italic ? FontStyleItalicMask : FontStyleNormalMask)
+ | (m_smallCaps ? FontVariantSmallCapsMask : FontVariantNormalMask)
+ | (FontWeight100Mask << (m_weight - FontWeight100)));
+
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/FontDescription.h b/WebCore/platform/graphics/FontDescription.h
new file mode 100644
index 0000000..d13e86a
--- /dev/null
+++ b/WebCore/platform/graphics/FontDescription.h
@@ -0,0 +1,139 @@
+/*
+ * 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, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * 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.LIother.m_ If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USm_
+ *
+ */
+
+#ifndef FontDescription_h
+#define FontDescription_h
+
+#include "FontFamily.h"
+#include "FontRenderingMode.h"
+#include "FontTraitsMask.h"
+
+namespace WebCore {
+
+enum FontWeight {
+ FontWeight100,
+ FontWeight200,
+ FontWeight300,
+ FontWeight400,
+ FontWeight500,
+ FontWeight600,
+ FontWeight700,
+ FontWeight800,
+ FontWeight900,
+ FontWeightNormal = FontWeight400,
+ FontWeightBold = FontWeight700
+};
+
+class FontDescription {
+public:
+ enum GenericFamilyType { NoFamily, StandardFamily, SerifFamily, SansSerifFamily,
+ MonospaceFamily, CursiveFamily, FantasyFamily };
+
+ FontDescription()
+ : m_specifiedSize(0)
+ , m_computedSize(0)
+ , m_italic(false)
+ , m_smallCaps(false)
+ , m_isAbsoluteSize(false)
+ , m_weight(FontWeightNormal)
+ , m_genericFamily(NoFamily)
+ , m_usePrinterFont(false)
+ , m_renderingMode(NormalRenderingMode)
+ , m_keywordSize(0)
+ {
+ }
+
+ bool operator==(const FontDescription&) const;
+ bool operator!=(const FontDescription& other) const { return !(*this == other); }
+
+ const FontFamily& family() const { return m_familyList; }
+ FontFamily& firstFamily() { return m_familyList; }
+ float specifiedSize() const { return m_specifiedSize; }
+ float computedSize() const { return m_computedSize; }
+ bool italic() const { return m_italic; }
+ int computedPixelSize() const { return int(m_computedSize + 0.5f); }
+ bool smallCaps() const { return m_smallCaps; }
+ bool isAbsoluteSize() const { return m_isAbsoluteSize; }
+ FontWeight weight() const { return static_cast<FontWeight>(m_weight); }
+ FontWeight lighterWeight() const;
+ FontWeight bolderWeight() const;
+ GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); }
+ bool usePrinterFont() const { return m_usePrinterFont; }
+ FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); }
+ int keywordSize() const { return m_keywordSize; }
+
+ FontTraitsMask traitsMask() const;
+
+ void setFamily(const FontFamily& family) { m_familyList = family; }
+ void setComputedSize(float s) { m_computedSize = s; }
+ void setSpecifiedSize(float s) { m_specifiedSize = s; }
+ void setItalic(bool i) { m_italic = i; }
+ void setSmallCaps(bool c) { m_smallCaps = c; }
+ void setIsAbsoluteSize(bool s) { m_isAbsoluteSize = s; }
+ void setWeight(FontWeight w) { m_weight = w; }
+ void setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; }
+ void setUsePrinterFont(bool p) { m_usePrinterFont = p; }
+ void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; }
+ void setKeywordSize(int s) { m_keywordSize = s; }
+
+private:
+ FontFamily m_familyList; // The list of font families to be used.
+
+ float m_specifiedSize; // Specified CSS value. Independent of rendering issues such as integer
+ // rounding, minimum font sizes, and zooming.
+ float m_computedSize; // Computed size adjusted for the minimum font size and the zoom factor.
+
+ bool m_italic : 1;
+ bool m_smallCaps : 1;
+ bool m_isAbsoluteSize : 1; // Whether or not CSS specified an explicit size
+ // (logical sizes like "medium" don't count).
+ unsigned m_weight : 8; // FontWeight
+ unsigned m_genericFamily : 3; // GenericFamilyType
+ bool m_usePrinterFont : 1;
+
+ unsigned m_renderingMode : 1; // Used to switch between CG and GDI text on Windows.
+
+ int m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so,
+ // then we can accurately translate across different generic families to adjust for different preference settings
+ // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>).
+};
+
+inline bool FontDescription::operator==(const FontDescription& other) const
+{
+ return m_familyList == other.m_familyList
+ && m_specifiedSize == other.m_specifiedSize
+ && m_computedSize == other.m_computedSize
+ && m_italic == other.m_italic
+ && m_smallCaps == other.m_smallCaps
+ && m_isAbsoluteSize == other.m_isAbsoluteSize
+ && m_weight == other.m_weight
+ && m_genericFamily == other.m_genericFamily
+ && m_usePrinterFont == other.m_usePrinterFont
+ && m_renderingMode == other.m_renderingMode
+ && m_keywordSize == other.m_keywordSize;
+}
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp
new file mode 100644
index 0000000..ef59c2f
--- /dev/null
+++ b/WebCore/platform/graphics/FontFallbackList.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "FontFallbackList.h"
+
+#include "Font.h"
+#include "FontCache.h"
+#include "SegmentedFontData.h"
+
+namespace WebCore {
+
+FontFallbackList::FontFallbackList()
+ : m_familyIndex(0)
+ , m_pitch(UnknownPitch)
+ , m_loadingCustomFonts(false)
+ , m_fontSelector(0)
+ , m_generation(FontCache::generation())
+{
+}
+
+void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector)
+{
+ releaseFontData();
+ m_fontList.clear();
+ m_familyIndex = 0;
+ m_pitch = UnknownPitch;
+ m_loadingCustomFonts = false;
+ m_fontSelector = fontSelector;
+ m_generation = FontCache::generation();
+}
+
+void FontFallbackList::releaseFontData()
+{
+ unsigned numFonts = m_fontList.size();
+ 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));
+ }
+ }
+}
+
+void FontFallbackList::determinePitch(const 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 Font* font, unsigned realizedFontIndex) const
+{
+ if (realizedFontIndex < m_fontList.size())
+ return m_fontList[realizedFontIndex].first; // This fallback font is already in our list.
+
+ // Make sure we're not passing in some crazy value here.
+ ASSERT(realizedFontIndex == m_fontList.size());
+
+ if (m_familyIndex == cAllFamiliesScanned)
+ return 0;
+
+ // Ask the font cache for the font data.
+ // 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());
+ if (result) {
+ m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont()));
+ if (result->isLoading())
+ m_loadingCustomFonts = true;
+ }
+ return result;
+}
+
+const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const UChar* characters, int length) const
+{
+ // This method is only called when the primary font does not contain the characters we need.
+ // Begin our search at position 1.
+ unsigned realizedFontIndex = 1;
+ const FontData* fontData = fontDataAt(font, realizedFontIndex);
+ while (fontData && !fontData->containsCharacters(characters, length))
+ fontData = fontDataAt(font, ++realizedFontIndex);
+
+ if (!fontData) {
+ ASSERT(FontCache::generation() == m_generation);
+ fontData = FontCache::getFontDataForCharacters(*font, characters, length);
+ }
+
+ return fontData;
+}
+
+void FontFallbackList::setPlatformFont(const FontPlatformData& platformData)
+{
+ m_familyIndex = cAllFamiliesScanned;
+ 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/FontFallbackList.h b/WebCore/platform/graphics/FontFallbackList.h
new file mode 100644
index 0000000..a23b32c
--- /dev/null
+++ b/WebCore/platform/graphics/FontFallbackList.h
@@ -0,0 +1,79 @@
+/*
+ * 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 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+// This file has no guards on purpose in order to detect redundant includes. This is a private header
+// and so this may catch someone trying to include this file in public cpp files.
+
+#include "FontSelector.h"
+#include "SimpleFontData.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class Font;
+class GraphicsContext;
+class IntRect;
+class FontDescription;
+class FontPlatformData;
+class FontSelector;
+
+const int cAllFamiliesScanned = -1;
+
+class FontFallbackList : public RefCounted<FontFallbackList> {
+public:
+ static PassRefPtr<FontFallbackList> create() { return adoptRef(new FontFallbackList()); }
+
+ ~FontFallbackList() { releaseFontData(); }
+ void invalidate(PassRefPtr<FontSelector>);
+
+ bool isFixedPitch(const Font* f) const { if (m_pitch == UnknownPitch) determinePitch(f); return m_pitch == FixedPitch; };
+ void determinePitch(const Font*) const;
+
+ bool loadingCustomFonts() const { return m_loadingCustomFonts; }
+
+ FontSelector* fontSelector() const { return m_fontSelector.get(); }
+ unsigned generation() const { return m_generation; }
+
+private:
+ FontFallbackList();
+
+ const FontData* primaryFont(const Font* f) const { return fontDataAt(f, 0); }
+ const FontData* fontDataAt(const Font*, unsigned index) const;
+ const FontData* fontDataForCharacters(const Font*, const UChar*, int length) const;
+
+ void setPlatformFont(const FontPlatformData&);
+
+ void releaseFontData();
+
+ mutable Vector<pair<const FontData*, bool>, 1> m_fontList;
+ mutable int m_familyIndex;
+ mutable Pitch m_pitch;
+ mutable bool m_loadingCustomFonts;
+ RefPtr<FontSelector> m_fontSelector;
+ unsigned m_generation;
+
+ friend class Font;
+};
+
+}
+
diff --git a/WebCore/platform/graphics/FontFamily.cpp b/WebCore/platform/graphics/FontFamily.cpp
new file mode 100644
index 0000000..12b59a4
--- /dev/null
+++ b/WebCore/platform/graphics/FontFamily.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2004, 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 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 "FontFamily.h"
+
+namespace WebCore {
+
+FontFamily::FontFamily(const FontFamily& other)
+ : m_family(other.m_family)
+ , m_next(other.m_next)
+{
+}
+
+FontFamily& FontFamily::operator=(const FontFamily& other)
+{
+ m_family = other.m_family;
+ m_next = other.m_next;
+ return *this;
+}
+
+bool operator==(const FontFamily& a, const FontFamily& b)
+{
+ if (a.family() != b.family())
+ return false;
+ const FontFamily* ap;
+ const FontFamily* bp;
+ for (ap = a.next(), bp = b.next(); ap != bp; ap = ap->next(), bp = bp->next()) {
+ if (!ap || !bp)
+ return false;
+ if (ap->family() != bp->family())
+ return false;
+ }
+ return true;
+}
+
+}
diff --git a/WebCore/platform/graphics/FontFamily.h b/WebCore/platform/graphics/FontFamily.h
new file mode 100644
index 0000000..126bd83
--- /dev/null
+++ b/WebCore/platform/graphics/FontFamily.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2003, 2006, 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontFamily_h
+#define FontFamily_h
+
+#include "AtomicString.h"
+#include <wtf/RefCounted.h>
+#include <wtf/ListRefPtr.h>
+
+namespace WebCore {
+
+class SharedFontFamily;
+
+class FontFamily {
+public:
+ FontFamily() { }
+ FontFamily(const FontFamily&);
+ FontFamily& operator=(const FontFamily&);
+
+ void setFamily(const AtomicString& family) { m_family = family; }
+ const AtomicString& family() const { return m_family; }
+ bool familyIsEmpty() const { return m_family.isEmpty(); }
+
+ const FontFamily* next() const;
+
+ void appendFamily(PassRefPtr<SharedFontFamily>);
+ PassRefPtr<SharedFontFamily> releaseNext();
+
+private:
+ AtomicString m_family;
+ ListRefPtr<SharedFontFamily> m_next;
+};
+
+class SharedFontFamily : public FontFamily, public RefCounted<SharedFontFamily> {
+public:
+ static PassRefPtr<SharedFontFamily> create()
+ {
+ return adoptRef(new SharedFontFamily);
+ }
+
+private:
+ SharedFontFamily() { }
+};
+
+bool operator==(const FontFamily&, const FontFamily&);
+inline bool operator!=(const FontFamily& a, const FontFamily& b) { return !(a == b); }
+
+inline const FontFamily* FontFamily::next() const
+{
+ return m_next.get();
+}
+
+inline void FontFamily::appendFamily(PassRefPtr<SharedFontFamily> family)
+{
+ m_next = family;
+}
+
+inline PassRefPtr<SharedFontFamily> FontFamily::releaseNext()
+{
+ return m_next.release();
+}
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/FontRenderingMode.h b/WebCore/platform/graphics/FontRenderingMode.h
new file mode 100644
index 0000000..c1ce497
--- /dev/null
+++ b/WebCore/platform/graphics/FontRenderingMode.h
@@ -0,0 +1,37 @@
+/*
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontRenderingMode_h
+#define FontRenderingMode_h
+
+namespace WebCore {
+
+// This setting is used to provide ways of switching between multiple rendering modes that may have different
+// metrics. It is used to switch between CG and GDI text on Windows.
+enum FontRenderingMode { NormalRenderingMode, AlternateRenderingMode };
+
+} // namespace WebCore
+
+#endif // FontRenderingMode_h
diff --git a/WebCore/platform/graphics/FontSelector.h b/WebCore/platform/graphics/FontSelector.h
new file mode 100644
index 0000000..9b520b9
--- /dev/null
+++ b/WebCore/platform/graphics/FontSelector.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007, 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontSelector_h
+#define FontSelector_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class AtomicString;
+class FontData;
+class FontDescription;
+
+class FontSelector : public RefCounted<FontSelector> {
+public:
+ virtual ~FontSelector() { }
+ virtual FontData* getFontData(const FontDescription&, const AtomicString& familyName) = 0;
+
+ virtual void fontCacheInvalidated() { }
+};
+
+} // namespace WebCore
+
+#endif // FontSelector_h
diff --git a/WebCore/platform/graphics/FontTraitsMask.h b/WebCore/platform/graphics/FontTraitsMask.h
new file mode 100644
index 0000000..686c30c
--- /dev/null
+++ b/WebCore/platform/graphics/FontTraitsMask.h
@@ -0,0 +1,70 @@
+/*
+ * 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 FontTraitsMask_h
+#define FontTraitsMask_h
+
+namespace WebCore {
+
+ enum {
+ FontStyleNormalBit = 0,
+ FontStyleItalicBit,
+ FontVariantNormalBit,
+ FontVariantSmallCapsBit,
+ FontWeight100Bit,
+ FontWeight200Bit,
+ FontWeight300Bit,
+ FontWeight400Bit,
+ FontWeight500Bit,
+ FontWeight600Bit,
+ FontWeight700Bit,
+ FontWeight800Bit,
+ FontWeight900Bit,
+ FontTraitsMaskWidth
+ };
+
+ enum FontTraitsMask {
+ FontStyleNormalMask = 1 << FontStyleNormalBit,
+ FontStyleItalicMask = 1 << FontStyleItalicBit,
+ FontStyleMask = FontStyleNormalMask | FontStyleItalicMask,
+
+ FontVariantNormalMask = 1 << FontVariantNormalBit,
+ FontVariantSmallCapsMask = 1 << FontVariantSmallCapsBit,
+ FontVariantMask = FontVariantNormalMask | FontVariantSmallCapsMask,
+
+ FontWeight100Mask = 1 << FontWeight100Bit,
+ FontWeight200Mask = 1 << FontWeight200Bit,
+ FontWeight300Mask = 1 << FontWeight300Bit,
+ FontWeight400Mask = 1 << FontWeight400Bit,
+ FontWeight500Mask = 1 << FontWeight500Bit,
+ FontWeight600Mask = 1 << FontWeight600Bit,
+ FontWeight700Mask = 1 << FontWeight700Bit,
+ FontWeight800Mask = 1 << FontWeight800Bit,
+ FontWeight900Mask = 1 << FontWeight900Bit,
+ FontWeightMask = FontWeight100Mask | FontWeight200Mask | FontWeight300Mask | FontWeight400Mask | FontWeight500Mask | FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask
+ };
+
+} // namespace WebCore
+#endif // FontTraitsMask_h
diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp
new file mode 100644
index 0000000..5e50959
--- /dev/null
+++ b/WebCore/platform/graphics/GeneratedImage.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 Apple Computer, 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 "GeneratedImage.h"
+
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+
+using namespace std;
+
+namespace WebCore {
+
+void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
+{
+ context->save();
+ context->setCompositeOperation(compositeOp);
+ context->clip(dstRect);
+ context->translate(dstRect.x(), dstRect.y());
+ if (dstRect.size() != srcRect.size())
+ context->scale(FloatSize(dstRect.width() / srcRect.width(), dstRect.height() / srcRect.height()));
+ context->translate(-srcRect.x(), -srcRect.y());
+ context->fillRect(FloatRect(FloatPoint(), m_size), *m_generator.get());
+ context->restore();
+}
+
+void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect)
+{
+ // Create a BitmapImage and call drawPattern on it.
+ auto_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size, false);
+ ASSERT(imageBuffer.get());
+
+ // Fill with the gradient.
+ GraphicsContext* graphicsContext = imageBuffer->context();
+ graphicsContext->fillRect(FloatRect(FloatPoint(), m_size), *m_generator.get());
+
+ // Grab the final image from the image buffer.
+ Image* bitmap = imageBuffer->image();
+
+ // Now just call drawTiled on that image.
+ bitmap->drawPattern(context, srcRect, patternTransform, phase, compositeOp, destRect);
+}
+
+}
diff --git a/WebCore/platform/graphics/GeneratedImage.h b/WebCore/platform/graphics/GeneratedImage.h
new file mode 100644
index 0000000..fb0661b
--- /dev/null
+++ b/WebCore/platform/graphics/GeneratedImage.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GeneratedImage_h
+#define GeneratedImage_h
+
+#include "Image.h"
+
+#include "Generator.h"
+#include "IntSize.h"
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class GeneratedImage : public Image {
+public:
+ static PassRefPtr<GeneratedImage> create(PassRefPtr<Generator> generator, const IntSize& size)
+ {
+ return adoptRef(new GeneratedImage(generator, size));
+ }
+ virtual ~GeneratedImage() {}
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+
+ // These are only used for SVGGeneratedImage right now
+ virtual void setContainerSize(const IntSize& size) { m_size = size; }
+ virtual bool usesContainerSize() const { return true; }
+ virtual bool hasRelativeWidth() const { return true; }
+ virtual bool hasRelativeHeight() const { return true; }
+
+ 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 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,
+ const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
+
+protected:
+ GeneratedImage(PassRefPtr<Generator> generator, const IntSize& size)
+ : m_generator(generator)
+ , m_size(size)
+ {
+ }
+
+ RefPtr<Generator> m_generator;
+ IntSize m_size;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/Generator.h b/WebCore/platform/graphics/Generator.h
new file mode 100644
index 0000000..a0af689
--- /dev/null
+++ b/WebCore/platform/graphics/Generator.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Generator_h
+#define Generator_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class FloatRect;
+class GraphicsContext;
+
+class Generator : public RefCounted<Generator> {
+public:
+ virtual ~Generator() {};
+
+ virtual void fill(GraphicsContext*, const FloatRect&) = 0;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
new file mode 100644
index 0000000..18957d5
--- /dev/null
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 GlyphBuffer_h
+#define GlyphBuffer_h
+
+#include "FloatSize.h"
+
+#if PLATFORM(CG)
+#include <ApplicationServices/ApplicationServices.h>
+#elif PLATFORM(CAIRO)
+#include <cairo.h>
+#endif
+
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+typedef unsigned short Glyph;
+class SimpleFontData;
+
+#if PLATFORM(CAIRO)
+// FIXME: Why does Cairo use such a huge struct instead of just an offset into an array?
+typedef cairo_glyph_t GlyphBufferGlyph;
+#else
+typedef Glyph GlyphBufferGlyph;
+#endif
+
+// CG uses CGSize instead of FloatSize so that the result of advances()
+// can be passed directly to CGContextShowGlyphsWithAdvances in FontMac.mm
+#if PLATFORM(CG)
+typedef CGSize GlyphBufferAdvance;
+#else
+typedef FloatSize GlyphBufferAdvance;
+#endif
+
+class GlyphBuffer {
+public:
+ bool isEmpty() const { return m_fontData.isEmpty(); }
+ int size() const { return m_fontData.size(); }
+
+ void clear()
+ {
+ m_fontData.clear();
+ m_glyphs.clear();
+ m_advances.clear();
+#if PLATFORM(WIN)
+ m_offsets.clear();
+#endif
+ }
+
+ GlyphBufferGlyph* glyphs(int from) { return m_glyphs.data() + from; }
+ GlyphBufferAdvance* advances(int from) { return m_advances.data() + from; }
+ const GlyphBufferGlyph* glyphs(int from) const { return m_glyphs.data() + from; }
+ const GlyphBufferAdvance* advances(int from) const { return m_advances.data() + from; }
+
+ const SimpleFontData* fontDataAt(int index) const { return m_fontData[index]; }
+
+ void swap(int index1, int index2)
+ {
+ const SimpleFontData* f = m_fontData[index1];
+ m_fontData[index1] = m_fontData[index2];
+ m_fontData[index2] = f;
+
+ GlyphBufferGlyph g = m_glyphs[index1];
+ m_glyphs[index1] = m_glyphs[index2];
+ m_glyphs[index2] = g;
+
+ GlyphBufferAdvance s = m_advances[index1];
+ m_advances[index1] = m_advances[index2];
+ m_advances[index2] = s;
+
+#if PLATFORM(WIN)
+ FloatSize offset = m_offsets[index1];
+ m_offsets[index1] = m_offsets[index2];
+ m_offsets[index2] = offset;
+#endif
+ }
+
+ Glyph glyphAt(int index) const
+ {
+#if PLATFORM(CAIRO)
+ return m_glyphs[index].index;
+#else
+ return m_glyphs[index];
+#endif
+ }
+
+ float advanceAt(int index) const
+ {
+#if PLATFORM(CG)
+ return m_advances[index].width;
+#else
+ return m_advances[index].width();
+#endif
+ }
+
+ FloatSize offsetAt(int index) const
+ {
+#if PLATFORM(WIN)
+ return m_offsets[index];
+#else
+ return FloatSize();
+#endif
+ }
+
+ 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;
+ m_glyphs.append(cairoGlyph);
+#else
+ m_glyphs.append(glyph);
+#endif
+
+#if PLATFORM(CG)
+ CGSize advance = { width, 0 };
+ m_advances.append(advance);
+#else
+ m_advances.append(FloatSize(width, 0));
+#endif
+
+#if PLATFORM(WIN)
+ if (offset)
+ m_offsets.append(*offset);
+ else
+ m_offsets.append(FloatSize());
+#endif
+ }
+
+ void add(Glyph glyph, const SimpleFontData* font, GlyphBufferAdvance advance)
+ {
+ m_fontData.append(font);
+#if PLATFORM(CAIRO)
+ cairo_glyph_t cairoGlyph;
+ cairoGlyph.index = glyph;
+ m_glyphs.append(cairoGlyph);
+#else
+ m_glyphs.append(glyph);
+#endif
+
+ m_advances.append(advance);
+ }
+
+private:
+ Vector<const SimpleFontData*, 2048> m_fontData;
+ Vector<GlyphBufferGlyph, 2048> m_glyphs;
+ Vector<GlyphBufferAdvance, 2048> m_advances;
+#if PLATFORM(WIN)
+ Vector<FloatSize, 2048> m_offsets;
+#endif
+};
+
+}
+#endif
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
new file mode 100644
index 0000000..6b9d23d
--- /dev/null
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2006, 2007, 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 "GlyphPageTreeNode.h"
+
+#include "CharacterNames.h"
+#include "SegmentedFontData.h"
+#include "SimpleFontData.h"
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+using std::max;
+using std::min;
+
+HashMap<int, GlyphPageTreeNode*>* GlyphPageTreeNode::roots = 0;
+GlyphPageTreeNode* GlyphPageTreeNode::pageZeroRoot = 0;
+
+GlyphPageTreeNode* GlyphPageTreeNode::getRoot(unsigned pageNumber)
+{
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+ roots = new HashMap<int, GlyphPageTreeNode*>;
+ pageZeroRoot = new GlyphPageTreeNode;
+ }
+
+ GlyphPageTreeNode* node = pageNumber ? roots->get(pageNumber) : pageZeroRoot;
+ if (!node) {
+ node = new GlyphPageTreeNode;
+#ifndef NDEBUG
+ node->m_pageNumber = pageNumber;
+#endif
+ if (pageNumber)
+ roots->set(pageNumber, node);
+ else
+ pageZeroRoot = node;
+ }
+ return node;
+}
+
+size_t GlyphPageTreeNode::treeGlyphPageCount()
+{
+ size_t count = 0;
+ if (roots) {
+ HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end();
+ for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); it != end; ++it)
+ count += it->second->pageCount();
+ }
+
+ if (pageZeroRoot)
+ count += pageZeroRoot->pageCount();
+
+ return count;
+}
+
+size_t GlyphPageTreeNode::pageCount() const
+{
+ size_t count = m_page && m_page->owner() == this ? 1 : 0;
+ HashMap<const FontData*, GlyphPageTreeNode*>::const_iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::const_iterator it = m_children.begin(); it != end; ++it)
+ count += it->second->pageCount();
+
+ return count;
+}
+
+void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData)
+{
+ // Enumerate all the roots and prune any tree that contains our custom font data.
+ if (roots) {
+ HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end();
+ for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); it != end; ++it)
+ it->second->pruneCustomFontData(fontData);
+ }
+
+ if (pageZeroRoot)
+ pageZeroRoot->pruneCustomFontData(fontData);
+}
+
+void GlyphPageTreeNode::pruneTreeFontData(const SimpleFontData* fontData)
+{
+ if (roots) {
+ HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end();
+ for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); it != end; ++it)
+ it->second->pruneFontData(fontData);
+ }
+
+ if (pageZeroRoot)
+ pageZeroRoot->pruneFontData(fontData);
+}
+
+GlyphPageTreeNode::~GlyphPageTreeNode()
+{
+ deleteAllValues(m_children);
+ delete m_systemFallbackChild;
+}
+
+void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNumber)
+{
+ ASSERT(!m_page);
+
+ // This function must not be called for the root of the tree, because that
+ // level does not contain any glyphs.
+ ASSERT(m_level > 0 && m_parent);
+
+ // The parent's page will be 0 if we are level one or the parent's font data
+ // did not contain any glyphs for that page.
+ GlyphPage* parentPage = m_parent->page();
+
+ // NULL FontData means we're being asked for the system fallback font.
+ if (fontData) {
+ if (m_level == 1) {
+ // Children of the root hold pure pages. These will cover only one
+ // font data's glyphs, and will have glyph index 0 if the font data does not
+ // contain the glyph.
+ unsigned start = pageNumber * GlyphPage::size;
+ UChar buffer[GlyphPage::size * 2 + 2];
+ unsigned bufferLength;
+ unsigned i;
+
+ // Fill in a buffer with the entire "page" of characters that we want to look up glyphs for.
+ if (start < 0x10000) {
+ bufferLength = GlyphPage::size;
+ for (i = 0; i < GlyphPage::size; i++)
+ buffer[i] = start + i;
+
+ if (start == 0) {
+ // Control characters must not render at all.
+ for (i = 0; i < 0x20; ++i)
+ buffer[i] = zeroWidthSpace;
+ for (i = 0x7F; i < 0xA0; i++)
+ buffer[i] = zeroWidthSpace;
+
+ // \n, \t, and nonbreaking space must render as a space.
+ buffer[(int)'\n'] = ' ';
+ buffer[(int)'\t'] = ' ';
+ buffer[noBreakSpace] = ' ';
+ } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) {
+ // LRM, RLM, LRE, RLE and PDF must not render at all.
+ buffer[leftToRightMark - start] = zeroWidthSpace;
+ buffer[rightToLeftMark - start] = zeroWidthSpace;
+ buffer[leftToRightEmbed - start] = zeroWidthSpace;
+ buffer[rightToLeftEmbed - start] = zeroWidthSpace;
+ buffer[leftToRightOverride - start] = zeroWidthSpace;
+ buffer[rightToLeftOverride - start] = zeroWidthSpace;
+ buffer[popDirectionalFormatting - start] = zeroWidthSpace;
+ } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) {
+ // Object replacement character must not render at all.
+ buffer[objectReplacementCharacter - start] = zeroWidthSpace;
+ }
+ } else {
+ bufferLength = GlyphPage::size * 2;
+ for (i = 0; i < GlyphPage::size; i++) {
+ int c = i + start;
+ buffer[i * 2] = U16_LEAD(c);
+ buffer[i * 2 + 1] = U16_TRAIL(c);
+ }
+ }
+
+ m_page = GlyphPage::create(this);
+
+ // Now that we have a buffer full of characters, we want to get back an array
+ // of glyph indices. This part involves calling into the platform-specific
+ // routine of our glyph map for actually filling in the page with the glyphs.
+ // Success is not guaranteed. For example, Times fails to fill page 260, giving glyph data
+ // for only 128 out of 256 characters.
+ bool haveGlyphs;
+ if (fontData->isSegmented()) {
+ haveGlyphs = false;
+
+ const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData);
+ unsigned numRanges = segmentedFontData->numRanges();
+ bool zeroFilled = false;
+ RefPtr<GlyphPage> scratchPage;
+ GlyphPage* pageToFill = m_page.get();
+ for (unsigned i = 0; i < numRanges; i++) {
+ const FontDataRange& range = segmentedFontData->rangeAt(i);
+ int from = max(0, range.from() - static_cast<int>(start));
+ int to = 1 + min(range.to() - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1);
+ if (from < static_cast<int>(GlyphPage::size) && to > 0) {
+ if (haveGlyphs && !scratchPage) {
+ scratchPage = GlyphPage::create(this);
+ pageToFill = scratchPage.get();
+ }
+
+ if (!zeroFilled) {
+ if (from > 0 || to < static_cast<int>(GlyphPage::size)) {
+ for (unsigned i = 0; i < GlyphPage::size; i++)
+ pageToFill->setGlyphDataForIndex(i, 0, 0);
+ }
+ zeroFilled = true;
+ }
+ haveGlyphs |= pageToFill->fill(from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), range.fontData());
+ if (scratchPage) {
+ for (int j = from; j < to; j++) {
+ if (!m_page->m_glyphs[j].glyph && pageToFill->m_glyphs[j].glyph)
+ m_page->m_glyphs[j] = pageToFill->m_glyphs[j];
+ }
+ }
+ }
+ }
+ } else
+ haveGlyphs = m_page->fill(0, GlyphPage::size, buffer, bufferLength, static_cast<const SimpleFontData*>(fontData));
+
+ if (!haveGlyphs)
+ m_page = 0;
+ } else if (parentPage && parentPage->owner() != m_parent) {
+ // The page we're overriding may not be owned by our parent node.
+ // This happens when our parent node provides no useful overrides
+ // and just copies the pointer to an already-existing page (see
+ // below).
+ //
+ // We want our override to be shared by all nodes that reference
+ // that page to avoid duplication, and so standardize on having the
+ // page's owner collect all the overrides. Call getChild on the
+ // page owner with the desired font data (this will populate
+ // the page) and then reference it.
+ m_page = parentPage->owner()->getChild(fontData, pageNumber)->page();
+ } else {
+ // Get the pure page for the fallback font (at level 1 with no
+ // overrides). getRootChild will always create a page if one
+ // doesn't exist, but the page doesn't necessarily have glyphs
+ // (this pointer may be 0).
+ GlyphPage* fallbackPage = getRootChild(fontData, pageNumber)->page();
+ if (!parentPage) {
+ // When the parent has no glyphs for this page, we can easily
+ // override it just by supplying the glyphs from our font.
+ m_page = fallbackPage;
+ } else if (!fallbackPage) {
+ // When our font has no glyphs for this page, we can just reference the
+ // parent page.
+ m_page = parentPage;
+ } else {
+ // Combine the parent's glyphs and ours to form a new more complete page.
+ m_page = GlyphPage::create(this);
+
+ // Overlay the parent page on the fallback page. Check if the fallback font
+ // has added anything.
+ bool newGlyphs = false;
+ for (unsigned i = 0; i < GlyphPage::size; i++) {
+ if (parentPage->m_glyphs[i].glyph)
+ m_page->m_glyphs[i] = parentPage->m_glyphs[i];
+ else if (fallbackPage->m_glyphs[i].glyph) {
+ m_page->m_glyphs[i] = fallbackPage->m_glyphs[i];
+ newGlyphs = true;
+ } else {
+ const GlyphData data = { 0, 0 };
+ m_page->m_glyphs[i] = data;
+ }
+ }
+
+ if (!newGlyphs)
+ // We didn't override anything, so our override is just the parent page.
+ m_page = parentPage;
+ }
+ }
+ } else {
+ m_page = GlyphPage::create(this);
+ // System fallback. Initialized with the parent's page here, as individual
+ // entries may use different fonts depending on character. If the Font
+ // ever finds it needs a glyph out of the system fallback page, it will
+ // ask the system for the best font to use and fill that glyph in for us.
+ if (parentPage)
+ memcpy(m_page->m_glyphs, parentPage->m_glyphs, GlyphPage::size * sizeof(m_page->m_glyphs[0]));
+ else {
+ const GlyphData data = { 0, 0 };
+ for (unsigned i = 0; i < GlyphPage::size; i++)
+ m_page->m_glyphs[i] = data;
+ }
+ }
+}
+
+GlyphPageTreeNode* GlyphPageTreeNode::getChild(const FontData* fontData, unsigned pageNumber)
+{
+ ASSERT(fontData || !m_isSystemFallback);
+ ASSERT(pageNumber == m_pageNumber);
+
+ GlyphPageTreeNode* child = fontData ? m_children.get(fontData) : m_systemFallbackChild;
+ if (!child) {
+ child = new GlyphPageTreeNode;
+ child->m_parent = this;
+ child->m_level = m_level + 1;
+ if (fontData && fontData->isCustomFont()) {
+ for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent)
+ curr->m_customFontCount++;
+ }
+
+#ifndef NDEBUG
+ child->m_pageNumber = m_pageNumber;
+#endif
+ if (fontData) {
+ m_children.set(fontData, child);
+ fontData->setMaxGlyphPageTreeLevel(max(fontData->maxGlyphPageTreeLevel(), child->m_level));
+ } else {
+ m_systemFallbackChild = child;
+ child->m_isSystemFallback = true;
+ }
+ child->initializePage(fontData, pageNumber);
+ }
+ return child;
+}
+
+void GlyphPageTreeNode::pruneCustomFontData(const FontData* fontData)
+{
+ if (!fontData || !m_customFontCount)
+ return;
+
+ // Prune any branch that contains this FontData.
+ GlyphPageTreeNode* node = m_children.get(fontData);
+ if (node) {
+ m_children.remove(fontData);
+ unsigned fontCount = node->m_customFontCount + 1;
+ delete node;
+ for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent)
+ curr->m_customFontCount -= fontCount;
+ }
+
+ // Check any branches that remain that still have custom fonts underneath them.
+ if (!m_customFontCount)
+ return;
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::iterator it = m_children.begin(); it != end; ++it)
+ it->second->pruneCustomFontData(fontData);
+}
+
+void GlyphPageTreeNode::pruneFontData(const SimpleFontData* fontData, unsigned level)
+{
+ ASSERT(fontData);
+ if (!fontData)
+ return;
+
+ // Prune any branch that contains this FontData.
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator child = m_children.find(fontData);
+ if (child == m_children.end()) {
+ // If there is no level-1 node for fontData, then there is no deeper node for it in this tree.
+ if (!level)
+ return;
+ } else {
+ GlyphPageTreeNode* node = child->second;
+ m_children.remove(fontData);
+ unsigned customFontCount = node->m_customFontCount;
+ delete node;
+ if (customFontCount) {
+ for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent)
+ curr->m_customFontCount -= customFontCount;
+ }
+ }
+
+ level++;
+ if (level > fontData->maxGlyphPageTreeLevel())
+ return;
+
+ HashMap<const FontData*, GlyphPageTreeNode*>::iterator end = m_children.end();
+ for (HashMap<const FontData*, GlyphPageTreeNode*>::iterator it = m_children.begin(); it != end; ++it)
+ it->second->pruneFontData(fontData, level);
+}
+
+}
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.h b/WebCore/platform/graphics/GlyphPageTreeNode.h
new file mode 100644
index 0000000..240b492
--- /dev/null
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2006, 2007, 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 GlyphPageTreeNode_h
+#define GlyphPageTreeNode_h
+
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class FontData;
+class GlyphPageTreeNode;
+class SimpleFontData;
+
+typedef unsigned short Glyph;
+
+// Holds the glyph index and the corresponding SimpleFontData information for a given
+// character.
+struct GlyphData {
+ Glyph glyph;
+ const SimpleFontData* fontData;
+};
+
+// A GlyphPage contains a fixed-size set of GlyphData mappings for a contiguous
+// range of characters in the Unicode code space. GlyphPages are indexed
+// starting from 0 and incrementing for each 256 glyphs.
+//
+// One page may actually include glyphs from other fonts if the characters are
+// missing in the parimary font. It is owned by exactly one GlyphPageTreeNode,
+// although multiple nodes may reference it as their "page" if they are supposed
+// to be overriding the parent's node, but provide no additional information.
+struct GlyphPage : public RefCounted<GlyphPage> {
+ static PassRefPtr<GlyphPage> create(GlyphPageTreeNode* owner)
+ {
+ return adoptRef(new GlyphPage(owner));
+ }
+
+ static const size_t size = 256; // Covers Latin-1 in a single page.
+ GlyphData m_glyphs[size];
+ GlyphPageTreeNode* m_owner;
+
+ const GlyphData& glyphDataForCharacter(UChar32 c) const { return m_glyphs[c % size]; }
+ void setGlyphDataForCharacter(UChar32 c, Glyph g, const SimpleFontData* f)
+ {
+ setGlyphDataForIndex(c % size, g, f);
+ }
+ void setGlyphDataForIndex(unsigned index, Glyph g, const SimpleFontData* f)
+ {
+ ASSERT(index < size);
+ m_glyphs[index].glyph = g;
+ m_glyphs[index].fontData = f;
+ }
+ GlyphPageTreeNode* owner() const { return m_owner; }
+
+ // Implemented by the platform.
+ bool fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const SimpleFontData*);
+
+private:
+ GlyphPage(GlyphPageTreeNode* owner)
+ : m_owner(owner)
+ {
+ }
+};
+
+// The glyph page tree is a data structure that maps (FontData, glyph page number)
+// to a GlyphPage. Level 0 (the "root") is special. There is one root
+// GlyphPageTreeNode for each glyph page number. The roots do not have a
+// GlyphPage associated with them, and their initializePage() function is never
+// called to fill the glyphs.
+//
+// Each root node maps a FontData pointer to another GlyphPageTreeNode at
+// level 1 (the "root child") that stores the actual glyphs for a specific font data.
+// These nodes will only have a GlyphPage if they have glyphs for that range.
+//
+// Levels greater than one correspond to subsequent levels of the fallback list
+// for that font. These levels override their parent's page of glyphs by
+// filling in holes with the new font (thus making a more complete page).
+//
+// A NULL FontData pointer corresponds to the system fallback
+// font. It is tracked separately from the regular pages and overrides so that
+// the glyph pages do not get polluted with these last-resort glyphs. The
+// system fallback page is not populated at construction like the other pages,
+// but on demand for each glyph, because the system may need to use different
+// fallback fonts for each. This lazy population is done by the Font.
+class GlyphPageTreeNode {
+public:
+ GlyphPageTreeNode()
+ : m_parent(0)
+ , m_level(0)
+ , m_isSystemFallback(false)
+ , m_systemFallbackChild(0)
+ , m_customFontCount(0)
+#ifndef NDEBUG
+ , m_pageNumber(0)
+#endif
+ {
+ }
+
+ ~GlyphPageTreeNode();
+
+ static HashMap<int, GlyphPageTreeNode*>* roots;
+ static GlyphPageTreeNode* pageZeroRoot;
+
+ static GlyphPageTreeNode* getRootChild(const FontData* fontData, unsigned pageNumber)
+ {
+ return getRoot(pageNumber)->getChild(fontData, pageNumber);
+ }
+
+ static void pruneTreeCustomFontData(const FontData*);
+ static void pruneTreeFontData(const SimpleFontData*);
+
+ void pruneCustomFontData(const FontData*);
+ void pruneFontData(const SimpleFontData*, unsigned level = 0);
+
+ GlyphPageTreeNode* parent() const { return m_parent; }
+ GlyphPageTreeNode* getChild(const FontData*, unsigned pageNumber);
+
+ // Returns a page of glyphs (or NULL if there are no glyphs in this page's character range).
+ GlyphPage* page() const { return m_page.get(); }
+
+ // Returns the level of this node. See class-level comment.
+ unsigned level() const { return m_level; }
+
+ // The system fallback font has special rules (see above).
+ bool isSystemFallback() const { return m_isSystemFallback; }
+
+ static size_t treeGlyphPageCount();
+ size_t pageCount() const;
+
+private:
+ static GlyphPageTreeNode* getRoot(unsigned pageNumber);
+ void initializePage(const FontData*, unsigned pageNumber);
+
+ GlyphPageTreeNode* m_parent;
+ RefPtr<GlyphPage> m_page;
+ unsigned m_level;
+ bool m_isSystemFallback;
+ HashMap<const FontData*, GlyphPageTreeNode*> m_children;
+ GlyphPageTreeNode* m_systemFallbackChild;
+ unsigned m_customFontCount;
+
+#ifndef NDEBUG
+ unsigned m_pageNumber;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // GlyphPageTreeNode_h
diff --git a/WebCore/platform/graphics/GlyphWidthMap.cpp b/WebCore/platform/graphics/GlyphWidthMap.cpp
new file mode 100644
index 0000000..6e8d68d
--- /dev/null
+++ b/WebCore/platform/graphics/GlyphWidthMap.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "GlyphWidthMap.h"
+
+namespace WebCore
+{
+
+float GlyphWidthMap::widthForGlyph(Glyph g)
+{
+ unsigned pageNumber = (g / GlyphWidthPage::size);
+ GlyphWidthPage* page = locatePage(pageNumber);
+ if (page)
+ return page->widthForGlyph(g);
+ return cGlyphWidthUnknown;
+}
+
+void GlyphWidthMap::setWidthForGlyph(Glyph glyph, float width)
+{
+ unsigned pageNumber = (glyph / GlyphWidthPage::size);
+ GlyphWidthPage* page = locatePage(pageNumber);
+ if (page)
+ page->setWidthForGlyph(glyph, width);
+}
+
+inline GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePage(unsigned pageNumber)
+{
+ GlyphWidthPage* page;
+ if (pageNumber == 0) {
+ if (m_filledPrimaryPage)
+ return &m_primaryPage;
+ page = &m_primaryPage;
+ m_filledPrimaryPage = true;
+ } else {
+ if (m_pages) {
+ GlyphWidthPage* result = m_pages->get(pageNumber);
+ if (result)
+ return result;
+ }
+ page = new GlyphWidthPage;
+ if (!m_pages)
+ m_pages = new HashMap<int, GlyphWidthPage*>;
+ m_pages->set(pageNumber, page);
+ }
+
+ // Fill in the whole page with the unknown glyph width value.
+ for (unsigned i = 0; i < GlyphWidthPage::size; i++)
+ page->setWidthForIndex(i, cGlyphWidthUnknown);
+
+ return page;
+}
+
+}
diff --git a/WebCore/platform/graphics/GlyphWidthMap.h b/WebCore/platform/graphics/GlyphWidthMap.h
new file mode 100644
index 0000000..1633769
--- /dev/null
+++ b/WebCore/platform/graphics/GlyphWidthMap.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 GlyphWidthMap_h
+#define GlyphWidthMap_h
+
+#include <wtf/unicode/Unicode.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+typedef unsigned short Glyph;
+
+const float cGlyphWidthUnknown = -1;
+
+class GlyphWidthMap : Noncopyable {
+public:
+ GlyphWidthMap() : m_filledPrimaryPage(false), m_pages(0) {}
+ ~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); delete m_pages; } }
+
+ float widthForGlyph(Glyph);
+ void setWidthForGlyph(Glyph, float);
+
+private:
+ struct GlyphWidthPage {
+ static const size_t size = 256; // Usually covers Latin-1 in a single page.
+ float m_widths[size];
+
+ float widthForGlyph(Glyph g) const { return m_widths[g % size]; }
+ void setWidthForGlyph(Glyph g, float w)
+ {
+ setWidthForIndex(g % size, w);
+ }
+ void setWidthForIndex(unsigned index, float w)
+ {
+ m_widths[index] = w;
+ }
+ };
+
+ GlyphWidthPage* locatePage(unsigned page);
+
+ bool m_filledPrimaryPage;
+ GlyphWidthPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255.
+ HashMap<int, GlyphWidthPage*>* m_pages;
+};
+
+}
+#endif
diff --git a/WebCore/platform/graphics/Gradient.cpp b/WebCore/platform/graphics/Gradient.cpp
new file mode 100644
index 0000000..2e6a5d2
--- /dev/null
+++ b/WebCore/platform/graphics/Gradient.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "Gradient.h"
+
+#include "Color.h"
+
+namespace WebCore {
+
+Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
+ : m_radial(false)
+ , m_p0(p0)
+ , m_p1(p1)
+ , m_r0(0)
+ , m_r1(0)
+ , m_stopsSorted(false)
+ , m_lastStop(0)
+{
+ platformInit();
+}
+
+Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1)
+ : m_radial(true)
+ , m_p0(p0)
+ , m_p1(p1)
+ , m_r0(r0)
+ , m_r1(r1)
+ , m_stopsSorted(false)
+ , m_lastStop(0)
+{
+ platformInit();
+}
+
+Gradient::~Gradient()
+{
+ platformDestroy();
+}
+
+void Gradient::addColorStop(float value, const Color& color)
+{
+ float r;
+ float g;
+ float b;
+ float a;
+ color.getRGBA(r, g, b, a);
+ m_stops.append(ColorStop(value, r, g, b, a));
+
+ m_stopsSorted = false;
+
+ platformDestroy();
+}
+
+static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
+{
+ return a.stop < b.stop;
+}
+
+void Gradient::getColor(float value, float* r, float* g, float* b, float* a) const
+{
+ ASSERT(value >= 0);
+ ASSERT(value <= 1);
+
+ if (m_stops.isEmpty()) {
+ *r = 0;
+ *g = 0;
+ *b = 0;
+ *a = 0;
+ return;
+ }
+ if (!m_stopsSorted) {
+ if (m_stops.size())
+ std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
+ m_stopsSorted = true;
+ }
+ if (value <= 0 || value <= m_stops.first().stop) {
+ *r = m_stops.first().red;
+ *g = m_stops.first().green;
+ *b = m_stops.first().blue;
+ *a = m_stops.first().alpha;
+ return;
+ }
+ if (value >= 1 || value >= m_stops.last().stop) {
+ *r = m_stops.last().red;
+ *g = m_stops.last().green;
+ *b = m_stops.last().blue;
+ *a = m_stops.last().alpha;
+ return;
+ }
+
+ // Find stop before and stop after and interpolate.
+ int stop = findStop(value);
+ const ColorStop& lastStop = m_stops[stop];
+ const ColorStop& nextStop = m_stops[stop + 1];
+ float stopFraction = (value - lastStop.stop) / (nextStop.stop - lastStop.stop);
+ *r = lastStop.red + (nextStop.red - lastStop.red) * stopFraction;
+ *g = lastStop.green + (nextStop.green - lastStop.green) * stopFraction;
+ *b = lastStop.blue + (nextStop.blue - lastStop.blue) * stopFraction;
+ *a = lastStop.alpha + (nextStop.alpha - lastStop.alpha) * stopFraction;
+}
+
+int Gradient::findStop(float value) const
+{
+ ASSERT(value >= 0);
+ ASSERT(value <= 1);
+ ASSERT(m_stopsSorted);
+
+ int numStops = m_stops.size();
+ ASSERT(numStops >= 2);
+ ASSERT(m_lastStop < numStops - 1);
+
+ int i = m_lastStop;
+ if (value < m_stops[i].stop)
+ i = 1;
+ else
+ i = m_lastStop + 1;
+
+ for (; i < numStops - 1; ++i)
+ if (value < m_stops[i].stop)
+ break;
+
+ m_lastStop = i - 1;
+ return m_lastStop;
+}
+
+} //namespace
diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h
new file mode 100644
index 0000000..00ef2b6
--- /dev/null
+++ b/WebCore/platform/graphics/Gradient.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Gradient_h
+#define Gradient_h
+
+#include "FloatPoint.h"
+#include "Generator.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(CG)
+typedef struct CGShading* CGShadingRef;
+typedef CGShadingRef PlatformGradient;
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QGradient;
+QT_END_NAMESPACE
+typedef QGradient* PlatformGradient;
+#elif PLATFORM(CAIRO)
+typedef struct _cairo_pattern cairo_pattern_t;
+typedef cairo_pattern_t* PlatformGradient;
+#elif PLATFORM(SGL)
+#include "SkShader.h"
+typedef class PlatformGradientRec* PlatformGradient;
+#elif PLATFORM(SKIA)
+class SkShader;
+typedef class SkShader* PlatformGradient;
+typedef class SkShader* PlatformPattern;
+#else
+typedef void* PlatformGradient;
+#endif
+
+namespace WebCore {
+
+ class Color;
+
+ class Gradient : public Generator {
+ public:
+ static PassRefPtr<Gradient> create(const FloatPoint& p0, const FloatPoint& p1)
+ {
+ return adoptRef(new Gradient(p0, p1));
+ }
+ static PassRefPtr<Gradient> create(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1)
+ {
+ return adoptRef(new Gradient(p0, r0, p1, r1));
+ }
+ virtual ~Gradient();
+
+ void addColorStop(float, const Color&);
+
+ void getColor(float value, float* r, float* g, float* b, float* a) const;
+
+#if PLATFORM(SGL)
+ SkShader* getShader(SkShader::TileMode);
+#else
+ PlatformGradient platformGradient();
+#endif
+
+ struct ColorStop {
+ float stop;
+ float red;
+ float green;
+ float blue;
+ float alpha;
+
+ ColorStop() : stop(0), red(0), green(0), blue(0), alpha(0) { }
+ ColorStop(float s, float r, float g, float b, float a) : stop(s), red(r), green(g), blue(b), alpha(a) { }
+ };
+
+ void setStopsSorted(bool s) { m_stopsSorted = s; }
+
+ virtual void fill(GraphicsContext*, const FloatRect&);
+
+ private:
+ Gradient(const FloatPoint& p0, const FloatPoint& p1);
+ Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1);
+
+ void platformInit() { m_gradient = 0; }
+ void platformDestroy();
+
+ int findStop(float value) const;
+
+ bool m_radial;
+ FloatPoint m_p0;
+ FloatPoint m_p1;
+ float m_r0;
+ float m_r1;
+ mutable Vector<ColorStop> m_stops;
+ mutable bool m_stopsSorted;
+ mutable int m_lastStop;
+
+ PlatformGradient m_gradient;
+ };
+
+} //namespace
+
+#endif
diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp
new file mode 100644
index 0000000..9cd2969
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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 "GraphicsContext.h"
+
+#include "BidiResolver.h"
+#include "Generator.h"
+#include "GraphicsContextPrivate.h"
+#include "Font.h"
+#include "NotImplemented.h"
+
+using namespace std;
+
+namespace WebCore {
+
+class TextRunIterator {
+public:
+ TextRunIterator()
+ : m_textRun(0)
+ , m_offset(0)
+ {
+ }
+
+ TextRunIterator(const TextRun* textRun, unsigned offset)
+ : m_textRun(textRun)
+ , m_offset(offset)
+ {
+ }
+
+ TextRunIterator(const TextRunIterator& other)
+ : m_textRun(other.m_textRun)
+ , m_offset(other.m_offset)
+ {
+ }
+
+ unsigned offset() const { return m_offset; }
+ void increment() { m_offset++; }
+ bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); }
+ UChar current() const { return (*m_textRun)[m_offset]; }
+ WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); }
+
+ bool operator==(const TextRunIterator& other)
+ {
+ return m_offset == other.m_offset && m_textRun == other.m_textRun;
+ }
+
+ bool operator!=(const TextRunIterator& other) { return !operator==(other); }
+
+private:
+ const TextRun* m_textRun;
+ int m_offset;
+};
+
+GraphicsContextPrivate* GraphicsContext::createGraphicsContextPrivate()
+{
+ return new GraphicsContextPrivate;
+}
+
+void GraphicsContext::destroyGraphicsContextPrivate(GraphicsContextPrivate* deleteMe)
+{
+ delete deleteMe;
+}
+
+void GraphicsContext::save()
+{
+ if (paintingDisabled())
+ return;
+
+ m_common->stack.append(m_common->state);
+
+ savePlatformState();
+}
+
+void GraphicsContext::restore()
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_common->stack.isEmpty()) {
+ LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty");
+ return;
+ }
+ m_common->state = m_common->stack.last();
+ m_common->stack.removeLast();
+
+ 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;
+ setPlatformStrokeThickness(thickness);
+}
+
+void GraphicsContext::setStrokeStyle(const StrokeStyle& style)
+{
+ m_common->state.strokeStyle = style;
+ setPlatformStrokeStyle(style);
+}
+
+void GraphicsContext::setStrokeColor(const Color& color)
+{
+ m_common->state.strokeColorSpace = SolidColorSpace;
+ m_common->state.strokeColor = color;
+ setPlatformStrokeColor(color);
+}
+
+void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
+{
+ m_common->state.shadowSize = size;
+ m_common->state.shadowBlur = blur;
+ m_common->state.shadowColor = color;
+ setPlatformShadow(size, blur, color);
+}
+
+void GraphicsContext::clearShadow()
+{
+ m_common->state.shadowSize = IntSize();
+ m_common->state.shadowBlur = 0;
+ m_common->state.shadowColor = Color();
+ clearPlatformShadow();
+}
+
+bool GraphicsContext::getShadow(IntSize& size, int& blur, Color& color) const
+{
+ size = m_common->state.shadowSize;
+ blur = m_common->state.shadowBlur;
+ color = m_common->state.shadowColor;
+
+ return color.isValid() && color.alpha() && (blur || size.width() || size.height());
+}
+
+float GraphicsContext::strokeThickness() const
+{
+ return m_common->state.strokeThickness;
+}
+
+StrokeStyle GraphicsContext::strokeStyle() const
+{
+ return m_common->state.strokeStyle;
+}
+
+Color GraphicsContext::strokeColor() const
+{
+ return m_common->state.strokeColor;
+}
+
+WindRule GraphicsContext::fillRule() const
+{
+ return m_common->state.fillRule;
+}
+
+void GraphicsContext::setFillRule(WindRule fillRule)
+{
+ m_common->state.fillRule = fillRule;
+}
+
+GradientSpreadMethod GraphicsContext::spreadMethod() const
+{
+ return m_common->state.spreadMethod;
+}
+
+void GraphicsContext::setSpreadMethod(GradientSpreadMethod spreadMethod)
+{
+ m_common->state.spreadMethod = spreadMethod;
+}
+
+void GraphicsContext::setFillColor(const Color& color)
+{
+ m_common->state.fillColorSpace = SolidColorSpace;
+ m_common->state.fillColor = color;
+ setPlatformFillColor(color);
+}
+
+Color GraphicsContext::fillColor() const
+{
+ return m_common->state.fillColor;
+}
+
+void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern)
+{
+ ASSERT(pattern);
+ if (!pattern) {
+ setStrokeColor(Color::black);
+ return;
+ }
+ m_common->state.strokeColorSpace = PatternColorSpace;
+ m_common->state.strokePattern = pattern;
+}
+
+void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern)
+{
+ ASSERT(pattern);
+ if (!pattern) {
+ setFillColor(Color::black);
+ return;
+ }
+ m_common->state.fillColorSpace = PatternColorSpace;
+ m_common->state.fillPattern = pattern;
+}
+
+void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient)
+{
+ ASSERT(gradient);
+ if (!gradient) {
+ setStrokeColor(Color::black);
+ return;
+ }
+ m_common->state.strokeColorSpace = GradientColorSpace;
+ m_common->state.strokeGradient = gradient;
+}
+
+void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient)
+{
+ ASSERT(gradient);
+ if (!gradient) {
+ setFillColor(Color::black);
+ return;
+ }
+ m_common->state.fillColorSpace = GradientColorSpace;
+ m_common->state.fillGradient = gradient;
+}
+
+bool GraphicsContext::updatingControlTints() const
+{
+ return m_common->m_updatingControlTints;
+}
+
+void GraphicsContext::setUpdatingControlTints(bool b)
+{
+ setPaintingDisabled(b);
+ m_common->m_updatingControlTints = b;
+}
+
+void GraphicsContext::setPaintingDisabled(bool f)
+{
+ m_common->state.paintingDisabled = f;
+}
+
+bool GraphicsContext::paintingDisabled() const
+{
+ return m_common->state.paintingDisabled;
+}
+
+void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op)
+{
+ drawImage(image, p, IntRect(0, 0, -1, -1), op);
+}
+
+void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, bool useLowQualityScale)
+{
+ drawImage(image, r, IntRect(0, 0, -1, -1), op, useLowQualityScale);
+}
+
+void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op)
+{
+ drawImage(image, IntRect(dest, srcRect.size()), srcRect, op);
+}
+
+void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale)
+{
+ drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale);
+}
+
+void GraphicsContext::drawText(const TextRun& run, const IntPoint& point, int from, int to)
+{
+ if (paintingDisabled())
+ return;
+
+ font().drawText(this, run, point, from, to);
+}
+
+void GraphicsContext::drawBidiText(const TextRun& run, const FloatPoint& point)
+{
+ if (paintingDisabled())
+ return;
+
+ BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
+ WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
+
+ bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride())));
+
+ bidiResolver.setPosition(TextRunIterator(&run, 0));
+ bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
+
+ if (!bidiResolver.runCount())
+ return;
+
+ FloatPoint currPoint = point;
+ BidiCharacterRun* bidiRun = bidiResolver.firstRun();
+ while (bidiRun) {
+
+ TextRun subrun = run;
+ subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start());
+ subrun.setRTL(bidiRun->level() % 2);
+ subrun.setDirectionalOverride(bidiRun->dirOverride(false));
+
+ 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);
+ }
+
+ bidiResolver.deleteRuns();
+}
+
+void GraphicsContext::drawHighlightForText(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);
+}
+
+void GraphicsContext::initFocusRing(int width, int offset)
+{
+ if (paintingDisabled())
+ return;
+ clearFocusRing();
+
+ m_common->m_focusRingWidth = width;
+ m_common->m_focusRingOffset = offset;
+}
+
+void GraphicsContext::clearFocusRing()
+{
+ m_common->m_focusRingRects.clear();
+}
+
+IntRect GraphicsContext::focusRingBoundingRect()
+{
+ IntRect result = IntRect(0, 0, 0, 0);
+
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+ for (unsigned i = 0; i < rectCount; i++)
+ result.unite(rects[i]);
+
+ return result;
+}
+
+void GraphicsContext::addFocusRingRect(const IntRect& rect)
+{
+ if (paintingDisabled() || rect.isEmpty())
+ return;
+ m_common->m_focusRingRects.append(rect);
+}
+
+int GraphicsContext::focusRingWidth() const
+{
+ return m_common->m_focusRingWidth;
+}
+
+int GraphicsContext::focusRingOffset() const
+{
+ return m_common->m_focusRingOffset;
+}
+
+const Vector<IntRect>& GraphicsContext::focusRingRects() const
+{
+ return m_common->m_focusRingRects;
+}
+
+void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
+{
+ if (paintingDisabled() || !image)
+ return;
+
+ float tsw = src.width();
+ float tsh = src.height();
+ float tw = dest.width();
+ float th = dest.height();
+
+ if (tsw == -1)
+ tsw = image->width();
+ if (tsh == -1)
+ tsh = image->height();
+
+ if (tw == -1)
+ tw = image->width();
+ if (th == -1)
+ th = image->height();
+
+ if (useLowQualityScale) {
+ save();
+ setImageInterpolationQuality(InterpolationNone);
+ }
+ image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op);
+ if (useLowQualityScale)
+ restore();
+}
+
+void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op)
+{
+ if (paintingDisabled() || !image)
+ return;
+
+ image->drawTiled(this, rect, srcPoint, tileSize, op);
+}
+
+void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op)
+{
+ if (paintingDisabled() || !image)
+ return;
+
+ if (hRule == Image::StretchTile && vRule == Image::StretchTile)
+ // Just do a scale.
+ return drawImage(image, dest, srcRect, op);
+
+ image->drawTiled(this, dest, srcRect, hRule, vRule, op);
+}
+
+void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
+ const IntSize& bottomLeft, const IntSize& bottomRight)
+{
+ if (paintingDisabled())
+ return;
+
+ clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
+}
+
+void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
+ const IntSize& bottomLeft, const IntSize& bottomRight)
+{
+ if (paintingDisabled())
+ return;
+
+ clipOut(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
+}
+
+int GraphicsContext::textDrawingMode()
+{
+ return m_common->state.textDrawingMode;
+}
+
+void GraphicsContext::setTextDrawingMode(int mode)
+{
+ m_common->state.textDrawingMode = mode;
+ if (paintingDisabled())
+ return;
+ setPlatformTextDrawingMode(mode);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, Generator& generator)
+{
+ if (paintingDisabled())
+ return;
+ generator.fill(this, rect);
+}
+
+#if !PLATFORM(CG) && !PLATFORM(SKIA)
+// Implement this if you want to go ahead and push the drawing mode into your native context
+// immediately.
+void GraphicsContext::setPlatformTextDrawingMode(int mode)
+{
+}
+#endif
+
+#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA)
+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
new file mode 100644
index 0000000..95bdc90
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsContext_h
+#define GraphicsContext_h
+
+#include "DashArray.h"
+#include "FloatRect.h"
+#include "Image.h"
+#include "IntRect.h"
+#include "Path.h"
+#include "TextDirection.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/Platform.h>
+
+#if PLATFORM(CG)
+typedef struct CGContext PlatformGraphicsContext;
+#elif PLATFORM(CAIRO)
+typedef struct _cairo PlatformGraphicsContext;
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QPainter;
+QT_END_NAMESPACE
+typedef QPainter PlatformGraphicsContext;
+#elif PLATFORM(SGL)
+namespace WebCore {
+class PlatformGraphicsContext;
+}
+class SkPaint;
+struct SkPoint;
+#elif PLATFORM(WX)
+class wxGCDC;
+class wxWindowDC;
+
+// wxGraphicsContext allows us to support Path, etc.
+// but on some platforms, e.g. Linux, it requires fairly
+// new software.
+#if USE(WXGC)
+// On OS X, wxGCDC is just a typedef for wxDC, so use wxDC explicitly to make
+// the linker happy.
+#ifdef __APPLE__
+ class wxDC;
+ typedef wxDC PlatformGraphicsContext;
+#else
+ typedef wxGCDC PlatformGraphicsContext;
+#endif
+#else
+ typedef wxWindowDC PlatformGraphicsContext;
+#endif
+#elif PLATFORM(SKIA)
+typedef class PlatformContextSkia PlatformGraphicsContext;
+#else
+typedef void PlatformGraphicsContext;
+#endif
+
+#if PLATFORM(GTK)
+typedef struct _GdkDrawable GdkDrawable;
+typedef struct _GdkEventExpose GdkEventExpose;
+#endif
+
+#if PLATFORM(WIN)
+typedef struct HDC__* HDC;
+#if !PLATFORM(CG)
+// UInt8 is defined in CoreFoundation/CFBase.h
+typedef unsigned char UInt8;
+#endif
+#endif
+
+#if PLATFORM(QT) && defined(Q_WS_WIN)
+#include <windows.h>
+#endif
+
+namespace WebCore {
+
+ const int cMisspellingLineThickness = 3;
+ const int cMisspellingLinePatternWidth = 4;
+ const int cMisspellingLinePatternGapWidth = 1;
+
+ class AffineTransform;
+ class Font;
+ class Generator;
+ class Gradient;
+ class GraphicsContextPrivate;
+ class GraphicsContextPlatformPrivate;
+ class ImageBuffer;
+ class KURL;
+ class Path;
+ class Pattern;
+ class TextRun;
+
+ // These bits can be ORed together for a total of 8 possible text drawing modes.
+ const int cTextInvisible = 0;
+ const int cTextFill = 1;
+ const int cTextStroke = 2;
+ const int cTextClip = 4;
+
+ enum StrokeStyle {
+ NoStroke,
+ SolidStroke,
+ DottedStroke,
+ DashedStroke
+ };
+
+ enum InterpolationQuality {
+ InterpolationDefault,
+ InterpolationNone,
+ InterpolationLow,
+ InterpolationMedium,
+ InterpolationHigh
+ };
+
+ // FIXME: Currently these constants have to match the values used in the SVG
+ // DOM API. That's a mistake. We need to make cut that dependency.
+ enum GradientSpreadMethod {
+ SpreadMethodPad = 1,
+ SpreadMethodReflect = 2,
+ SpreadMethodRepeat = 3
+ };
+
+ class GraphicsContext : Noncopyable {
+ public:
+ GraphicsContext(PlatformGraphicsContext*);
+ ~GraphicsContext();
+
+ PlatformGraphicsContext* platformContext() const;
+
+ const Font& font() const;
+ void setFont(const Font&);
+
+ float strokeThickness() const;
+ void setStrokeThickness(float);
+ StrokeStyle strokeStyle() const;
+ void setStrokeStyle(const StrokeStyle& style);
+ Color strokeColor() const;
+ void setStrokeColor(const Color&);
+ void setStrokePattern(PassRefPtr<Pattern>);
+ void setStrokeGradient(PassRefPtr<Gradient>);
+
+ WindRule fillRule() const;
+ void setFillRule(WindRule);
+ GradientSpreadMethod spreadMethod() const;
+ void setSpreadMethod(GradientSpreadMethod);
+ Color fillColor() const;
+ void setFillColor(const Color&);
+ void setFillPattern(PassRefPtr<Pattern>);
+ void setFillGradient(PassRefPtr<Gradient>);
+
+#if PLATFORM(SGL)
+ /* these should be pused to apple. needed for CanvasStyle.cpp */
+ void setCMYKAFillColor(float c, float m, float y, float k, float a);
+ void setCMYKAStrokeColor(float c, float m, float y, float k, float a);
+
+ // initialize a paint for filling
+ void setupFillPaint(SkPaint*);
+ // initialize a paint for stroking
+ void setupStrokePaint(SkPaint*);
+ // initialize a paint for a shadow, or if false is returned, the
+ // parameters are left untouched
+ bool setupShadowPaint(SkPaint* paint, SkPoint* offset);
+ // returns true if there is a valid (non-transparent) fill color
+ bool willFill() const;
+ // returns true if there is a valid (non-transparent) stroke color
+ bool willStroke() const;
+
+ /** platform-specific factory method to return a bitmap graphicscontext,
+ called by <canvas> when we need to draw offscreen. Caller is responsible for
+ deleting the context. Use drawOffscreenContext() to draw the context's image
+ onto another graphics context.
+ */
+ static GraphicsContext* createOffscreenContext(int width, int height);
+#endif
+
+ void save();
+ void restore();
+
+ // These draw methods will do both stroking and filling.
+ void drawRect(const IntRect&);
+ void drawLine(const IntPoint&, const IntPoint&);
+ void drawEllipse(const IntRect&);
+ void drawConvexPolygon(size_t numPoints, const FloatPoint*, bool shouldAntialias = false);
+
+ void drawPath();
+ void fillPath();
+ void strokePath();
+
+ // Arc drawing (used by border-radius in CSS) just supports stroking at the moment.
+ void strokeArc(const IntRect&, int startAngle, int angleSpan);
+
+ void fillRect(const FloatRect&);
+ void fillRect(const FloatRect&, const Color&);
+ void fillRect(const FloatRect&, Generator&);
+ void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&);
+
+ void clearRect(const FloatRect&);
+
+ void strokeRect(const FloatRect&);
+ void strokeRect(const FloatRect&, float lineWidth);
+
+ void drawImage(Image*, const IntPoint&, CompositeOperator = CompositeSourceOver);
+ void drawImage(Image*, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawImage(Image*, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver);
+ void drawImage(Image*, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1),
+ CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
+ void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize,
+ CompositeOperator = CompositeSourceOver);
+ void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect,
+ Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile,
+ CompositeOperator = CompositeSourceOver);
+
+ void setImageInterpolationQuality(InterpolationQuality);
+ InterpolationQuality imageInterpolationQuality() const;
+
+ void clip(const FloatRect&);
+ void addRoundedRectClip(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight);
+ void addInnerRoundedRectClip(const IntRect&, int thickness);
+ 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 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);
+
+ FloatRect roundToDevicePixels(const FloatRect&);
+
+ void drawLineForText(const IntPoint&, int width, bool printing);
+ void drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar);
+
+ bool paintingDisabled() const;
+ void setPaintingDisabled(bool);
+
+ bool updatingControlTints() const;
+ void setUpdatingControlTints(bool);
+
+ void beginTransparencyLayer(float opacity);
+ void endTransparencyLayer();
+
+ void setShadow(const IntSize&, int blur, const Color&);
+ bool getShadow(IntSize&, int&, Color&) const;
+ void clearShadow();
+
+ void initFocusRing(int width, int offset);
+ void addFocusRingRect(const IntRect&);
+ void drawFocusRing(const Color&);
+ void clearFocusRing();
+ IntRect focusRingBoundingRect();
+
+ void setLineCap(LineCap);
+ void setLineDash(const DashArray&, float dashOffset);
+ void setLineJoin(LineJoin);
+ void setMiterLimit(float);
+
+ void setAlpha(float);
+#if PLATFORM(CAIRO)
+ float getAlpha();
+#endif
+
+ void setCompositeOperation(CompositeOperator);
+
+ void beginPath();
+ void addPath(const Path&);
+
+ void clip(const Path&);
+ void clipOut(const Path&);
+
+ void scale(const FloatSize&);
+ void rotate(float angleInRadians);
+ void translate(float x, float y);
+ IntPoint origin();
+
+ void setURLForRect(const KURL&, const IntRect&);
+
+ void concatCTM(const AffineTransform&);
+ AffineTransform getCTM() const;
+
+ void setUseAntialiasing(bool = true);
+
+#if PLATFORM(WIN)
+ GraphicsContext(HDC, bool hasAlpha = false); // FIXME: To be removed.
+ bool inTransparencyLayer() const;
+ HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
+ void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in HDC should be the one handed back by getWindowsContext.
+
+ class WindowsBitmap : public Noncopyable {
+ public:
+ WindowsBitmap(HDC, IntSize);
+ ~WindowsBitmap();
+
+ HDC hdc() const { return m_hdc; }
+ UInt8* buffer() const { return m_bitmapBuffer; }
+ unsigned bufferLength() const { return m_bitmapBufferLength; }
+ IntSize size() const { return m_size; }
+ unsigned bytesPerRow() const { return m_bytesPerRow; }
+
+ private:
+ HDC m_hdc;
+ HBITMAP m_bitmap;
+ UInt8* m_bitmapBuffer;
+ unsigned m_bitmapBufferLength;
+ IntSize m_size;
+ unsigned m_bytesPerRow;
+ };
+
+ WindowsBitmap* createWindowsBitmap(IntSize);
+ // The bitmap should be non-premultiplied.
+ void drawWindowsBitmap(WindowsBitmap*, const IntPoint&);
+#endif
+
+#if PLATFORM(QT) && defined(Q_WS_WIN)
+ HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true);
+ void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true);
+#endif
+
+#if PLATFORM(QT)
+ bool inTransparencyLayer() const;
+ PlatformPath* currentPath();
+#endif
+
+#if PLATFORM(GTK)
+ void setGdkExposeEvent(GdkEventExpose*);
+ GdkDrawable* gdkDrawable() const;
+ GdkEventExpose* gdkExposeEvent() const;
+#endif
+
+ private:
+ void savePlatformState();
+ void restorePlatformState();
+
+ void setPlatformTextDrawingMode(int);
+ void setPlatformFont(const Font& font);
+
+ void setPlatformStrokeColor(const Color&);
+ void setPlatformStrokeStyle(const StrokeStyle&);
+ void setPlatformStrokeThickness(float);
+
+ void setPlatformFillColor(const Color&);
+
+ void setPlatformShadow(const IntSize&, int blur, const Color&);
+ void clearPlatformShadow();
+
+ int focusRingWidth() const;
+ int focusRingOffset() const;
+ const Vector<IntRect>& focusRingRects() const;
+
+ static GraphicsContextPrivate* createGraphicsContextPrivate();
+ static void destroyGraphicsContextPrivate(GraphicsContextPrivate*);
+
+ GraphicsContextPrivate* m_common;
+ GraphicsContextPlatformPrivate* m_data; // Deprecated; m_commmon can just be downcasted. To be removed.
+ };
+
+} // namespace WebCore
+
+#endif // GraphicsContext_h
diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h
new file mode 100644
index 0000000..de94527
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsContextPrivate.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsContextPrivate_h
+#define GraphicsContextPrivate_h
+
+#include "Font.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "Pattern.h"
+
+namespace WebCore {
+
+// FIXME: This is a place-holder until we decide to add
+// real color space support to WebCore. At that time, ColorSpace will be a
+// class and instances will be held off of Colors. There will be
+// special singleton Gradient and Pattern color spaces to mark when
+// a fill or stroke is using a gradient or pattern instead of a solid color.
+// https://bugs.webkit.org/show_bug.cgi?id=20558
+ enum ColorSpace {
+ SolidColorSpace,
+ PatternColorSpace,
+ GradientColorSpace
+ };
+
+ struct GraphicsContextState {
+ GraphicsContextState()
+ : textDrawingMode(cTextFill)
+ , strokeStyle(SolidStroke)
+ , strokeThickness(0)
+#if PLATFORM(CAIRO)
+ , globalAlpha(1.0f)
+#endif
+ , strokeColorSpace(SolidColorSpace)
+ , strokeColor(Color::black)
+ , fillRule(RULE_NONZERO)
+ , fillColorSpace(SolidColorSpace)
+ , fillColor(Color::black)
+ , paintingDisabled(false)
+ , shadowBlur(0)
+ {
+ }
+
+ Font font;
+ int textDrawingMode;
+
+ StrokeStyle strokeStyle;
+ float strokeThickness;
+#if PLATFORM(CAIRO)
+ float globalAlpha;
+#endif
+ ColorSpace strokeColorSpace;
+ Color strokeColor;
+ RefPtr<Gradient> strokeGradient;
+ RefPtr<Pattern> strokePattern;
+
+ WindRule fillRule;
+ GradientSpreadMethod spreadMethod;
+ ColorSpace fillColorSpace;
+ Color fillColor;
+ RefPtr<Gradient> fillGradient;
+ RefPtr<Pattern> fillPattern;
+
+ bool paintingDisabled;
+
+ IntSize shadowSize;
+ unsigned shadowBlur;
+ Color shadowColor;
+ };
+
+ class GraphicsContextPrivate {
+ public:
+ GraphicsContextPrivate()
+ : m_focusRingWidth(0)
+ , m_focusRingOffset(0)
+ , m_updatingControlTints(false)
+ {
+ }
+
+ GraphicsContextState state;
+ Vector<GraphicsContextState> stack;
+ Vector<IntRect> m_focusRingRects;
+ int m_focusRingWidth;
+ int m_focusRingOffset;
+ bool m_updatingControlTints;
+ };
+
+} // namespace WebCore
+
+#endif // GraphicsContextPrivate_h
diff --git a/WebCore/platform/graphics/GraphicsTypes.cpp b/WebCore/platform/graphics/GraphicsTypes.cpp
new file mode 100644
index 0000000..761bf40
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsTypes.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "GraphicsTypes.h"
+
+#include "PlatformString.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+static const char* const compositeOperatorNames[] = {
+ "clear",
+ "copy",
+ "source-over",
+ "source-in",
+ "source-out",
+ "source-atop",
+ "destination-over",
+ "destination-in",
+ "destination-out",
+ "destination-atop",
+ "xor",
+ "darker",
+ "highlight",
+ "lighter"
+};
+const int numCompositeOperatorNames = sizeof(compositeOperatorNames) / sizeof(compositeOperatorNames[0]);
+
+bool parseCompositeOperator(const String& s, CompositeOperator& op)
+{
+ for (int i = 0; i < numCompositeOperatorNames; i++)
+ if (s == compositeOperatorNames[i]) {
+ op = static_cast<CompositeOperator>(i);
+ return true;
+ }
+ return false;
+}
+
+String compositeOperatorName(CompositeOperator op)
+{
+ ASSERT(op >= 0);
+ ASSERT(op < numCompositeOperatorNames);
+ return compositeOperatorNames[op];
+}
+
+bool parseLineCap(const String& s, LineCap& cap)
+{
+ if (s == "butt") {
+ cap = ButtCap;
+ return true;
+ }
+ if (s == "round") {
+ cap = RoundCap;
+ return true;
+ }
+ if (s == "square") {
+ cap = SquareCap;
+ return true;
+ }
+ return false;
+}
+
+String lineCapName(LineCap cap)
+{
+ ASSERT(cap >= 0);
+ ASSERT(cap < 3);
+ const char* const names[3] = { "butt", "round", "square" };
+ return names[cap];
+}
+
+bool parseLineJoin(const String& s, LineJoin& join)
+{
+ if (s == "miter") {
+ join = MiterJoin;
+ return true;
+ }
+ if (s == "round") {
+ join = RoundJoin;
+ return true;
+ }
+ if (s == "bevel") {
+ join = BevelJoin;
+ return true;
+ }
+ return false;
+}
+
+String lineJoinName(LineJoin join)
+{
+ ASSERT(join >= 0);
+ ASSERT(join < 3);
+ const char* const names[3] = { "miter", "round", "bevel" };
+ return names[join];
+}
+
+String textAlignName(TextAlign align)
+{
+ ASSERT(align >= 0);
+ ASSERT(align < 5);
+ const char* const names[5] = { "start", "end", "left", "center", "right" };
+ return names[align];
+}
+
+bool parseTextAlign(const String& s, TextAlign& align)
+{
+ if (s == "start") {
+ align = StartTextAlign;
+ return true;
+ }
+ if (s == "end") {
+ align = EndTextAlign;
+ return true;
+ }
+ if (s == "left") {
+ align = LeftTextAlign;
+ return true;
+ }
+ if (s == "center") {
+ align = CenterTextAlign;
+ return true;
+ }
+ if (s == "right") {
+ align = RightTextAlign;
+ return true;
+ }
+ return false;
+}
+
+String textBaselineName(TextBaseline baseline)
+{
+ ASSERT(baseline >= 0);
+ ASSERT(baseline < 6);
+ const char* const names[6] = { "alphabetic", "top", "middle", "bottom", "ideographic", "hanging" };
+ return names[baseline];
+}
+
+bool parseTextBaseline(const String& s, TextBaseline& baseline)
+{
+ if (s == "alphabetic") {
+ baseline = AlphabeticTextBaseline;
+ return true;
+ }
+ if (s == "top") {
+ baseline = TopTextBaseline;
+ return true;
+ }
+ if (s == "middle") {
+ baseline = MiddleTextBaseline;
+ return true;
+ }
+ if (s == "bottom") {
+ baseline = BottomTextBaseline;
+ return true;
+ }
+ if (s == "ideographic") {
+ baseline = IdeographicTextBaseline;
+ return true;
+ }
+ if (s == "hanging") {
+ baseline = HangingTextBaseline;
+ return true;
+ }
+ return false;
+}
+
+}
diff --git a/WebCore/platform/graphics/GraphicsTypes.h b/WebCore/platform/graphics/GraphicsTypes.h
new file mode 100644
index 0000000..cdf5e31
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsTypes.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GraphicsTypes_h
+#define GraphicsTypes_h
+
+namespace WebCore {
+
+ class String;
+
+ // Note: These constants exactly match the NSCompositeOperator constants of
+ // AppKit on Mac OS X Tiger. If these ever change, we'll need to change the
+ // Mac OS X Tiger platform code to map one to the other.
+ enum CompositeOperator {
+ CompositeClear,
+ CompositeCopy,
+ CompositeSourceOver,
+ CompositeSourceIn,
+ CompositeSourceOut,
+ CompositeSourceAtop,
+ CompositeDestinationOver,
+ CompositeDestinationIn,
+ CompositeDestinationOut,
+ CompositeDestinationAtop,
+ CompositeXOR,
+ CompositePlusDarker,
+ CompositeHighlight,
+ CompositePlusLighter
+ };
+
+ enum LineCap { ButtCap, RoundCap, SquareCap };
+
+ enum LineJoin { MiterJoin, RoundJoin, BevelJoin };
+
+ enum HorizontalAlignment { AlignLeft, AlignRight, AlignHCenter };
+
+ enum TextBaseline { AlphabeticTextBaseline, TopTextBaseline, MiddleTextBaseline, BottomTextBaseline, IdeographicTextBaseline, HangingTextBaseline };
+
+ enum TextAlign { StartTextAlign, EndTextAlign, LeftTextAlign, CenterTextAlign, RightTextAlign };
+
+ String compositeOperatorName(CompositeOperator);
+ bool parseCompositeOperator(const String&, CompositeOperator&);
+
+ String lineCapName(LineCap);
+ bool parseLineCap(const String&, LineCap&);
+
+ String lineJoinName(LineJoin);
+ bool parseLineJoin(const String&, LineJoin&);
+
+ String textAlignName(TextAlign);
+ bool parseTextAlign(const String&, TextAlign&);
+
+ String textBaselineName(TextBaseline);
+ bool parseTextBaseline(const String&, TextBaseline&);
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h
new file mode 100644
index 0000000..444c67c
--- /dev/null
+++ b/WebCore/platform/graphics/Icon.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 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.
+ *
+ */
+
+#ifndef Icon_h
+#define Icon_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+#ifdef __OBJC__
+@class NSImage;
+#else
+class NSImage;
+#endif
+#elif PLATFORM(WIN)
+typedef struct HICON__* HICON;
+#elif PLATFORM(QT)
+#include <QIcon>
+#elif PLATFORM(GTK)
+typedef struct _GdkPixbuf GdkPixbuf;
+#elif PLATFORM(CHROMIUM)
+#include "PlatformIcon.h"
+#endif
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntRect;
+class String;
+
+class Icon : public RefCounted<Icon> {
+public:
+ static PassRefPtr<Icon> createIconForFile(const String& filename);
+ static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames);
+
+ ~Icon();
+
+ void paint(GraphicsContext*, const IntRect&);
+
+#if PLATFORM(WIN)
+ static PassRefPtr<Icon> create(HICON hIcon) { return adoptRef(new Icon(hIcon)); }
+#endif
+
+private:
+#if PLATFORM(MAC)
+ Icon(NSImage*);
+ RetainPtr<NSImage> m_nsImage;
+#elif PLATFORM(WIN)
+ Icon(HICON);
+ HICON m_hIcon;
+#elif PLATFORM(QT)
+ Icon();
+ QIcon m_icon;
+#elif PLATFORM(GTK)
+ Icon();
+ GdkPixbuf* m_icon;
+#elif PLATFORM(CHROMIUM)
+ Icon(const PlatformIcon&);
+ PlatformIcon m_icon;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp
new file mode 100644
index 0000000..ca6954e
--- /dev/null
+++ b/WebCore/platform/graphics/Image.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "Image.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "MIMETypeRegistry.h"
+
+#include <math.h>
+
+#if PLATFORM(CG)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace WebCore {
+
+Image::Image(ImageObserver* observer)
+ : m_imageObserver(observer)
+{
+}
+
+Image::~Image()
+{
+}
+
+Image* Image::nullImage()
+{
+ static RefPtr<Image> nullImage = BitmapImage::create();
+ return nullImage.get();
+}
+
+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;
+ if (!m_data.get())
+ return true;
+
+ int length = m_data->size();
+ if (!length)
+ return true;
+
+ 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)
+ return;
+
+ ctxt->save();
+ ctxt->setCompositeOperation(!color.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
+ ctxt->fillRect(dstRect, color);
+ ctxt->restore();
+}
+
+static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const FloatRect& srcRect, Image::TileRule hRule, Image::TileRule vRule)
+{
+ float scaleX = 1.0f, scaleY = 1.0f;
+
+ if (hRule == Image::StretchTile)
+ scaleX = dstRect.width() / srcRect.width();
+ if (vRule == Image::StretchTile)
+ scaleY = dstRect.height() / srcRect.height();
+
+ if (hRule == Image::RepeatTile)
+ scaleX = scaleY;
+ if (vRule == Image::RepeatTile)
+ scaleY = scaleX;
+
+ return FloatSize(scaleX, scaleY);
+}
+
+
+void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op)
+{
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, destRect, solidColor(), op);
+ return;
+ }
+
+ FloatSize intrinsicTileSize = size();
+ if (hasRelativeWidth())
+ intrinsicTileSize.setWidth(scaledTileSize.width());
+ if (hasRelativeHeight())
+ intrinsicTileSize.setHeight(scaledTileSize.height());
+
+ FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(),
+ scaledTileSize.height() / intrinsicTileSize.height());
+ AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height());
+
+ FloatRect oneTileRect;
+ oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width()));
+ oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.height()));
+ oneTileRect.setSize(scaledTileSize);
+
+ // Check and see if a single draw of the image can cover the entire area we are supposed to tile.
+ if (oneTileRect.contains(destRect)) {
+ FloatRect visibleSrcRect;
+ visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width());
+ visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height());
+ visibleSrcRect.setWidth(destRect.width() / scale.width());
+ visibleSrcRect.setHeight(destRect.height() / scale.height());
+ draw(ctxt, destRect, visibleSrcRect, op);
+ return;
+ }
+
+ FloatRect tileRect(FloatPoint(), intrinsicTileSize);
+ drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect);
+
+ startAnimation();
+}
+
+// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things.
+void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator op)
+{
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, dstRect, solidColor(), op);
+ return;
+ }
+
+ // FIXME: We do not support 'round' yet. For now just map it to 'repeat'.
+ if (hRule == RoundTile)
+ hRule = RepeatTile;
+ if (vRule == RoundTile)
+ vRule = RepeatTile;
+
+ FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule);
+ AffineTransform patternTransform = AffineTransform().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).
+ float hPhase = scale.width() * srcRect.x();
+ float vPhase = scale.height() * srcRect.y();
+ if (hRule == Image::RepeatTile)
+ hPhase -= fmodf(dstRect.width(), scale.width() * srcRect.width()) / 2.0f;
+ if (vRule == Image::RepeatTile)
+ vPhase -= fmodf(dstRect.height(), scale.height() * srcRect.height()) / 2.0f;
+ FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase);
+
+ drawPattern(ctxt, srcRect, patternTransform, patternPhase, op, dstRect);
+
+ startAnimation();
+}
+
+
+}
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
new file mode 100644
index 0000000..1419b2d
--- /dev/null
+++ b/WebCore/platform/graphics/Image.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Image_h
+#define Image_h
+
+#include "Color.h"
+#include "GraphicsTypes.h"
+#include "ImageSource.h"
+#include <wtf/RefPtr.h>
+#include <wtf/PassRefPtr.h>
+#include "SharedBuffer.h"
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class NSImage;
+#else
+class NSImage;
+#endif
+#endif
+
+#if PLATFORM(CG)
+struct CGContext;
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagSIZE SIZE;
+typedef SIZE* LPSIZE;
+typedef struct HBITMAP__ *HBITMAP;
+#endif
+
+#if PLATFORM(SKIA)
+class NativeImageSkia;
+#endif
+
+#if PLATFORM(QT)
+#include <QPixmap>
+#endif
+
+#if PLATFORM(SGL)
+class SkBitmapRef;
+#endif
+
+namespace WebCore {
+
+class AffineTransform;
+class FloatPoint;
+class FloatRect;
+class FloatSize;
+class GraphicsContext;
+class IntRect;
+class IntSize;
+class SharedBuffer;
+class String;
+
+// This class gets notified when an image creates or destroys decoded frames and when it advances animation frames.
+class ImageObserver;
+
+class Image : public RefCounted<Image> {
+ friend class GeneratedImage;
+ friend class GraphicsContext;
+public:
+ virtual ~Image();
+
+ static PassRefPtr<Image> create(ImageObserver* = 0);
+ static PassRefPtr<Image> loadPlatformResource(const char* name);
+ static bool supportsType(const String&);
+
+ virtual bool isBitmapImage() const { return false; }
+
+ // Derived classes should override this if they can assure that
+ // the image contains only resources from its own security origin.
+ virtual bool hasSingleSecurityOrigin() const { return false; }
+
+ static Image* nullImage();
+ bool isNull() const;
+
+ // These are only used for SVGImage right now
+ virtual void setContainerSize(const IntSize&) { }
+ virtual bool usesContainerSize() const { return false; }
+ virtual bool hasRelativeWidth() const { return false; }
+ virtual bool hasRelativeHeight() const { return false; }
+
+ virtual IntSize size() const = 0;
+ IntRect rect() const;
+ int width() const;
+ int height() const;
+
+ bool setData(PassRefPtr<SharedBuffer> data, bool allDataReceived);
+ virtual bool dataChanged(bool allDataReceived) { return false; }
+
+ virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) = 0;
+ virtual unsigned decodedSize() const = 0;
+
+ SharedBuffer* data() { return m_data.get(); }
+
+ // 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
+ // automatically pause once all observers no longer want to render the image anywhere.
+ virtual void stopAnimation() {}
+ virtual void resetAnimation() {}
+
+ // Typically the CachedImage that owns us.
+ ImageObserver* imageObserver() const { return m_imageObserver; }
+
+ enum TileRule { StretchTile, RoundTile, RepeatTile };
+
+ virtual NativeImagePtr nativeImageForCurrentFrame() { return 0; }
+
+#if PLATFORM(MAC)
+ // Accessors for native image formats.
+ virtual NSImage* getNSImage() { return 0; }
+ virtual CFDataRef getTIFFRepresentation() { return 0; }
+#endif
+
+#if PLATFORM(CG)
+ virtual CGImageRef getCGImageRef() { return 0; }
+#endif
+
+#if PLATFORM(WIN)
+ virtual bool getHBITMAP(HBITMAP) { return false; }
+ virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE) { return false; }
+#endif
+
+#if PLATFORM(SGL)
+ virtual SkBitmapRef* getBitmap() { return 0; }
+ virtual void setURL(const String& str) {}
+#endif
+
+protected:
+ Image(ImageObserver* = 0);
+
+ static void fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op);
+
+#if PLATFORM(WIN)
+ virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator) { }
+#endif
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator) = 0;
+ void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, CompositeOperator);
+ void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator);
+
+ // Supporting tiled drawing
+ virtual bool mayFillWithSolidColor() const { return false; }
+ virtual Color solidColor() const { return Color(); }
+
+ virtual void startAnimation() { }
+
+ virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator, const FloatRect& destRect);
+#if PLATFORM(CG)
+ // These are private to CG. Ideally they would be only in the .cpp file, but the callback requires access
+ // to the private function nativeImageForCurrentFrame()
+ static void drawPatternCallback(void* info, CGContext*);
+#endif
+
+protected:
+ RefPtr<SharedBuffer> m_data; // The encoded raw data for the image.
+ ImageObserver* m_imageObserver;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h
new file mode 100644
index 0000000..7c68fc8
--- /dev/null
+++ b/WebCore/platform/graphics/ImageBuffer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007, 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageBuffer_h
+#define ImageBuffer_h
+
+#include "Image.h"
+#include "IntSize.h"
+#include "ImageBufferData.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <memory>
+
+namespace WebCore {
+
+ class GraphicsContext;
+ class ImageData;
+ class IntPoint;
+ class IntRect;
+ class String;
+
+ class ImageBuffer : Noncopyable {
+ public:
+ // Will return a null pointer on allocation failure.
+ static std::auto_ptr<ImageBuffer> create(const IntSize& size, bool grayScale)
+ {
+ bool success = false;
+ std::auto_ptr<ImageBuffer> buf(new ImageBuffer(size, grayScale, success));
+ if (success)
+ return buf;
+ return std::auto_ptr<ImageBuffer>();
+ }
+
+ ~ImageBuffer();
+
+ const IntSize& size() const { return m_size; }
+ GraphicsContext* context() const;
+
+ Image* image() const;
+
+ void clearImage() { m_image.clear(); }
+
+ PassRefPtr<ImageData> getImageData(const IntRect& rect) const;
+ void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint);
+
+ String toDataURL(const String& mimeType) const;
+
+ private:
+ ImageBufferData m_data;
+
+ IntSize m_size;
+ OwnPtr<GraphicsContext> m_context;
+ mutable RefPtr<Image> m_image;
+
+ // This constructor will place its succes into the given out-variable
+ // so that create() knows when it should return failure.
+ ImageBuffer(const IntSize&, bool grayScale, bool& success);
+ };
+
+} // namespace WebCore
+
+#endif // ImageBuffer_h
diff --git a/WebCore/platform/graphics/ImageObserver.h b/WebCore/platform/graphics/ImageObserver.h
new file mode 100644
index 0000000..4be83bd
--- /dev/null
+++ b/WebCore/platform/graphics/ImageObserver.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageObserver_h
+#define ImageObserver_h
+
+namespace WebCore {
+
+class Image;
+
+// Interface for notification about changes to an image, including decoding,
+// drawing, and animating.
+class ImageObserver {
+protected:
+ virtual ~ImageObserver() {}
+public:
+ virtual void decodedSizeChanged(const Image*, int delta) = 0;
+ virtual void didDraw(const Image*) = 0;
+
+ virtual bool shouldPauseAnimation(const Image*) = 0;
+ virtual void animationAdvanced(const Image*) = 0;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h
new file mode 100644
index 0000000..a9f346d
--- /dev/null
+++ b/WebCore/platform/graphics/ImageSource.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageSource_h
+#define ImageSource_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(WX)
+class wxBitmap;
+#elif PLATFORM(CG)
+typedef struct CGImageSource* CGImageSourceRef;
+typedef struct CGImage* CGImageRef;
+typedef const struct __CFData* CFDataRef;
+#elif PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QPixmap;
+QT_END_NAMESPACE
+#elif PLATFORM(CAIRO)
+struct _cairo_surface;
+typedef struct _cairo_surface cairo_surface_t;
+#elif PLATFORM(SGL)
+#include "SkString.h"
+class SkBitmapRef;
+class PrivateAndroidImageSourceRec;
+#elif PLATFORM(SKIA)
+class NativeImageSkia;
+#endif
+
+namespace WebCore {
+
+class IntSize;
+class SharedBuffer;
+
+#if PLATFORM(WX)
+class ImageDecoder;
+typedef ImageDecoder* NativeImageSourcePtr;
+typedef const Vector<char>* NativeBytePtr;
+typedef wxBitmap* NativeImagePtr;
+#elif PLATFORM(CG)
+typedef CGImageSourceRef NativeImageSourcePtr;
+typedef CGImageRef NativeImagePtr;
+#elif PLATFORM(QT)
+class ImageDecoderQt;
+typedef ImageDecoderQt* NativeImageSourcePtr;
+typedef QPixmap* NativeImagePtr;
+#elif PLATFORM(SGL)
+class String;
+struct NativeImageSourcePtr {
+ SkString m_url;
+ PrivateAndroidImageSourceRec* m_image;
+};
+typedef const Vector<char>* NativeBytePtr;
+typedef SkBitmapRef* NativeImagePtr;
+#elif PLATFORM(CAIRO)
+class ImageDecoder;
+typedef ImageDecoder* NativeImageSourcePtr;
+typedef cairo_surface_t* NativeImagePtr;
+#elif PLATFORM(SKIA)
+class ImageDecoder;
+typedef ImageDecoder* NativeImageSourcePtr;
+typedef NativeImageSkia* NativeImagePtr;
+#endif
+
+const int cAnimationLoopOnce = -1;
+const int cAnimationNone = -2;
+
+class ImageSource : Noncopyable {
+public:
+ ImageSource();
+ ~ImageSource();
+
+ void clear();
+
+ bool initialized() const;
+
+ void setData(SharedBuffer* data, bool allDataReceived);
+
+ bool isSizeAvailable();
+ IntSize size() const;
+ IntSize frameSizeAtIndex(size_t) const;
+
+ int repetitionCount();
+
+ size_t frameCount() const;
+
+ 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.
+
+#if PLATFORM(SGL)
+ void clearURL();
+ void setURL(const String& url);
+#endif
+private:
+ NativeImageSourcePtr m_decoder;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h
new file mode 100644
index 0000000..cb24b4e
--- /dev/null
+++ b/WebCore/platform/graphics/IntPoint.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IntPoint_h
+#define IntPoint_h
+
+#include "IntSize.h"
+#include <wtf/Platform.h>
+
+#if PLATFORM(CG)
+typedef struct CGPoint CGPoint;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGPoint NSPoint;
+#else
+typedef struct _NSPoint NSPoint;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagPOINT POINT;
+typedef struct tagPOINTS POINTS;
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QPoint;
+QT_END_NAMESPACE
+#elif PLATFORM(GTK)
+typedef struct _GdkPoint GdkPoint;
+#endif
+#if PLATFORM(SYMBIAN)
+class TPoint;
+#endif
+
+#if PLATFORM(WX)
+class wxPoint;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkPoint;
+struct SkIPoint;
+#endif
+
+namespace WebCore {
+
+class IntPoint {
+public:
+ IntPoint() : m_x(0), m_y(0) { }
+ IntPoint(int x, int y) : m_x(x), m_y(y) { }
+
+ int x() const { return m_x; }
+ int y() const { return m_y; }
+
+ void setX(int x) { m_x = x; }
+ void setY(int y) { m_y = y; }
+
+ void move(int dx, int dy) { m_x += dx; m_y += dy; }
+
+ IntPoint expandedTo(const IntPoint& other) const
+ {
+ return IntPoint(m_x > other.m_x ? m_x : other.m_x,
+ m_y > other.m_y ? m_y : other.m_y);
+ }
+
+ IntPoint shrunkTo(const IntPoint& other) const
+ {
+ return IntPoint(m_x < other.m_x ? m_x : other.m_x,
+ m_y < other.m_y ? m_y : other.m_y);
+ }
+
+ void clampNegativeToZero()
+ {
+ *this = expandedTo(IntPoint());
+ }
+
+#if PLATFORM(CG)
+ explicit IntPoint(const CGPoint&); // don't do this implicitly since it's lossy
+ operator CGPoint() const;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ explicit IntPoint(const NSPoint&); // don't do this implicitly since it's lossy
+ operator NSPoint() const;
+#endif
+
+#if PLATFORM(WIN)
+ IntPoint(const POINT&);
+ operator POINT() const;
+ IntPoint(const POINTS&);
+ operator POINTS() const;
+#elif PLATFORM(QT)
+ IntPoint(const QPoint&);
+ operator QPoint() const;
+#elif PLATFORM(GTK)
+ IntPoint(const GdkPoint&);
+ operator GdkPoint() const;
+#endif
+#if PLATFORM(SYMBIAN)
+ IntPoint(const TPoint&);
+ operator TPoint() const;
+#endif
+
+#if PLATFORM(WX)
+ IntPoint(const wxPoint&);
+ operator wxPoint() const;
+#endif
+
+#if PLATFORM(SKIA)
+ IntPoint(const SkIPoint&);
+ operator SkIPoint() const;
+ operator SkPoint() const;
+#endif
+
+private:
+ int m_x, m_y;
+};
+
+inline IntPoint& operator+=(IntPoint& a, const IntSize& b)
+{
+ a.move(b.width(), b.height());
+ return a;
+}
+
+inline IntPoint& operator-=(IntPoint& a, const IntSize& b)
+{
+ a.move(-b.width(), -b.height());
+ return a;
+}
+
+inline IntPoint operator+(const IntPoint& a, const IntSize& b)
+{
+ return IntPoint(a.x() + b.width(), a.y() + b.height());
+}
+
+inline IntSize operator-(const IntPoint& a, const IntPoint& b)
+{
+ return IntSize(a.x() - b.x(), a.y() - b.y());
+}
+
+inline IntPoint operator-(const IntPoint& a, const IntSize& b)
+{
+ return IntPoint(a.x() - b.width(), a.y() - b.height());
+}
+
+inline bool operator==(const IntPoint& a, const IntPoint& b)
+{
+ return a.x() == b.x() && a.y() == b.y();
+}
+
+inline bool operator!=(const IntPoint& a, const IntPoint& b)
+{
+ return a.x() != b.x() || a.y() != b.y();
+}
+
+} // namespace WebCore
+
+#endif // IntPoint_h
diff --git a/WebCore/platform/graphics/IntRect.cpp b/WebCore/platform/graphics/IntRect.cpp
new file mode 100644
index 0000000..622e525
--- /dev/null
+++ b/WebCore/platform/graphics/IntRect.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, 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 "IntRect.h"
+
+#include "FloatRect.h"
+#include <algorithm>
+
+using std::max;
+using std::min;
+
+namespace WebCore {
+
+IntRect::IntRect(const FloatRect& r)
+ : m_location(IntPoint(static_cast<int>(r.x()), static_cast<int>(r.y())))
+ , m_size(IntSize(static_cast<int>(r.width()), static_cast<int>(r.height())))
+{
+}
+
+bool IntRect::intersects(const IntRect& other) const
+{
+ // Checking emptiness handles negative widths as well as zero.
+ return !isEmpty() && !other.isEmpty()
+ && x() < other.right() && other.x() < right()
+ && y() < other.bottom() && other.y() < bottom();
+}
+
+bool IntRect::contains(const IntRect& other) const
+{
+ return x() <= other.x() && right() >= other.right()
+ && y() <= other.y() && bottom() >= other.bottom();
+}
+
+void IntRect::intersect(const IntRect& other)
+{
+ int l = max(x(), other.x());
+ int t = max(y(), other.y());
+ int r = min(right(), other.right());
+ int b = min(bottom(), other.bottom());
+
+ // Return a clean empty rectangle for non-intersecting cases.
+ if (l >= r || t >= b) {
+ l = 0;
+ t = 0;
+ r = 0;
+ b = 0;
+ }
+
+ m_location.setX(l);
+ m_location.setY(t);
+ m_size.setWidth(r - l);
+ m_size.setHeight(b - t);
+}
+
+void IntRect::unite(const IntRect& other)
+{
+ // Handle empty special cases first.
+ if (other.isEmpty())
+ return;
+ if (isEmpty()) {
+ *this = other;
+ return;
+ }
+
+ int l = min(x(), other.x());
+ int t = min(y(), other.y());
+ int r = max(right(), other.right());
+ int b = max(bottom(), other.bottom());
+
+ m_location.setX(l);
+ m_location.setY(t);
+ m_size.setWidth(r - l);
+ m_size.setHeight(b - t);
+}
+
+void IntRect::scale(float s)
+{
+ m_location.setX((int)(x() * s));
+ m_location.setY((int)(y() * s));
+ m_size.setWidth((int)(width() * s));
+ m_size.setHeight((int)(height() * s));
+}
+
+}
diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h
new file mode 100644
index 0000000..03784a3
--- /dev/null
+++ b/WebCore/platform/graphics/IntRect.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IntRect_h
+#define IntRect_h
+
+#include "IntPoint.h"
+#include <wtf/Platform.h>
+
+#if PLATFORM(CG)
+typedef struct CGRect CGRect;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGRect NSRect;
+#else
+typedef struct _NSRect NSRect;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagRECT RECT;
+#elif PLATFORM(QT)
+QT_BEGIN_NAMESPACE
+class QRect;
+QT_END_NAMESPACE
+#elif PLATFORM(GTK)
+typedef struct _GdkRectangle GdkRectangle;
+#endif
+#if PLATFORM(SYMBIAN)
+class TRect;
+#endif
+
+#if PLATFORM(WX)
+class wxRect;
+#endif
+
+#if PLATFORM(SKIA)
+struct SkRect;
+struct SkIRect;
+#endif
+
+namespace WebCore {
+
+class FloatRect;
+
+class IntRect {
+public:
+ IntRect() { }
+ IntRect(const IntPoint& location, const IntSize& size)
+ : m_location(location), m_size(size) { }
+ IntRect(int x, int y, int width, int height)
+ : m_location(IntPoint(x, y)), m_size(IntSize(width, height)) { }
+
+ explicit IntRect(const FloatRect& rect); // don't do this implicitly since it's lossy
+
+ IntPoint location() const { return m_location; }
+ IntSize size() const { return m_size; }
+
+ void setLocation(const IntPoint& location) { m_location = location; }
+ void setSize(const IntSize& size) { m_size = size; }
+
+ int x() const { return m_location.x(); }
+ int y() const { return m_location.y(); }
+ int width() const { return m_size.width(); }
+ int height() const { return m_size.height(); }
+
+ void setX(int x) { m_location.setX(x); }
+ void setY(int y) { m_location.setY(y); }
+ void setWidth(int width) { m_size.setWidth(width); }
+ void setHeight(int height) { m_size.setHeight(height); }
+
+ // Be careful with these functions. The point is considered to be to the right and below. These are not
+ // substitutes for right() and bottom().
+ IntPoint topLeft() const { return m_location; }
+ IntPoint topRight() const { return IntPoint(right() - 1, y()); }
+ IntPoint bottomLeft() const { return IntPoint(x(), bottom() - 1); }
+ IntPoint bottomRight() const { return IntPoint(right() - 1, bottom() - 1); }
+
+ bool isEmpty() const { return m_size.isEmpty(); }
+
+ int right() const { return x() + width(); }
+ int bottom() const { return y() + height(); }
+
+ void move(const IntSize& s) { m_location += s; }
+ void move(int dx, int dy) { m_location.move(dx, dy); }
+
+ bool intersects(const IntRect&) const;
+ bool contains(const IntRect&) const;
+
+ // This checks to see if the rect contains x,y in the traditional sense.
+ // Equivalent to checking if the rect contains a 1x1 rect below and to the right of (px,py).
+ bool contains(int px, int py) const
+ { return px >= x() && px < right() && py >= y() && py < bottom(); }
+ bool contains(const IntPoint& point) const { return contains(point.x(), point.y()); }
+
+ void intersect(const IntRect&);
+ void unite(const IntRect&);
+
+ void inflateX(int dx)
+ {
+ m_location.setX(m_location.x() - dx);
+ m_size.setWidth(m_size.width() + dx + dx);
+ }
+ void inflateY(int dy)
+ {
+ m_location.setY(m_location.y() - dy);
+ m_size.setHeight(m_size.height() + dy + dy);
+ }
+ void inflate(int d) { inflateX(d); inflateY(d); }
+ void scale(float s);
+
+#if PLATFORM(WX)
+ IntRect(const wxRect&);
+ operator wxRect() const;
+#endif
+
+#if PLATFORM(WIN)
+ IntRect(const RECT&);
+ operator RECT() const;
+#elif PLATFORM(QT)
+ IntRect(const QRect&);
+ operator QRect() const;
+#elif PLATFORM(GTK)
+ IntRect(const GdkRectangle&);
+ operator GdkRectangle() const;
+#endif
+#if PLATFORM(SYMBIAN)
+ IntRect(const TRect&);
+ operator TRect() const;
+ TRect Rect() const;
+#endif
+
+#if PLATFORM(CG)
+ operator CGRect() const;
+#endif
+
+#if PLATFORM(SKIA)
+ IntRect(const SkIRect&);
+ operator SkRect() const;
+ operator SkIRect() const;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ operator NSRect() const;
+#endif
+
+private:
+ IntPoint m_location;
+ IntSize m_size;
+};
+
+inline IntRect intersection(const IntRect& a, const IntRect& b)
+{
+ IntRect c = a;
+ c.intersect(b);
+ return c;
+}
+
+inline IntRect unionRect(const IntRect& a, const IntRect& b)
+{
+ IntRect c = a;
+ c.unite(b);
+ return c;
+}
+
+inline bool operator==(const IntRect& a, const IntRect& b)
+{
+ return a.location() == b.location() && a.size() == b.size();
+}
+
+inline bool operator!=(const IntRect& a, const IntRect& b)
+{
+ return a.location() != b.location() || a.size() != b.size();
+}
+
+#if PLATFORM(CG)
+IntRect enclosingIntRect(const CGRect&);
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+IntRect enclosingIntRect(const NSRect&);
+#endif
+
+} // namespace WebCore
+
+#endif // IntRect_h
diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h
new file mode 100644
index 0000000..7245408
--- /dev/null
+++ b/WebCore/platform/graphics/IntSize.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IntSize_h
+#define IntSize_h
+
+#include <wtf/Platform.h>
+
+#if PLATFORM(CG)
+typedef struct CGSize CGSize;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+typedef struct CGSize NSSize;
+#else
+typedef struct _NSSize NSSize;
+#endif
+#endif
+
+#if PLATFORM(WIN)
+typedef struct tagSIZE SIZE;
+#elif PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QSize;
+QT_END_NAMESPACE
+#endif
+#if PLATFORM(SYMBIAN)
+class TSize;
+#endif
+
+namespace WebCore {
+
+class IntSize {
+public:
+ IntSize() : m_width(0), m_height(0) { }
+ IntSize(int width, int height) : m_width(width), m_height(height) { }
+
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+
+ void setWidth(int width) { m_width = width; }
+ void setHeight(int height) { m_height = height; }
+
+ bool isEmpty() const { return m_width <= 0 || m_height <= 0; }
+
+ IntSize expandedTo(const IntSize& other) const
+ {
+ return IntSize(m_width > other.m_width ? m_width : other.m_width,
+ m_height > other.m_height ? m_height : other.m_height);
+ }
+
+ IntSize shrunkTo(const IntSize& other) const
+ {
+ return IntSize(m_width < other.m_width ? m_width : other.m_width,
+ m_height < other.m_height ? m_height : other.m_height);
+ }
+
+ void clampNegativeToZero()
+ {
+ *this = expandedTo(IntSize());
+ }
+
+#if PLATFORM(CG)
+ explicit IntSize(const CGSize&); // don't do this implicitly since it's lossy
+ operator CGSize() const;
+#endif
+
+#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)
+ explicit IntSize(const NSSize &); // don't do this implicitly since it's lossy
+ operator NSSize() const;
+#endif
+
+#if PLATFORM(WIN)
+ IntSize(const SIZE&);
+ operator SIZE() const;
+#endif
+
+#if PLATFORM(QT)
+ IntSize(const QSize&);
+ operator QSize() const;
+#endif
+#if PLATFORM(SYMBIAN)
+ IntSize(const TSize&);
+ operator TSize() const;
+#endif
+
+
+private:
+ int m_width, m_height;
+};
+
+inline IntSize& operator+=(IntSize& a, const IntSize& b)
+{
+ a.setWidth(a.width() + b.width());
+ a.setHeight(a.height() + b.height());
+ return a;
+}
+
+inline IntSize& operator-=(IntSize& a, const IntSize& b)
+{
+ a.setWidth(a.width() - b.width());
+ a.setHeight(a.height() - b.height());
+ return a;
+}
+
+inline IntSize operator+(const IntSize& a, const IntSize& b)
+{
+ return IntSize(a.width() + b.width(), a.height() + b.height());
+}
+
+inline IntSize operator-(const IntSize& a, const IntSize& b)
+{
+ return IntSize(a.width() - b.width(), a.height() - b.height());
+}
+
+inline IntSize operator-(const IntSize& size)
+{
+ return IntSize(-size.width(), -size.height());
+}
+
+inline bool operator==(const IntSize& a, const IntSize& b)
+{
+ return a.width() == b.width() && a.height() == b.height();
+}
+
+inline bool operator!=(const IntSize& a, const IntSize& b)
+{
+ return a.width() != b.width() || a.height() != b.height();
+}
+
+} // namespace WebCore
+
+#endif // IntSize_h
diff --git a/WebCore/platform/graphics/IntSizeHash.h b/WebCore/platform/graphics/IntSizeHash.h
new file mode 100644
index 0000000..ad6eac3
--- /dev/null
+++ b/WebCore/platform/graphics/IntSizeHash.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef IntSizeHash_h
+#define IntSizeHash_h
+
+#include "IntSize.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+
+using WebCore::IntSize;
+
+namespace WTF {
+
+ template<> struct IntHash<IntSize> {
+ static unsigned hash(const IntSize& key) { return intHash((static_cast<uint64_t>(key.width()) << 32 | key.height())); }
+ static bool equal(const IntSize& a, const IntSize& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+ template<> struct DefaultHash<IntSize> { typedef IntHash<IntSize> Hash; };
+
+ template<> struct HashTraits<IntSize> : GenericHashTraits<IntSize> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = false;
+ static void constructDeletedValue(IntSize& slot) { new (&slot) IntSize(-1, -1); }
+ static bool isDeletedValue(const IntSize& value) { return value.width() == -1 && value.height() == -1; }
+ };
+} // namespace WTF
+
+#endif
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
new file mode 100644
index 0000000..21e31fc
--- /dev/null
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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"
+
+#if ENABLE(VIDEO)
+#include "MediaPlayer.h"
+
+#include "IntRect.h"
+#include "MIMETypeRegistry.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "Document.h"
+
+#if PLATFORM(MAC)
+#include "MediaPlayerPrivateQTKit.h"
+#elif PLATFORM(WIN)
+#include "MediaPlayerPrivateQuickTimeWin.h"
+#elif PLATFORM(GTK)
+#include "MediaPlayerPrivateGStreamer.h"
+#elif PLATFORM(QT)
+#include "MediaPlayerPrivatePhonon.h"
+#elif PLATFORM(CHROMIUM)
+#include "MediaPlayerPrivateChromium.h"
+#endif
+
+namespace WebCore {
+
+ MediaPlayer::MediaPlayer(MediaPlayerClient* client)
+ : m_mediaPlayerClient(client)
+ , m_private(new MediaPlayerPrivate(this))
+ , m_frameView(0)
+ , m_visible(false)
+ , m_rate(1.0f)
+ , m_volume(1.0f)
+{
+}
+
+MediaPlayer::~MediaPlayer()
+{
+ delete m_private;
+}
+
+void MediaPlayer::load(const String& url)
+{
+ m_private->load(url);
+}
+
+void MediaPlayer::cancelLoad()
+{
+ m_private->cancelLoad();
+}
+
+void MediaPlayer::play()
+{
+ m_private->play();
+}
+
+void MediaPlayer::pause()
+{
+ m_private->pause();
+}
+
+float MediaPlayer::duration() const
+{
+ return m_private->duration();
+}
+
+float MediaPlayer::currentTime() const
+{
+ return m_private->currentTime();
+}
+
+void MediaPlayer::seek(float time)
+{
+ m_private->seek(time);
+}
+
+bool MediaPlayer::paused() const
+{
+ return m_private->paused();
+}
+
+bool MediaPlayer::seeking() const
+{
+ return m_private->seeking();
+}
+
+IntSize MediaPlayer::naturalSize()
+{
+ return m_private->naturalSize();
+}
+
+bool MediaPlayer::hasVideo()
+{
+ return m_private->hasVideo();
+}
+
+bool MediaPlayer::inMediaDocument()
+{
+ Frame* frame = m_frameView ? m_frameView->frame() : 0;
+ Document* document = frame ? frame->document() : 0;
+
+ return document && document->isMediaDocument();
+}
+
+MediaPlayer::NetworkState MediaPlayer::networkState()
+{
+ return m_private->networkState();
+}
+
+MediaPlayer::ReadyState MediaPlayer::readyState()
+{
+ return m_private->readyState();
+}
+
+float MediaPlayer::volume() const
+{
+ return m_volume;
+}
+
+void MediaPlayer::setVolume(float volume)
+{
+ m_volume = volume;
+ m_private->setVolume(volume);
+}
+
+float MediaPlayer::rate() const
+{
+ return m_rate;
+}
+
+void MediaPlayer::setRate(float rate)
+{
+ m_rate = rate;
+ m_private->setRate(rate);
+}
+
+int MediaPlayer::dataRate() const
+{
+ return m_private->dataRate();
+}
+
+void MediaPlayer::setEndTime(float time)
+{
+ m_private->setEndTime(time);
+}
+
+float MediaPlayer::maxTimeBuffered()
+{
+ return m_private->maxTimeBuffered();
+}
+
+float MediaPlayer::maxTimeSeekable()
+{
+ return m_private->maxTimeSeekable();
+}
+
+unsigned MediaPlayer::bytesLoaded()
+{
+ return m_private->bytesLoaded();
+}
+
+bool MediaPlayer::totalBytesKnown()
+{
+ return m_private->totalBytesKnown();
+}
+
+unsigned MediaPlayer::totalBytes()
+{
+ return m_private->totalBytes();
+}
+
+void MediaPlayer::setRect(const IntRect& r)
+{
+ m_rect = r;
+ m_private->setRect(r);
+}
+
+bool MediaPlayer::visible() const
+{
+ return m_visible;
+}
+
+void MediaPlayer::setVisible(bool b)
+{
+ m_visible = b;
+ m_private->setVisible(b);
+}
+
+void MediaPlayer::paint(GraphicsContext* p, const IntRect& r)
+{
+ m_private->paint(p, r);
+}
+
+bool MediaPlayer::supportsType(const String& type)
+{
+ HashSet<String> types;
+ getSupportedTypes(types);
+ return MIMETypeRegistry::isSupportedMediaMIMEType(type) && types.contains(type);
+}
+
+void MediaPlayer::getSupportedTypes(HashSet<String>& types)
+{
+ MediaPlayerPrivate::getSupportedTypes(types);
+}
+
+bool MediaPlayer::isAvailable()
+{
+ static bool availabityKnown = false;
+ static bool isAvailable;
+ if (!availabityKnown) {
+ isAvailable = MediaPlayerPrivate::isAvailable();
+ availabityKnown = true;
+ }
+ return isAvailable;
+}
+
+void MediaPlayer::networkStateChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerNetworkStateChanged(this);
+}
+
+void MediaPlayer::readyStateChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerReadyStateChanged(this);
+}
+
+void MediaPlayer::volumeChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerVolumeChanged(this);
+}
+
+void MediaPlayer::timeChanged()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerTimeChanged(this);
+}
+
+void MediaPlayer::repaint()
+{
+ if (m_mediaPlayerClient)
+ m_mediaPlayerClient->mediaPlayerRepaint(this);
+}
+
+}
+#endif
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
new file mode 100644
index 0000000..1beab95
--- /dev/null
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayer_h
+#define MediaPlayer_h
+
+#if ENABLE(VIDEO)
+
+#include "IntRect.h"
+#include "StringHash.h"
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class FrameView;
+class GraphicsContext;
+class IntSize;
+class MediaPlayer;
+class MediaPlayerPrivate;
+class String;
+
+class MediaPlayerClient {
+public:
+ virtual ~MediaPlayerClient() { }
+ virtual void mediaPlayerNetworkStateChanged(MediaPlayer*) { }
+ virtual void mediaPlayerReadyStateChanged(MediaPlayer*) { }
+ virtual void mediaPlayerVolumeChanged(MediaPlayer*) { }
+ virtual void mediaPlayerTimeChanged(MediaPlayer*) { }
+ virtual void mediaPlayerRepaint(MediaPlayer*) { }
+};
+
+class MediaPlayer : Noncopyable {
+public:
+ MediaPlayer(MediaPlayerClient*);
+ virtual ~MediaPlayer();
+
+ static bool isAvailable();
+ static bool supportsType(const String&);
+ static void getSupportedTypes(HashSet<String>&);
+
+ IntSize naturalSize();
+ bool hasVideo();
+
+ void setFrameView(FrameView* frameView) { m_frameView = frameView; }
+ bool inMediaDocument();
+
+ IntRect rect() const { return m_rect; }
+ void setRect(const IntRect& r);
+
+ void load(const String& url);
+ void cancelLoad();
+
+ bool visible() const;
+ void setVisible(bool);
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float time);
+
+ void setEndTime(float time);
+
+ float rate() const;
+ void setRate(float);
+
+ float maxTimeBuffered();
+ float maxTimeSeekable();
+
+ unsigned bytesLoaded();
+ bool totalBytesKnown();
+ unsigned totalBytes();
+
+ float volume() const;
+ void setVolume(float);
+
+ int dataRate() const;
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ enum NetworkState { Empty, LoadFailed, Loading, LoadedMetaData, LoadedFirstFrame, Loaded };
+ NetworkState networkState();
+
+ enum ReadyState { DataUnavailable, CanShowCurrentFrame, CanPlay, CanPlayThrough };
+ ReadyState readyState();
+
+ void networkStateChanged();
+ void readyStateChanged();
+ void volumeChanged();
+ void timeChanged();
+
+ void repaint();
+
+private:
+
+ friend class MediaPlayerPrivate;
+
+ MediaPlayerClient* m_mediaPlayerClient;
+ MediaPlayerPrivate* m_private;
+ FrameView* m_frameView;
+ IntRect m_rect;
+ bool m_visible;
+ float m_rate;
+ float m_volume;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp
new file mode 100644
index 0000000..f3450be
--- /dev/null
+++ b/WebCore/platform/graphics/Path.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+#include "Path.h"
+
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "PathTraversalState.h"
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+const float QUARTER = 0.552f; // approximation of control point positions on a bezier
+ // to simulate a quarter of a circle.
+namespace WebCore {
+
+static void pathLengthApplierFunction(void* info, const PathElement* element)
+{
+ PathTraversalState& traversalState = *static_cast<PathTraversalState*>(info);
+ if (traversalState.m_success)
+ return;
+ traversalState.m_previous = traversalState.m_current;
+ FloatPoint* points = element->points;
+ float segmentLength = 0.0f;
+ switch (element->type) {
+ case PathElementMoveToPoint:
+ segmentLength = traversalState.moveTo(points[0]);
+ break;
+ case PathElementAddLineToPoint:
+ segmentLength = traversalState.lineTo(points[0]);
+ break;
+ case PathElementAddQuadCurveToPoint:
+ segmentLength = traversalState.quadraticBezierTo(points[0], points[1]);
+ break;
+ case PathElementAddCurveToPoint:
+ segmentLength = traversalState.cubicBezierTo(points[0], points[1], points[2]);
+ break;
+ case PathElementCloseSubpath:
+ segmentLength = traversalState.closeSubpath();
+ break;
+ }
+ traversalState.m_totalLength += segmentLength;
+ if ((traversalState.m_action == PathTraversalState::TraversalPointAtLength ||
+ traversalState.m_action == PathTraversalState::TraversalNormalAngleAtLength) &&
+ (traversalState.m_totalLength >= traversalState.m_desiredLength)) {
+ FloatSize change = traversalState.m_current - traversalState.m_previous;
+ float slope = atan2f(change.height(), change.width());
+
+ if (traversalState.m_action == PathTraversalState::TraversalPointAtLength) {
+ float offset = traversalState.m_desiredLength - traversalState.m_totalLength;
+ traversalState.m_current.move(offset * cosf(slope), offset * sinf(slope));
+ } else {
+ static const float rad2deg = 180.0f / piFloat;
+ traversalState.m_normalAngle = slope * rad2deg;
+ }
+
+ traversalState.m_success = true;
+ }
+}
+
+float Path::length()
+{
+ PathTraversalState traversalState(PathTraversalState::TraversalTotalLength);
+ apply(&traversalState, pathLengthApplierFunction);
+ return traversalState.m_totalLength;
+}
+
+FloatPoint Path::pointAtLength(float length, bool& ok)
+{
+ PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength);
+ traversalState.m_desiredLength = length;
+ apply(&traversalState, pathLengthApplierFunction);
+ ok = traversalState.m_success;
+ return traversalState.m_current;
+}
+
+float Path::normalAngleAtLength(float length, bool& ok)
+{
+ PathTraversalState traversalState(PathTraversalState::TraversalNormalAngleAtLength);
+ traversalState.m_desiredLength = length;
+ apply(&traversalState, pathLengthApplierFunction);
+ ok = traversalState.m_success;
+ return traversalState.m_normalAngle;
+}
+
+Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& roundingRadii)
+{
+ Path path;
+ float x = rectangle.x();
+ float y = rectangle.y();
+ float width = rectangle.width();
+ float height = rectangle.height();
+ float rx = roundingRadii.width();
+ float ry = roundingRadii.height();
+ if (width <= 0.0f || height <= 0.0f)
+ return path;
+
+ float dx = rx, dy = ry;
+ // If rx is greater than half of the width of the rectangle
+ // then set rx to half of the width (required in SVG spec)
+ if (dx > width * 0.5f)
+ dx = width * 0.5f;
+
+ // If ry is greater than half of the height of the rectangle
+ // then set ry to half of the height (required in SVG spec)
+ if (dy > height * 0.5f)
+ dy = height * 0.5f;
+
+ path.moveTo(FloatPoint(x + dx, y));
+
+ if (dx < width * 0.5f)
+ path.addLineTo(FloatPoint(x + width - rx, y));
+
+ path.addBezierCurveTo(FloatPoint(x + width - dx * (1 - QUARTER), y), FloatPoint(x + width, y + dy * (1 - QUARTER)), FloatPoint(x + width, y + dy));
+
+ if (dy < height * 0.5)
+ path.addLineTo(FloatPoint(x + width, y + height - dy));
+
+ path.addBezierCurveTo(FloatPoint(x + width, y + height - dy * (1 - QUARTER)), FloatPoint(x + width - dx * (1 - QUARTER), y + height), FloatPoint(x + width - dx, y + height));
+
+ if (dx < width * 0.5)
+ path.addLineTo(FloatPoint(x + dx, y + height));
+
+ path.addBezierCurveTo(FloatPoint(x + dx * (1 - QUARTER), y + height), FloatPoint(x, y + height - dy * (1 - QUARTER)), FloatPoint(x, y + height - dy));
+
+ if (dy < height * 0.5)
+ path.addLineTo(FloatPoint(x, y + dy));
+
+ path.addBezierCurveTo(FloatPoint(x, y + dy * (1 - QUARTER)), FloatPoint(x + dx * (1 - QUARTER), y), FloatPoint(x + dx, y));
+
+ path.closeSubpath();
+
+ return path;
+}
+
+Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius)
+{
+ Path path;
+
+ float width = rectangle.width();
+ float height = rectangle.height();
+ if (width <= 0.0 || height <= 0.0)
+ return path;
+
+ if (width < topLeftRadius.width() + topRightRadius.width()
+ || width < bottomLeftRadius.width() + bottomRightRadius.width()
+ || height < topLeftRadius.height() + bottomLeftRadius.height()
+ || height < topRightRadius.height() + bottomRightRadius.height())
+ // If all the radii cannot be accommodated, return a rect.
+ return createRectangle(rectangle);
+
+ float x = rectangle.x();
+ float y = rectangle.y();
+
+ path.moveTo(FloatPoint(x + topLeftRadius.width(), y));
+
+ path.addLineTo(FloatPoint(x + width - topRightRadius.width(), y));
+
+ path.addBezierCurveTo(FloatPoint(x + width - topRightRadius.width() * (1 - QUARTER), y), FloatPoint(x + width, y + topRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width, y + topRightRadius.height()));
+
+ path.addLineTo(FloatPoint(x + width, y + height - bottomRightRadius.height()));
+
+ path.addBezierCurveTo(FloatPoint(x + width, y + height - bottomRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width - bottomRightRadius.width() * (1 - QUARTER), y + height), FloatPoint(x + width - bottomRightRadius.width(), y + height));
+
+ path.addLineTo(FloatPoint(x + bottomLeftRadius.width(), y + height));
+
+ path.addBezierCurveTo(FloatPoint(x + bottomLeftRadius.width() * (1 - QUARTER), y + height), FloatPoint(x, y + height - bottomLeftRadius.height() * (1 - QUARTER)), FloatPoint(x, y + height - bottomLeftRadius.height()));
+
+ path.addLineTo(FloatPoint(x, y + topLeftRadius.height()));
+
+ path.addBezierCurveTo(FloatPoint(x, y + topLeftRadius.height() * (1 - QUARTER)), FloatPoint(x + topLeftRadius.width() * (1 - QUARTER), y), FloatPoint(x + topLeftRadius.width(), y));
+
+ path.closeSubpath();
+
+ return path;
+}
+
+Path Path::createRectangle(const FloatRect& rectangle)
+{
+ Path path;
+ float x = rectangle.x();
+ float y = rectangle.y();
+ float width = rectangle.width();
+ float height = rectangle.height();
+ if (width <= 0.0f || height <= 0.0f)
+ return path;
+
+ path.moveTo(FloatPoint(x, y));
+ path.addLineTo(FloatPoint(x + width, y));
+ path.addLineTo(FloatPoint(x + width, y + height));
+ path.addLineTo(FloatPoint(x, y + height));
+ path.closeSubpath();
+
+ return path;
+}
+
+Path Path::createEllipse(const FloatPoint& center, float rx, float ry)
+{
+ float cx = center.x();
+ float cy = center.y();
+ Path path;
+ if (rx <= 0.0f || ry <= 0.0f)
+ return path;
+
+ float x = cx;
+ float y = cy;
+
+ unsigned step = 0, num = 100;
+ bool running = true;
+ while (running)
+ {
+ if (step == num)
+ {
+ running = false;
+ break;
+ }
+
+ float angle = static_cast<float>(step) / static_cast<float>(num) * 2.0f * piFloat;
+ x = cx + cosf(angle) * rx;
+ y = cy + sinf(angle) * ry;
+
+ step++;
+ if (step == 1)
+ path.moveTo(FloatPoint(x, y));
+ else
+ path.addLineTo(FloatPoint(x, y));
+ }
+
+ path.closeSubpath();
+
+ return path;
+}
+
+Path Path::createCircle(const FloatPoint& center, float r)
+{
+ return createEllipse(center, r, r);
+}
+
+Path Path::createLine(const FloatPoint& start, const FloatPoint& end)
+{
+ Path path;
+ if (start.x() == end.x() && start.y() == end.y())
+ return path;
+
+ path.moveTo(start);
+ path.addLineTo(end);
+
+ return path;
+}
+
+}
diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h
new file mode 100644
index 0000000..06e6ee4
--- /dev/null
+++ b/WebCore/platform/graphics/Path.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Path_h
+#define Path_h
+
+#if PLATFORM(CG)
+typedef struct CGPath PlatformPath;
+#elif PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
+class QPainterPath;
+QT_END_NAMESPACE
+typedef QPainterPath PlatformPath;
+#elif PLATFORM(SGL)
+class SkPath;
+typedef SkPath PlatformPath;
+#elif PLATFORM(WX) && USE(WXGC)
+class wxGraphicsPath;
+typedef wxGraphicsPath PlatformPath;
+#elif PLATFORM(CAIRO)
+namespace WebCore {
+ struct CairoPath;
+}
+typedef WebCore::CairoPath PlatformPath;
+#elif PLATFORM(SKIA)
+class SkPath;
+typedef SkPath PlatformPath;
+#else
+typedef void PlatformPath;
+#endif
+
+namespace WebCore {
+
+ class AffineTransform;
+ class FloatPoint;
+ class FloatSize;
+ class FloatRect;
+ class String;
+
+ enum WindRule {
+ RULE_NONZERO = 0,
+ RULE_EVENODD = 1
+ };
+
+ enum PathElementType {
+ PathElementMoveToPoint,
+ PathElementAddLineToPoint,
+ PathElementAddQuadCurveToPoint,
+ PathElementAddCurveToPoint,
+ PathElementCloseSubpath
+ };
+
+ struct PathElement {
+ PathElementType type;
+ FloatPoint* points;
+ };
+
+ typedef void (*PathApplierFunction) (void* info, const PathElement*);
+
+ class Path {
+ public:
+ Path();
+ ~Path();
+
+ Path(const Path&);
+ Path& operator=(const Path&);
+
+ bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const;
+ FloatRect boundingRect() const;
+
+ float length();
+ FloatPoint pointAtLength(float length, bool& ok);
+ float normalAngleAtLength(float length, bool& ok);
+
+ void clear();
+ bool isEmpty() const;
+
+ void moveTo(const FloatPoint&);
+ void addLineTo(const FloatPoint&);
+ void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& endPoint);
+ void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint);
+ void addArcTo(const FloatPoint&, const FloatPoint&, float radius);
+ void closeSubpath();
+
+ void addArc(const FloatPoint&, float radius, float startAngle, float endAngle, bool anticlockwise);
+ void addRect(const FloatRect&);
+ void addEllipse(const FloatRect&);
+
+ void translate(const FloatSize&);
+
+ String debugString() const;
+
+ PlatformPath* platformPath() const { return m_path; }
+
+ static Path createRoundedRectangle(const FloatRect&, const FloatSize& roundingRadii);
+ static Path createRoundedRectangle(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius);
+ static Path createRectangle(const FloatRect&);
+ static Path createEllipse(const FloatPoint& center, float rx, float ry);
+ static Path createCircle(const FloatPoint& center, float r);
+ static Path createLine(const FloatPoint&, const FloatPoint&);
+
+ void apply(void* info, PathApplierFunction) const;
+ void transform(const AffineTransform&);
+
+ private:
+ PlatformPath* m_path;
+ };
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/PathTraversalState.cpp b/WebCore/platform/graphics/PathTraversalState.cpp
new file mode 100644
index 0000000..d202649
--- /dev/null
+++ b/WebCore/platform/graphics/PathTraversalState.cpp
@@ -0,0 +1,207 @@
+/*
+ * This file is part of the WebKit open source project.
+ *
+ * Copyright (C) 2006, 2007 Eric Seidel (eric@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.
+ */
+
+#include "config.h"
+#include "PathTraversalState.h"
+
+#include "Path.h"
+
+#include <math.h>
+
+namespace WebCore {
+
+static const float kPathSegmentLengthTolerance = 0.00001f;
+
+static inline FloatPoint midPoint(const FloatPoint& first, const FloatPoint& second)
+{
+ return FloatPoint((first.x() + second.x()) / 2.0f, (first.y() + second.y()) / 2.0f);
+}
+
+static inline float distanceLine(const FloatPoint& start, const FloatPoint& end)
+{
+ return sqrtf((end.x() - start.x()) * (end.x() - start.x()) + (end.y() - start.y()) * (end.y() - start.y()));
+}
+
+struct QuadraticBezier {
+ QuadraticBezier() { }
+ QuadraticBezier(const FloatPoint& s, const FloatPoint& c, const FloatPoint& e)
+ : start(s)
+ , control(c)
+ , end(e)
+ {
+ }
+
+ float approximateDistance() const
+ {
+ return distanceLine(start, control) + distanceLine(control, end);
+ }
+
+ void split(QuadraticBezier& left, QuadraticBezier& right) const
+ {
+ left.control = midPoint(start, control);
+ right.control = midPoint(control, end);
+
+ FloatPoint leftControlToRightControl = midPoint(left.control, right.control);
+ left.end = leftControlToRightControl;
+ right.start = leftControlToRightControl;
+
+ left.start = start;
+ right.end = end;
+ }
+
+ FloatPoint start;
+ FloatPoint control;
+ FloatPoint end;
+};
+
+struct CubicBezier {
+ CubicBezier() { }
+ CubicBezier(const FloatPoint& s, const FloatPoint& c1, const FloatPoint& c2, const FloatPoint& e)
+ : start(s)
+ , control1(c1)
+ , control2(c2)
+ , end(e)
+ {
+ }
+
+ float approximateDistance() const
+ {
+ return distanceLine(start, control1) + distanceLine(control1, control2) + distanceLine(control2, end);
+ }
+
+ void split(CubicBezier& left, CubicBezier& right) const
+ {
+ FloatPoint startToControl1 = midPoint(control1, control2);
+
+ left.start = start;
+ left.control1 = midPoint(start, control1);
+ left.control2 = midPoint(left.control1, startToControl1);
+
+ right.control2 = midPoint(control2, end);
+ right.control1 = midPoint(right.control2, startToControl1);
+ right.end = end;
+
+ FloatPoint leftControl2ToRightControl1 = midPoint(left.control2, right.control1);
+ left.end = leftControl2ToRightControl1;
+ right.start = leftControl2ToRightControl1;
+ }
+
+ FloatPoint start;
+ FloatPoint control1;
+ FloatPoint control2;
+ FloatPoint end;
+};
+
+// FIXME: This function is possibly very slow due to the ifs required for proper path measuring
+// A simple speed-up would be to use an additional boolean template parameter to control whether
+// to use the "fast" version of this function with no PathTraversalState updating, vs. the slow
+// version which does update the PathTraversalState. We'll have to shark it to see if that's necessary.
+// Another check which is possible up-front (to send us down the fast path) would be to check if
+// approximateDistance() + current total distance > desired distance
+template<class CurveType>
+static float curveLength(PathTraversalState& traversalState, CurveType curve)
+{
+ Vector<CurveType> curveStack;
+ curveStack.append(curve);
+
+ float totalLength = 0.0f;
+ do {
+ float length = curve.approximateDistance();
+ if ((length - distanceLine(curve.start, curve.end)) > kPathSegmentLengthTolerance) {
+ CurveType left, right;
+ curve.split(left, right);
+ curve = left;
+ curveStack.append(right);
+ } else {
+ totalLength += length;
+ if (traversalState.m_action == PathTraversalState::TraversalPointAtLength
+ || traversalState.m_action == PathTraversalState::TraversalNormalAngleAtLength) {
+ traversalState.m_previous = curve.start;
+ traversalState.m_current = curve.end;
+ if (traversalState.m_totalLength + totalLength > traversalState.m_desiredLength)
+ return totalLength;
+ }
+ curve = curveStack.last();
+ curveStack.removeLast();
+ }
+ } while (!curveStack.isEmpty());
+
+ return totalLength;
+}
+
+PathTraversalState::PathTraversalState(PathTraversalAction action)
+ : m_action(action)
+ , m_success(false)
+ , m_totalLength(0.0f)
+ , m_segmentIndex(0)
+ , m_desiredLength(0.0f)
+ , m_normalAngle(0.0f)
+{
+}
+
+float PathTraversalState::closeSubpath()
+{
+ float distance = distanceLine(m_current, m_start);
+ m_start = m_control1 = m_control2 = m_current;
+ return distance;
+}
+
+float PathTraversalState::moveTo(const FloatPoint& point)
+{
+ m_current = m_start = m_control1 = m_control2 = point;
+ return 0.0f;
+}
+
+float PathTraversalState::lineTo(const FloatPoint& point)
+{
+ float distance = distanceLine(m_current, point);
+ m_current = m_control1 = m_control2 = point;
+ return distance;
+}
+
+float PathTraversalState::quadraticBezierTo(const FloatPoint& newControl, const FloatPoint& newEnd)
+{
+ float distance = curveLength<QuadraticBezier>(*this, QuadraticBezier(m_current, newControl, newEnd));
+
+ m_control1 = newControl;
+ m_control2 = newEnd;
+
+ if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength)
+ m_current = newEnd;
+
+ return distance;
+}
+
+float PathTraversalState::cubicBezierTo(const FloatPoint& newControl1, const FloatPoint& newControl2, const FloatPoint& newEnd)
+{
+ float distance = curveLength<CubicBezier>(*this, CubicBezier(m_current, newControl1, newControl2, newEnd));
+
+ m_control1 = newEnd;
+ m_control2 = newControl2;
+
+ if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength)
+ m_current = newEnd;
+
+ return distance;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/PathTraversalState.h b/WebCore/platform/graphics/PathTraversalState.h
new file mode 100644
index 0000000..5b75767
--- /dev/null
+++ b/WebCore/platform/graphics/PathTraversalState.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006, 2007 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PathTraversalState_h
+#define PathTraversalState_h
+
+#include "FloatPoint.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class Path;
+
+ class PathTraversalState {
+ public:
+ enum PathTraversalAction {
+ TraversalTotalLength,
+ TraversalPointAtLength,
+ TraversalSegmentAtLength,
+ TraversalNormalAngleAtLength
+ };
+
+ PathTraversalState(PathTraversalAction);
+
+ float closeSubpath();
+ float moveTo(const FloatPoint&);
+ float lineTo(const FloatPoint&);
+ float quadraticBezierTo(const FloatPoint& newControl, const FloatPoint& newEnd);
+ float cubicBezierTo(const FloatPoint& newControl1, const FloatPoint& newControl2, const FloatPoint& newEnd);
+
+ public:
+ PathTraversalAction m_action;
+ bool m_success;
+
+ FloatPoint m_current;
+ FloatPoint m_start;
+ FloatPoint m_control1;
+ FloatPoint m_control2;
+
+ float m_totalLength;
+ unsigned m_segmentIndex;
+ float m_desiredLength;
+
+ // For normal calculations
+ FloatPoint m_previous;
+ float m_normalAngle; // degrees
+ };
+}
+
+#endif
diff --git a/WebCore/platform/graphics/Pattern.cpp b/WebCore/platform/graphics/Pattern.cpp
new file mode 100644
index 0000000..d388bd7
--- /dev/null
+++ b/WebCore/platform/graphics/Pattern.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 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
+ * 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 "Pattern.h"
+
+#include "Image.h"
+
+namespace WebCore {
+
+Pattern::Pattern(Image* image, bool repeatX, bool repeatY)
+ : m_tileImage(image)
+ , m_repeatX(repeatX)
+ , m_repeatY(repeatY)
+{
+ ASSERT(image);
+}
+
+Pattern::~Pattern()
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h
new file mode 100644
index 0000000..985c7c0
--- /dev/null
+++ b/WebCore/platform/graphics/Pattern.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Pattern_h
+#define Pattern_h
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(CG)
+typedef struct CGPattern* CGPatternRef;
+typedef CGPatternRef PlatformPatternPtr;
+#elif PLATFORM(CAIRO)
+#include <cairo.h>
+typedef cairo_pattern_t* PlatformPatternPtr;
+#elif PLATFORM(SKIA) || PLATFORM(SGL)
+class SkShader;
+typedef SkShader* PlatformPatternPtr;
+#elif PLATFORM(QT)
+#include <QBrush>
+typedef QBrush PlatformPatternPtr;
+#elif PLATFORM(WX)
+#if USE(WXGC)
+class wxGraphicsBrush;
+typedef wxGraphicsBrush* PlatformPatternPtr;
+#else
+class wxBrush;
+typedef wxBrush* PlatformPatternPtr;
+#endif // USE(WXGC)
+#endif
+
+namespace WebCore {
+ class AffineTransform;
+ class Image;
+
+ class Pattern : public RefCounted<Pattern> {
+ public:
+ static PassRefPtr<Pattern> create(Image* tileImage, bool repeatX, bool repeatY)
+ {
+ return adoptRef(new Pattern(tileImage, repeatX, repeatY));
+ }
+ virtual ~Pattern();
+
+ Image* tileImage() const { return m_tileImage.get(); }
+
+ PlatformPatternPtr createPlatformPattern(const AffineTransform& patternTransform) const;
+
+ private:
+ Pattern(Image*, bool repeatX, bool repeatY);
+
+ RefPtr<Image> m_tileImage;
+ bool m_repeatX;
+ bool m_repeatY;
+ };
+
+} //namespace
+
+#endif
diff --git a/WebCore/platform/graphics/Pen.cpp b/WebCore/platform/graphics/Pen.cpp
new file mode 100644
index 0000000..a3dcb86
--- /dev/null
+++ b/WebCore/platform/graphics/Pen.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2003 Apple Computer, 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 "Pen.h"
+
+namespace WebCore {
+
+Pen::Pen(const Color &color, unsigned width, PenStyle style) : m_style(style), m_width(width), m_color(color)
+{
+}
+
+const Color &Pen::color() const
+{
+ return m_color;
+}
+
+unsigned Pen::width() const
+{
+ return m_width;
+}
+
+Pen::PenStyle Pen::style() const
+{
+ return m_style;
+}
+
+void Pen::setColor(const Color &color)
+{
+ m_color = color;
+}
+
+void Pen::setWidth(unsigned width)
+{
+ m_width = width;
+}
+
+void Pen::setStyle(PenStyle style)
+{
+ m_style = style;
+}
+
+bool Pen::operator==(const Pen &compareTo) const
+{
+ return (m_width == compareTo.m_width) &&
+ (m_style == compareTo.m_style) &&
+ (m_color == compareTo.m_color);
+}
+
+bool Pen::operator!=(const Pen &compareTo) const
+{
+ return !(*this == compareTo);
+}
+
+}
diff --git a/WebCore/platform/graphics/Pen.h b/WebCore/platform/graphics/Pen.h
new file mode 100644
index 0000000..cb45a2e
--- /dev/null
+++ b/WebCore/platform/graphics/Pen.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2003-6 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Pen_h
+#define Pen_h
+
+#include "Color.h"
+
+#if PLATFORM(WX)
+class wxPen;
+#endif
+
+namespace WebCore {
+
+class Pen {
+public:
+ enum PenStyle {
+ NoPen,
+ SolidLine,
+ DotLine,
+ DashLine
+ };
+
+ Pen(const Color &c = Color::black, unsigned w = 0, PenStyle ps = SolidLine);
+
+ const Color &color() const;
+ unsigned width() const;
+ PenStyle style() const;
+
+ void setColor(const Color &);
+ void setWidth(unsigned);
+ void setStyle(PenStyle);
+
+ bool operator==(const Pen &) const;
+ bool operator!=(const Pen &) const;
+
+#if PLATFORM(WX)
+ Pen(const wxPen&);
+ operator wxPen() const;
+#endif
+
+private:
+ PenStyle m_style;
+ unsigned m_width;
+ Color m_color;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/SegmentedFontData.cpp b/WebCore/platform/graphics/SegmentedFontData.cpp
new file mode 100644
index 0000000..ceefe4f
--- /dev/null
+++ b/WebCore/platform/graphics/SegmentedFontData.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 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 "SegmentedFontData.h"
+
+#include "SimpleFontData.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+SegmentedFontData::~SegmentedFontData()
+{
+}
+
+const SimpleFontData* SegmentedFontData::fontDataForCharacter(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() <= c && it->to() >= c)
+ return it->fontData();
+ }
+ return m_ranges[0].fontData();
+}
+
+bool SegmentedFontData::containsCharacters(const UChar* characters, int length) 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])
+ return true;
+ }
+ return false;
+}
+
+bool SegmentedFontData::isCustomFont() const
+{
+ // All segmented fonts are custom fonts.
+ return true;
+}
+
+bool SegmentedFontData::isLoading() const
+{
+ Vector<FontDataRange>::const_iterator end = m_ranges.end();
+ for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) {
+ if (it->fontData()->isLoading())
+ return true;
+ }
+ return false;
+}
+
+bool SegmentedFontData::isSegmented() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/SegmentedFontData.h b/WebCore/platform/graphics/SegmentedFontData.h
new file mode 100644
index 0000000..1adec15
--- /dev/null
+++ b/WebCore/platform/graphics/SegmentedFontData.h
@@ -0,0 +1,75 @@
+/*
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SegmentedFontData_h
+#define SegmentedFontData_h
+
+#include "FontData.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class SimpleFontData;
+
+struct FontDataRange {
+ FontDataRange(UChar32 from, UChar32 to, const SimpleFontData* fontData)
+ : m_from(from)
+ , m_to(to)
+ , m_fontData(fontData)
+ {
+ }
+
+ UChar32 from() const { return m_from; }
+ UChar32 to() const { return m_to; }
+ const SimpleFontData* fontData() const { return m_fontData; }
+
+private:
+ UChar32 m_from;
+ UChar32 m_to;
+ const SimpleFontData* m_fontData;
+};
+
+class SegmentedFontData : public FontData {
+public:
+ virtual ~SegmentedFontData();
+
+ virtual const SimpleFontData* fontDataForCharacter(UChar32) const;
+ virtual bool containsCharacters(const UChar*, int length) const;
+
+ virtual bool isCustomFont() const;
+ 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]; }
+
+private:
+ Vector<FontDataRange, 1> m_ranges;
+};
+
+} // namespace WebCore
+
+#endif // SegmentedFontData_h
diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp
new file mode 100644
index 0000000..372fcc8
--- /dev/null
+++ b/WebCore/platform/graphics/SimpleFontData.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2005, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include "FontCache.h"
+#if ENABLE(SVG_FONTS)
+#include "SVGFontData.h"
+#include "SVGFontFaceElement.h"
+#endif
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData)
+ : m_font(f)
+ , m_treatAsFixedPitch(false)
+#if ENABLE(SVG_FONTS)
+ , m_svgFontData(svgFontData)
+#endif
+ , m_isCustomFont(customFont)
+ , m_isLoading(loading)
+ , m_smallCapsFontData(0)
+{
+#if ENABLE(SVG_FONTS) && !PLATFORM(QT)
+ if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) {
+ m_unitsPerEm = svgFontFaceElement->unitsPerEm();
+
+ double scale = f.size();
+ if (m_unitsPerEm)
+ scale /= m_unitsPerEm;
+
+ m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale);
+ m_descent = static_cast<int>(svgFontFaceElement->descent() * scale);
+ m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale);
+ m_lineGap = 0.1f * f.size();
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ m_spaceGlyph = 0;
+ m_spaceWidth = 0;
+ m_adjustedSpaceWidth = 0;
+ determinePitch();
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+ return;
+ }
+#endif
+
+ platformInit();
+
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+ if (!glyphPageZero) {
+ LOG_ERROR("Failed to get glyph page zero.");
+ m_spaceGlyph = 0;
+ m_spaceWidth = 0;
+ m_adjustedSpaceWidth = 0;
+ determinePitch();
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+ return;
+ }
+
+ // Nasty hack to determine if we should round or ceil space widths.
+ // If the font is monospace or fake monospace we ceil to ensure that
+ // every character and the space are the same width. Otherwise we round.
+ m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
+ float width = widthForGlyph(m_spaceGlyph);
+ m_spaceWidth = width;
+ determinePitch();
+ m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
+
+ // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
+ // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
+ // See <http://bugs.webkit.org/show_bug.cgi?id=13178>
+ // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
+ // are mapped to the ZERO WIDTH SPACE glyph.
+ Glyph zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph;
+ if (zeroWidthSpaceGlyph) {
+ if (zeroWidthSpaceGlyph != m_spaceGlyph)
+ m_glyphToWidthMap.setWidthForGlyph(zeroWidthSpaceGlyph, 0);
+ else
+ LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width not overridden.");
+ }
+
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+}
+
+SimpleFontData::~SimpleFontData()
+{
+ if (!isCustomFont()) {
+ if (m_smallCapsFontData)
+ FontCache::releaseFontData(m_smallCapsFontData);
+ GlyphPageTreeNode::pruneTreeFontData(this);
+ }
+
+#if ENABLE(SVG_FONTS) && !PLATFORM(QT)
+ if (!m_svgFontData || !m_svgFontData->svgFontFaceElement())
+#endif
+ platformDestroy();
+}
+
+float SimpleFontData::widthForGlyph(Glyph glyph) const
+{
+ float width = m_glyphToWidthMap.widthForGlyph(glyph);
+ if (width != cGlyphWidthUnknown)
+ return width;
+
+ width = platformWidthForGlyph(glyph);
+ m_glyphToWidthMap.setWidthForGlyph(glyph, width);
+
+ return width;
+}
+
+const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
+{
+ return this;
+}
+
+bool SimpleFontData::isSegmented() const
+{
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
new file mode 100644
index 0000000..5f26cbf
--- /dev/null
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -0,0 +1,202 @@
+/*
+ * This file is part of the internal font implementation.
+ *
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SimpleFontData_h
+#define SimpleFontData_h
+
+#include "FontData.h"
+#include "FontPlatformData.h"
+#include "GlyphPageTreeNode.h"
+#include "GlyphWidthMap.h"
+#include <wtf/OwnPtr.h>
+
+#if USE(ATSUI)
+typedef struct OpaqueATSUStyle* ATSUStyle;
+#endif
+
+#if PLATFORM(WIN)
+#include <usp10.h>
+#endif
+
+#if PLATFORM(CAIRO)
+#include <cairo.h>
+#endif
+
+namespace WebCore {
+
+class FontDescription;
+class FontPlatformData;
+class SharedBuffer;
+class SVGFontData;
+class WidthMap;
+
+enum Pitch { UnknownPitch, FixedPitch, VariablePitch };
+
+class SimpleFontData : public FontData {
+public:
+ SimpleFontData(const FontPlatformData&, bool customFont = false, bool loading = false, SVGFontData* data = 0);
+ virtual ~SimpleFontData();
+
+public:
+ const FontPlatformData& platformData() const { return m_font; }
+ SimpleFontData* smallCapsFontData(const FontDescription& fontDescription) const;
+
+ // vertical metrics
+ int ascent() const { return m_ascent; }
+ int descent() const { return m_descent; }
+ int lineSpacing() const { return m_lineSpacing; }
+ int lineGap() const { return m_lineGap; }
+ float xHeight() const { return m_xHeight; }
+ unsigned unitsPerEm() const { return m_unitsPerEm; }
+
+ float widthForGlyph(Glyph) const;
+ float platformWidthForGlyph(Glyph) const;
+
+ virtual const SimpleFontData* fontDataForCharacter(UChar32) const;
+ virtual bool containsCharacters(const UChar*, int length) const;
+
+ void determinePitch();
+ Pitch pitch() const { return m_treatAsFixedPitch ? FixedPitch : VariablePitch; }
+
+#if ENABLE(SVG_FONTS)
+ SVGFontData* svgFontData() const { return m_svgFontData.get(); }
+ bool isSVGFont() const { return m_svgFontData; }
+#else
+ bool isSVGFont() const { return false; }
+#endif
+
+ virtual bool isCustomFont() const { return m_isCustomFont; }
+ virtual bool isLoading() const { return m_isLoading; }
+ virtual bool isSegmented() const;
+
+ const GlyphData& missingGlyphData() const { return m_missingGlyphData; }
+
+#if PLATFORM(MAC)
+ NSFont* getNSFont() const { return m_font.font(); }
+#endif
+
+#if USE(CORE_TEXT)
+ CTFontRef getCTFont() const;
+ CFDictionaryRef getCFStringAttributes() const;
+#endif
+
+#if USE(ATSUI)
+ void checkShapesArabic() const;
+ bool shapesArabic() const
+ {
+ if (!m_checkedShapesArabic)
+ checkShapesArabic();
+ return m_shapesArabic;
+ }
+#endif
+
+#if PLATFORM(WIN)
+ bool isSystemFont() const { return m_isSystemFont; }
+ SCRIPT_FONTPROPERTIES* scriptFontProperties() const;
+ SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; }
+
+ static void setShouldApplyMacAscentHack(bool);
+ static bool shouldApplyMacAscentHack();
+#endif
+
+#if PLATFORM(CAIRO)
+ void setFont(cairo_t*) const;
+#endif
+
+#if PLATFORM(WX)
+ wxFont getWxFont() const { return m_font.font(); }
+#endif
+
+private:
+ void platformInit();
+ void platformDestroy();
+
+ void commonInit();
+
+#if PLATFORM(WIN)
+ void initGDIFont();
+ void platformCommonDestroy();
+ float widthForGDIGlyph(Glyph glyph) const;
+#endif
+
+public:
+ int m_ascent;
+ int m_descent;
+ int m_lineSpacing;
+ int m_lineGap;
+ float m_xHeight;
+ unsigned m_unitsPerEm;
+
+ FontPlatformData m_font;
+
+ mutable GlyphWidthMap m_glyphToWidthMap;
+
+ bool m_treatAsFixedPitch;
+
+#if ENABLE(SVG_FONTS)
+ OwnPtr<SVGFontData> m_svgFontData;
+#endif
+
+ bool m_isCustomFont; // Whether or not we are custom font loaded via @font-face
+ bool m_isLoading; // Whether or not this custom font is still in the act of loading.
+
+ Glyph m_spaceGlyph;
+ float m_spaceWidth;
+ float m_adjustedSpaceWidth;
+
+ GlyphData m_missingGlyphData;
+
+ mutable SimpleFontData* m_smallCapsFontData;
+
+#if PLATFORM(CG) || PLATFORM(WIN)
+ float m_syntheticBoldOffset;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef BUILDING_ON_TIGER
+ void* m_styleGroup;
+#endif
+#endif
+
+#if USE(ATSUI)
+ mutable ATSUStyle m_ATSUStyle;
+ mutable bool m_ATSUStyleInitialized;
+ mutable bool m_ATSUMirrors;
+ mutable bool m_checkedShapesArabic;
+ mutable bool m_shapesArabic;
+#endif
+
+#if USE(CORE_TEXT)
+ mutable RetainPtr<CTFontRef> m_CTFont;
+ mutable RetainPtr<CFDictionaryRef> m_CFStringAttributes;
+#endif
+
+#if PLATFORM(WIN)
+ bool m_isSystemFont;
+ mutable SCRIPT_CACHE m_scriptCache;
+ mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // SimpleFontData_h
diff --git a/WebCore/platform/graphics/StringTruncator.cpp b/WebCore/platform/graphics/StringTruncator.cpp
new file mode 100644
index 0000000..b6c86ce
--- /dev/null
+++ b/WebCore/platform/graphics/StringTruncator.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StringTruncator.h"
+
+#include "CharacterNames.h"
+#include "Font.h"
+#include "TextBreakIterator.h"
+#include <wtf/Assertions.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+#define STRING_BUFFER_SIZE 2048
+
+typedef unsigned TruncationFunction(const String&, unsigned length, unsigned keepCount, UChar* buffer);
+
+static inline int textBreakAtOrPreceding(TextBreakIterator* it, int offset)
+{
+ if (isTextBreak(it, offset))
+ return offset;
+
+ int result = textBreakPreceding(it, offset);
+ return result == TextBreakDone ? 0 : result;
+}
+
+static inline int boundedTextBreakFollowing(TextBreakIterator* it, int offset, int length)
+{
+ int result = textBreakFollowing(it, offset);
+ return result == TextBreakDone ? length : result;
+}
+
+static unsigned centerTruncateToBuffer(const String& string, unsigned length, unsigned keepCount, UChar* buffer)
+{
+ ASSERT(keepCount < length);
+ ASSERT(keepCount < STRING_BUFFER_SIZE);
+
+ unsigned omitStart = (keepCount + 1) / 2;
+ TextBreakIterator* it = characterBreakIterator(string.characters(), length);
+ unsigned omitEnd = boundedTextBreakFollowing(it, omitStart + (length - keepCount) - 1, length);
+ omitStart = textBreakAtOrPreceding(it, omitStart);
+
+ unsigned truncatedLength = omitStart + 1 + (length - omitEnd);
+ ASSERT(truncatedLength <= length);
+
+ memcpy(buffer, string.characters(), sizeof(UChar) * omitStart);
+ buffer[omitStart] = horizontalEllipsis;
+ memcpy(&buffer[omitStart + 1], &string.characters()[omitEnd], sizeof(UChar) * (length - omitEnd));
+
+ return truncatedLength;
+}
+
+static unsigned rightTruncateToBuffer(const String& string, unsigned length, unsigned keepCount, UChar* buffer)
+{
+ ASSERT(keepCount < length);
+ ASSERT(keepCount < STRING_BUFFER_SIZE);
+
+ TextBreakIterator* it = characterBreakIterator(string.characters(), length);
+ unsigned keepLength = textBreakAtOrPreceding(it, keepCount);
+ unsigned truncatedLength = keepLength + 1;
+
+ memcpy(buffer, string.characters(), sizeof(UChar) * keepLength);
+ buffer[keepLength] = horizontalEllipsis;
+
+ return truncatedLength;
+}
+
+static float stringWidth(const Font& renderer, const UChar* characters, unsigned length, bool disableRoundingHacks)
+{
+ TextRun run(characters, length);
+ if (disableRoundingHacks)
+ run.disableRoundingHacks();
+ return renderer.floatWidth(run);
+}
+
+static String truncateString(const String& string, float maxWidth, const Font& font, TruncationFunction truncateToBuffer, bool disableRoundingHacks)
+{
+ if (string.isEmpty())
+ return string;
+
+ ASSERT(maxWidth >= 0);
+
+ float currentEllipsisWidth = stringWidth(font, &horizontalEllipsis, 1, disableRoundingHacks);
+
+ UChar stringBuffer[STRING_BUFFER_SIZE];
+ unsigned truncatedLength;
+ unsigned keepCount;
+ unsigned length = string.length();
+
+ if (length > STRING_BUFFER_SIZE) {
+ keepCount = STRING_BUFFER_SIZE - 1; // need 1 character for the ellipsis
+ truncatedLength = centerTruncateToBuffer(string, length, keepCount, stringBuffer);
+ } else {
+ keepCount = length;
+ memcpy(stringBuffer, string.characters(), sizeof(UChar) * length);
+ truncatedLength = length;
+ }
+
+ float width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks);
+ if (width <= maxWidth)
+ return string;
+
+ unsigned keepCountForLargestKnownToFit = 0;
+ float widthForLargestKnownToFit = currentEllipsisWidth;
+
+ unsigned keepCountForSmallestKnownToNotFit = keepCount;
+ float widthForSmallestKnownToNotFit = width;
+
+ if (currentEllipsisWidth >= maxWidth) {
+ keepCountForLargestKnownToFit = 1;
+ keepCountForSmallestKnownToNotFit = 2;
+ }
+
+ while (keepCountForLargestKnownToFit + 1 < keepCountForSmallestKnownToNotFit) {
+ ASSERT(widthForLargestKnownToFit <= maxWidth);
+ ASSERT(widthForSmallestKnownToNotFit > maxWidth);
+
+ float ratio = (keepCountForSmallestKnownToNotFit - keepCountForLargestKnownToFit)
+ / (widthForSmallestKnownToNotFit - widthForLargestKnownToFit);
+ keepCount = static_cast<unsigned>(maxWidth * ratio);
+
+ if (keepCount <= keepCountForLargestKnownToFit) {
+ keepCount = keepCountForLargestKnownToFit + 1;
+ } else if (keepCount >= keepCountForSmallestKnownToNotFit) {
+ keepCount = keepCountForSmallestKnownToNotFit - 1;
+ }
+
+ ASSERT(keepCount < length);
+ ASSERT(keepCount > 0);
+ ASSERT(keepCount < keepCountForSmallestKnownToNotFit);
+ ASSERT(keepCount > keepCountForLargestKnownToFit);
+
+ truncatedLength = truncateToBuffer(string, length, keepCount, stringBuffer);
+
+ width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks);
+ if (width <= maxWidth) {
+ keepCountForLargestKnownToFit = keepCount;
+ widthForLargestKnownToFit = width;
+ } else {
+ keepCountForSmallestKnownToNotFit = keepCount;
+ widthForSmallestKnownToNotFit = width;
+ }
+ }
+
+ if (keepCountForLargestKnownToFit == 0) {
+ keepCountForLargestKnownToFit = 1;
+ }
+
+ if (keepCount != keepCountForLargestKnownToFit) {
+ keepCount = keepCountForLargestKnownToFit;
+ truncatedLength = truncateToBuffer(string, length, keepCount, stringBuffer);
+ }
+
+ return String(stringBuffer, truncatedLength);
+}
+
+String StringTruncator::centerTruncate(const String& string, float maxWidth, const Font& font, bool disableRoundingHacks)
+{
+ return truncateString(string, maxWidth, font, centerTruncateToBuffer, disableRoundingHacks);
+}
+
+String StringTruncator::rightTruncate(const String& string, float maxWidth, const Font& font, bool disableRoundingHacks)
+{
+ return truncateString(string, maxWidth, font, rightTruncateToBuffer, disableRoundingHacks);
+}
+
+float StringTruncator::width(const String& string, const Font& font, bool disableRoundingHacks)
+{
+ return stringWidth(font, string.characters(), string.length(), disableRoundingHacks);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/StringTruncator.h b/WebCore/platform/graphics/StringTruncator.h
new file mode 100644
index 0000000..0a8532b
--- /dev/null
+++ b/WebCore/platform/graphics/StringTruncator.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StringTruncator_h
+#define StringTruncator_h
+
+namespace WebCore {
+
+ class Font;
+ class String;
+
+ class StringTruncator {
+ public:
+ static String centerTruncate(const String&, float maxWidth, const Font&, bool disableRoundingHacks = true);
+ static String rightTruncate(const String&, float maxWidth, const Font&, bool disableRoundingHacks = true);
+ static float width(const String&, const Font&, bool disableRoundingHacks = true);
+ };
+
+} // namespace WebCore
+
+#endif // !defined(StringTruncator_h)
diff --git a/WebCore/platform/graphics/TextRun.h b/WebCore/platform/graphics/TextRun.h
new file mode 100644
index 0000000..166b047
--- /dev/null
+++ b/WebCore/platform/graphics/TextRun.h
@@ -0,0 +1,126 @@
+/*
+ * 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, 2006, 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TextRun_h
+#define TextRun_h
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class RenderObject;
+class SVGPaintServer;
+
+class TextRun {
+public:
+ TextRun(const UChar* c, int len, bool allowTabs = false, int xpos = 0, int padding = 0, bool rtl = false, bool directionalOverride = false,
+ bool applyRunRounding = true, bool applyWordRounding = true)
+ : m_characters(c)
+ , m_len(len)
+ , m_xpos(xpos)
+ , m_padding(padding)
+ , m_allowTabs(allowTabs)
+ , m_rtl(rtl)
+ , m_directionalOverride(directionalOverride)
+ , m_applyRunRounding(applyRunRounding)
+ , m_applyWordRounding(applyWordRounding)
+ , m_disableSpacing(false)
+#if ENABLE(SVG_FONTS)
+ , m_referencingRenderObject(0)
+ , m_activePaintServer(0)
+#endif
+ {
+ }
+
+ TextRun(const String& s, bool allowTabs = false, int xpos = 0, int padding = 0, bool rtl = false, bool directionalOverride = false,
+ bool applyRunRounding = true, bool applyWordRounding = true)
+ : m_characters(s.characters())
+ , m_len(s.length())
+ , m_xpos(xpos)
+ , m_padding(padding)
+ , m_allowTabs(allowTabs)
+ , m_rtl(rtl)
+ , m_directionalOverride(directionalOverride)
+ , m_applyRunRounding(applyRunRounding)
+ , m_applyWordRounding(applyWordRounding)
+ , m_disableSpacing(false)
+#if ENABLE(SVG_FONTS)
+ , m_referencingRenderObject(0)
+ , m_activePaintServer(0)
+#endif
+ {
+ }
+
+ UChar operator[](int i) const { return m_characters[i]; }
+ const UChar* data(int i) const { return &m_characters[i]; }
+
+ const UChar* characters() const { return m_characters; }
+ int length() const { return m_len; }
+
+ void setText(const UChar* c, int len) { m_characters = c; m_len = len; }
+
+ bool allowTabs() const { return m_allowTabs; }
+ int xPos() const { return m_xpos; }
+ int padding() const { return m_padding; }
+ bool rtl() const { return m_rtl; }
+ bool ltr() const { return !m_rtl; }
+ bool directionalOverride() const { return m_directionalOverride; }
+ bool applyRunRounding() const { return m_applyRunRounding; }
+ bool applyWordRounding() const { return m_applyWordRounding; }
+ bool spacingDisabled() const { return m_disableSpacing; }
+
+ void disableSpacing() { m_disableSpacing = true; }
+ void disableRoundingHacks() { m_applyRunRounding = m_applyWordRounding = false; }
+ void setRTL(bool b) { m_rtl = b; }
+ void setDirectionalOverride(bool override) { m_directionalOverride = override; }
+
+#if ENABLE(SVG_FONTS)
+ RenderObject* referencingRenderObject() const { return m_referencingRenderObject; }
+ void setReferencingRenderObject(RenderObject* object) { m_referencingRenderObject = object; }
+
+ SVGPaintServer* activePaintServer() const { return m_activePaintServer; }
+ void setActivePaintServer(SVGPaintServer* object) { m_activePaintServer = object; }
+#endif
+
+private:
+ const UChar* m_characters;
+ int m_len;
+
+ int m_xpos;
+ int m_padding;
+ bool m_allowTabs;
+ bool m_rtl;
+ bool m_directionalOverride;
+ bool m_applyRunRounding;
+ bool m_applyWordRounding;
+ bool m_disableSpacing;
+
+#if ENABLE(SVG_FONTS)
+ RenderObject* m_referencingRenderObject;
+ SVGPaintServer* m_activePaintServer;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/UnitBezier.h b/WebCore/platform/graphics/UnitBezier.h
new file mode 100644
index 0000000..973d75b
--- /dev/null
+++ b/WebCore/platform/graphics/UnitBezier.h
@@ -0,0 +1,123 @@
+/*
+ * 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 UnitBezier_h
+#define UnitBezier_h
+
+#include <math.h>
+
+namespace WebCore {
+
+ struct UnitBezier {
+ UnitBezier(double p1x, double p1y, double p2x, double p2y)
+ {
+ // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
+ cx = 3.0 * p1x;
+ bx = 3.0 * (p2x - p1x) - cx;
+ ax = 1.0 - cx -bx;
+
+ cy = 3.0 * p1y;
+ by = 3.0 * (p2y - p1y) - cy;
+ ay = 1.0 - cy - by;
+ }
+
+ double sampleCurveX(double t)
+ {
+ // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
+ return ((ax * t + bx) * t + cx) * t;
+ }
+
+ double sampleCurveY(double t)
+ {
+ return ((ay * t + by) * t + cy) * t;
+ }
+
+ double sampleCurveDerivativeX(double t)
+ {
+ return (3.0 * ax * t + 2.0 * bx) * t + cx;
+ }
+
+ // Given an x value, find a parametric value it came from.
+ double solveCurveX(double x, double epsilon)
+ {
+ double t0;
+ double t1;
+ double t2;
+ double x2;
+ double d2;
+ int i;
+
+ // First try a few iterations of Newton's method -- normally very fast.
+ for (t2 = x, i = 0; i < 8; i++) {
+ x2 = sampleCurveX(t2) - x;
+ if (fabs (x2) < epsilon)
+ return t2;
+ d2 = sampleCurveDerivativeX(t2);
+ if (fabs(d2) < 1e-6)
+ break;
+ t2 = t2 - x2 / d2;
+ }
+
+ // Fall back to the bisection method for reliability.
+ t0 = 0.0;
+ t1 = 1.0;
+ t2 = x;
+
+ if (t2 < t0)
+ return t0;
+ if (t2 > t1)
+ return t1;
+
+ while (t0 < t1) {
+ x2 = sampleCurveX(t2);
+ if (fabs(x2 - x) < epsilon)
+ return t2;
+ if (x > x2)
+ t0 = t2;
+ else
+ t1 = t2;
+ t2 = (t1 - t0) * .5 + t0;
+ }
+
+ // Failure.
+ return t2;
+ }
+
+ double solve(double x, double epsilon)
+ {
+ return sampleCurveY(solveCurveX(x, epsilon));
+ }
+
+ private:
+ double ax;
+ double bx;
+ double cx;
+
+ double ay;
+ double by;
+ double cy;
+ };
+}
+#endif
diff --git a/WebCore/platform/graphics/WidthIterator.cpp b/WebCore/platform/graphics/WidthIterator.cpp
new file mode 100644
index 0000000..a16d739
--- /dev/null
+++ b/WebCore/platform/graphics/WidthIterator.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * 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 "WidthIterator.h"
+
+#include "Font.h"
+#include "GlyphBuffer.h"
+#include "SimpleFontData.h"
+#include <wtf/MathExtras.h>
+
+#if USE(ICU_UNICODE)
+#include <unicode/unorm.h>
+#endif
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+// According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
+static const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
+
+WidthIterator::WidthIterator(const Font* font, const TextRun& run)
+ : m_font(font)
+ , m_run(run)
+ , m_end(run.length())
+ , m_currentCharacter(0)
+ , m_runWidthSoFar(0)
+ , m_finalRoundingWidth(0)
+{
+ // If the padding is non-zero, count the number of spaces in the run
+ // and divide that by the padding for per space addition.
+ m_padding = m_run.padding();
+ if (!m_padding)
+ m_padPerSpace = 0;
+ else {
+ float numSpaces = 0;
+ for (int i = 0; i < run.length(); i++)
+ if (Font::treatAsSpace(m_run[i]))
+ numSpaces++;
+
+ if (numSpaces == 0)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = ceilf(m_run.padding() / numSpaces);
+ }
+}
+
+void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
+{
+ if (offset > m_end)
+ offset = m_end;
+
+ int currentCharacter = m_currentCharacter;
+ const UChar* cp = m_run.data(currentCharacter);
+
+ bool rtl = m_run.rtl();
+ bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_padding) && !m_run.spacingDisabled();
+
+ float runWidthSoFar = m_runWidthSoFar;
+ float lastRoundingWidth = m_finalRoundingWidth;
+
+ while (currentCharacter < offset) {
+ UChar32 c = *cp;
+ unsigned clusterLength = 1;
+ if (c >= 0x3041) {
+ if (c <= 0x30FE) {
+ // Deal with Hiragana and Katakana voiced and semi-voiced syllables.
+ // Normalize into composed form, and then look for glyph with base + combined mark.
+ // Check above for character range to minimize performance impact.
+ UChar32 normalized = normalizeVoicingMarks(currentCharacter);
+ if (normalized) {
+ c = normalized;
+ clusterLength = 2;
+ }
+ } else if (U16_IS_SURROGATE(c)) {
+ if (!U16_IS_SURROGATE_LEAD(c))
+ break;
+
+ // Do we have a surrogate pair? If so, determine the full Unicode (32 bit)
+ // code point before glyph lookup.
+ // Make sure we have another character and it's a low surrogate.
+ if (currentCharacter + 1 >= m_run.length())
+ break;
+ UChar low = cp[1];
+ if (!U16_IS_TRAIL(low))
+ break;
+ c = U16_GET_SUPPLEMENTARY(c, low);
+ clusterLength = 2;
+ }
+ }
+
+ const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl);
+ Glyph glyph = glyphData.glyph;
+ const SimpleFontData* fontData = glyphData.fontData;
+
+ ASSERT(fontData);
+
+ // Now that we have a glyph and font data, get its width.
+ float width;
+ if (c == '\t' && m_run.allowTabs()) {
+ float tabWidth = m_font->tabWidth();
+ width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth);
+ } else {
+ width = fontData->widthForGlyph(glyph);
+ // We special case spaces in two ways when applying word rounding.
+ // First, we round spaces to an adjusted width in all fonts.
+ // Second, in fixed-pitch fonts we ensure that all characters that
+ // match the width of the space character have the same width as the space character.
+ if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) {
+ width = fontData->m_adjustedSpaceWidth;
+ }
+ }
+
+ if (hasExtraSpacing) {
+ // Account for letter-spacing.
+ if (width && m_font->letterSpacing()) {
+ width += m_font->letterSpacing();
+ }
+
+ if (Font::treatAsSpace(c)) {
+ // Account for padding. WebCore uses space padding to justify text.
+ // We distribute the specified padding over the available spaces in the run.
+ if (m_padding) {
+ // Use left over padding if not evenly divisible by number of spaces.
+ if (m_padding < m_padPerSpace) {
+ width += m_padding;
+ m_padding = 0;
+ } else {
+ width += m_padPerSpace;
+ m_padding -= m_padPerSpace;
+ }
+ }
+
+ // Account for word spacing.
+ // We apply additional space between "words" by adding width to the space character.
+ if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) {
+ width += m_font->wordSpacing();
+ }
+ }
+ }
+
+ // Advance past the character we just dealt with.
+ cp += clusterLength;
+ currentCharacter += clusterLength;
+
+ // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters
+ // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
+ // We adjust the width of the last character of a "word" to ensure an integer width.
+ // If we move KHTML to floats we can remove this (and related) hacks.
+
+ float oldWidth = width;
+
+ // Force characters that are used to determine word boundaries for the rounding hack
+ // to be integer width, so following words will start on an integer boundary.
+ if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) {
+ width = ceilf(width);
+ }
+
+ // Check to see if the next character is a "rounding hack character", if so, adjust
+ // width so that the total run width will be on an integer boundary.
+ if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp))
+ || (m_run.applyRunRounding() && currentCharacter >= m_end)) {
+ float totalWidth = runWidthSoFar + width;
+ width += ceilf(totalWidth) - totalWidth;
+ }
+
+ runWidthSoFar += width;
+
+ if (glyphBuffer)
+ glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width));
+
+ lastRoundingWidth = width - oldWidth;
+ }
+
+ m_currentCharacter = currentCharacter;
+ m_runWidthSoFar = runWidthSoFar;
+ m_finalRoundingWidth = lastRoundingWidth;
+}
+
+bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer)
+{
+ glyphBuffer->clear();
+ advance(m_currentCharacter + 1, glyphBuffer);
+ float w = 0;
+ for (int i = 0; i < glyphBuffer->size(); ++i)
+ w += glyphBuffer->advanceAt(i);
+ width = w;
+ return !glyphBuffer->isEmpty();
+}
+
+UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter)
+{
+ if (currentCharacter + 1 < m_end) {
+ if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoicingMarksCombiningClass) {
+#if USE(ICU_UNICODE)
+ // Normalize into composed form using 3.2 rules.
+ UChar normalizedCharacters[2] = { 0, 0 };
+ UErrorCode uStatus = U_ZERO_ERROR;
+ int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2,
+ UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus);
+ if (resultLength == 1 && uStatus == 0)
+ return normalizedCharacters[0];
+#elif USE(QT4_UNICODE)
+ QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharacter)), 2);
+ QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Unicode_3_2);
+ if (res.length() == 1)
+ return res.at(0).unicode();
+#endif
+ }
+ }
+ return 0;
+}
+
+}
diff --git a/WebCore/platform/graphics/WidthIterator.h b/WebCore/platform/graphics/WidthIterator.h
new file mode 100644
index 0000000..5706d1e
--- /dev/null
+++ b/WebCore/platform/graphics/WidthIterator.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * 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.
+ *
+ */
+
+#ifndef WidthIterator_h
+#define WidthIterator_h
+
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class Font;
+class GlyphBuffer;
+class TextRun;
+
+struct WidthIterator {
+ WidthIterator(const Font*, const TextRun&);
+
+ void advance(int to, GlyphBuffer* = 0);
+ bool advanceOneCharacter(float& width, GlyphBuffer* = 0);
+
+ const Font* m_font;
+
+ const TextRun& m_run;
+ int m_end;
+
+ unsigned m_currentCharacter;
+ float m_runWidthSoFar;
+ float m_padding;
+ float m_padPerSpace;
+ float m_finalRoundingWidth;
+
+private:
+ UChar32 normalizeVoicingMarks(int currentCharacter);
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
new file mode 100644
index 0000000..c01d078
--- /dev/null
+++ b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "AffineTransform.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include "android_graphics.h"
+
+namespace WebCore {
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+AffineTransform::AffineTransform()
+{
+ m_transform.reset();
+}
+
+AffineTransform::AffineTransform(const SkMatrix& mat) : m_transform(mat) {}
+
+AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+{
+ m_transform.reset();
+
+ m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
+
+ m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
+}
+
+void AffineTransform::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));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
+
+ m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
+}
+
+void AffineTransform::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);
+
+ *x2 = SkScalarToDouble(dst.fX);
+ *y2 = SkScalarToDouble(dst.fY);
+}
+
+IntRect AffineTransform::mapRect(const IntRect &rect) const
+{
+ SkRect src, dst;
+ SkIRect ir;
+
+ android_setrect(&src, rect);
+ m_transform.mapRect(&dst, src);
+ dst.round(&ir);
+
+ return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+{
+ SkRect src, dst;
+ SkIRect ir;
+
+ android_setrect(&src, rect);
+ m_transform.mapRect(&dst, src);
+ dst.round(&ir);
+
+ return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
+}
+
+bool AffineTransform::isIdentity() const
+{
+ return m_transform.isIdentity();
+}
+
+void AffineTransform::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 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));
+ }
+
+AffineTransform &AffineTransform::scale(double sx, double sy)
+{
+ m_transform.preScale(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
+ return *this;
+}
+
+AffineTransform &AffineTransform::rotate(double d)
+{
+ m_transform.preRotate(SkDoubleToScalar(d));
+ return *this;
+}
+
+AffineTransform &AffineTransform::translate(double tx, double ty)
+{
+ m_transform.preTranslate(SkDoubleToScalar(tx), SkDoubleToScalar(ty));
+ return *this;
+}
+
+AffineTransform &AffineTransform::shear(double sx, double sy)
+{
+ m_transform.preSkew(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
+ return *this;
+}
+
+double AffineTransform::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
+{
+ AffineTransform inverse;
+
+ m_transform.invert(&inverse.m_transform);
+
+ return inverse;
+}
+
+AffineTransform::operator SkMatrix() const
+{
+ return m_transform;
+}
+
+bool AffineTransform::operator==(const AffineTransform &m2) const
+{
+ return m_transform == m2.m_transform;
+}
+
+AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+{
+ m_transform.setConcat(m2.m_transform, m_transform);
+ return *this;
+}
+
+AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+{
+ AffineTransform cat;
+
+ cat.m_transform.setConcat(m2.m_transform, m_transform);
+ return cat;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp
new file mode 100644
index 0000000..54a1a08
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontAndroid.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2006 Apple Computer, 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 "Font.h"
+
+#include "FontData.h"
+#include "FontFallbackList.h"
+#include "GraphicsContext.h"
+#include "GlyphBuffer.h"
+#include "PlatformGraphicsContext.h"
+#include "IntRect.h"
+
+#include "SkCanvas.h"
+#include "SkLayerDrawLooper.h"
+#include "SkPaint.h"
+#include "SkTemplates.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+static void updateForFont(SkPaint* paint, const SimpleFontData* font) {
+ font->platformData().setupPaint(paint);
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+}
+
+static SkPaint* setupFill(SkPaint* paint, GraphicsContext* gc,
+ const SimpleFontData* font) {
+ gc->setupFillPaint(paint);
+ updateForFont(paint, font);
+ return paint;
+}
+
+static SkPaint* setupStroke(SkPaint* paint, GraphicsContext* gc,
+ const SimpleFontData* font) {
+ gc->setupStrokePaint(paint);
+ updateForFont(paint, font);
+ return paint;
+}
+
+static bool setupForText(SkPaint* paint, GraphicsContext* gc,
+ const SimpleFontData* font) {
+ int mode = gc->textDrawingMode();
+
+ if ((mode & (cTextFill | cTextStroke)) == (cTextFill | cTextStroke)) {
+ SkLayerDrawLooper* looper = new SkLayerDrawLooper;
+ paint->setLooper(looper)->unref();
+
+ // we clear the looper, in case we have a shadow
+
+ SkPaint* fillP = NULL;
+ SkPaint* strokeP = NULL;
+ if (gc->willStroke()) {
+ strokeP = setupStroke(looper->addLayer(), gc, font);
+ strokeP->setLooper(NULL);
+ }
+ if (gc->willFill()) {
+ fillP = setupFill(looper->addLayer(), gc, font);
+ fillP->setLooper(NULL);
+ }
+
+ SkPaint shadowPaint;
+ SkPoint offset;
+ if (gc->setupShadowPaint(&shadowPaint, &offset)) {
+ SkPaint* p = looper->addLayer(offset.fX, offset.fY);
+ *p = shadowPaint;
+ if (strokeP && !fillP) {
+ // stroke the shadow if we have stroke but no fill
+ p->setStyle(SkPaint::kStroke_Style);
+ p->setStrokeWidth(strokeP->getStrokeWidth());
+ }
+ updateForFont(p, font);
+ }
+ } else if (mode & cTextFill) {
+ (void)setupFill(paint, gc, font);
+ } else if (mode & cTextStroke) {
+ (void)setupStroke(paint, gc, font);
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
+ const FloatPoint& point) const {
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+
+ SkPaint paint;
+ if (!setupForText(&paint, gc, font)) {
+ return;
+ }
+
+ SkScalar x = SkFloatToScalar(point.x());
+ SkScalar y = SkFloatToScalar(point.y());
+ const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
+ const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
+ SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
+ SkPoint* pos = storage.get();
+
+ /* We need an array of [x,y,x,y,x,y,...], but webkit is giving us
+ point.xy + [width, height, width, height, ...], so we have to convert
+ */
+ for (int i = 0; i < numGlyphs; i++) {
+ pos[i].set(x, y);
+ x += SkFloatToScalar(adv[i].width());
+ y += SkFloatToScalar(adv[i].height());
+ }
+
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
+ canvas->drawPosText(glyphs, numGlyphs * sizeof(*glyphs), pos, paint);
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int, int) const
+{
+ SkPaint paint;
+ SkScalar width, left;
+ SkPaint::FontMetrics metrics;
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+ width = paint.measureText(run.characters(), run.length() << 1);
+ SkScalar spacing = paint.getFontMetrics(&metrics);
+
+ return FloatRect(point.x(),
+ point.y() - floorf(SkScalarToFloat(-metrics.fAscent)),
+ roundf(SkScalarToFloat(width)),
+ roundf(SkScalarToFloat(spacing)));
+}
+
+void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, FloatPoint const& point, int, int) const
+{
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
+ SkPaint paint;
+
+ if (!setupForText(&paint, gc, primaryFont())) {
+ return;
+ }
+
+ // go to chars, instead of glyphs, which was set by setupForText()
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ canvas->drawText(run.characters(), run.length() << 1,
+ SkFloatToScalar(point.x()), SkFloatToScalar(point.y()),
+ paint);
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ SkPaint paint;
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+//printf("--------- complext measure %d chars\n", run.to() - run.from());
+
+ SkScalar width = paint.measureText(run.characters(), run.length() << 1);
+ return SkScalarToFloat(width);
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ SkPaint paint;
+ int count = run.length();
+ SkAutoSTMalloc<64, SkScalar> storage(count);
+ SkScalar* widths = storage.get();
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+ count = paint.getTextWidths(run.characters(), count << 1, widths);
+
+ if (count > 0)
+ {
+ SkScalar pos = 0;
+ for (int i = 0; i < count; i++)
+ {
+ if (x < SkScalarRound(pos + SkScalarHalf(widths[i])))
+ return i;
+ pos += widths[i];
+ }
+ }
+ return count;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
new file mode 100644
index 0000000..c257348
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2006 Apple Computer, 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 "FontCache.h"
+#include "FontPlatformData.h"
+#include "Font.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)
+{
+ // since all of our fonts logically map to the fallback, we can always claim
+ // that each font supports all characters.
+ return font.primaryFont();
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& font)
+{
+ static AtomicString str("sans-serif");
+ return getCachedFontPlatformData(font, str);
+}
+
+static char* AtomicStringToUTF8String(const AtomicString& utf16)
+{
+ SkASSERT(sizeof(uint16_t) == sizeof(utf16.characters()[0]));
+ const uint16_t* uni = (uint16_t*)utf16.characters();
+
+ size_t bytes = SkUTF16_ToUTF8(uni, utf16.length(), NULL);
+ char* utf8 = (char*)sk_malloc_throw(bytes + 1);
+
+ (void)SkUTF16_ToUTF8(uni, utf16.length(), utf8);
+ utf8[bytes] = 0;
+ return utf8;
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ char* storage = 0;
+ const char* name = 0;
+
+ if (family.length() == 0) {
+ static const struct {
+ FontDescription::GenericFamilyType mType;
+ const char* mName;
+ } gNames[] = {
+ { 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(gNames); i++)
+ {
+ if (type == gNames[i].mType)
+ {
+ name = gNames[i].mName;
+ break;
+ }
+ }
+ // if we fall out of the loop, its ok for name to still be 0
+ }
+ else { // convert the name to utf8
+ storage = AtomicStringToUTF8String(family);
+ name = storage;
+ }
+
+ int style = SkTypeface::kNormal;
+ if (fontDescription.weight() >= FontWeightBold)
+ style |= SkTypeface::kBold;
+ if (fontDescription.italic())
+ style |= SkTypeface::kItalic;
+
+ SkTypeface* tf = SkTypeface::Create(name, (SkTypeface::Style)style);
+
+ FontPlatformData* result = new FontPlatformData(tf,
+ fontDescription.computedSize(),
+ (style & SkTypeface::kBold) && !tf->isBold(),
+ (style & SkTypeface::kItalic) && !tf->isItalic());
+ tf->unref();
+ sk_free(storage);
+ return result;
+}
+
+ // new as of SVN change 36269, Sept 8, 2008
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ // Don't understand this yet, but it seems safe to leave unimplemented
+}
+
+}
+
diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..eb1933c
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "FontCustomPlatformData.h"
+
+#include "SkTypeface.h"
+#include "SkStream.h"
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+namespace WebCore {
+
+FontCustomPlatformData::FontCustomPlatformData(SkTypeface* face)
+{
+ face->safeRef();
+ m_typeface = face;
+}
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ m_typeface->safeUnref();
+ // the unref is enough to release the font data...
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic,
+ FontRenderingMode mode)
+{
+ // turn bold/italic into fakeBold/fakeItalic
+ if (m_typeface != NULL) {
+ if (m_typeface->isBold() == bold)
+ bold = false;
+ if (m_typeface->isItalic() == italic)
+ italic = false;
+ }
+ return FontPlatformData(m_typeface, size, bold, italic);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ // pass true until we know how we can share the data, and not have to
+ // make a copy of it.
+ SkStream* stream = new SkMemoryStream(buffer->data(), buffer->size(), true);
+ SkTypeface* face = SkTypeface::CreateFromStream(stream);
+ if (NULL == face) {
+ SkDebugf("--------- SkTypeface::CreateFromBuffer failed %d\n",
+ buffer->size());
+ return NULL;
+ }
+
+ SkAutoUnref aur(face);
+
+ return new FontCustomPlatformData(face);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.h b/WebCore/platform/graphics/android/FontCustomPlatformData.h
new file mode 100644
index 0000000..e45d509
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontCustomPlatformData_h_
+#define FontCustomPlatformData_h_
+
+#include <wtf/Noncopyable.h>
+#include "FontRenderingMode.h"
+
+class SkTypeface;
+
+namespace WebCore {
+
+ class SharedBuffer;
+ class FontPlatformData;
+
+ class FontCustomPlatformData : Noncopyable {
+ public:
+ FontCustomPlatformData(SkTypeface* face);
+ ~FontCustomPlatformData();
+
+ SkTypeface* typeface() const { return m_typeface; }
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode );
+
+ private:
+ SkTypeface* m_typeface;
+ };
+
+ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+} // namespace WebCore
+
+#endif // FontCustomPlatformData_h_
+
diff --git a/WebCore/platform/graphics/android/FontDataAndroid.cpp b/WebCore/platform/graphics/android/FontDataAndroid.cpp
new file mode 100644
index 0000000..3dd9789
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontDataAndroid.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2006 Apple Computer, 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 "Font.h"
+#include "FontCache.h"
+#include "SimpleFontData.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkTime.h"
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ SkPaint paint;
+ SkPaint::FontMetrics metrics;
+
+ m_font.setupPaint(&paint);
+ (void)paint.getFontMetrics(&metrics);
+
+ // use ceil instead of round to favor descent, given a lot of accidental
+ // clipping of descenders (e.g. 14pt 'g') in textedit fields
+ int d = SkScalarCeil(metrics.fDescent);
+ int s = SkScalarRound(metrics.fDescent - metrics.fAscent);
+ int a = s - d;
+
+ m_ascent = a;
+ m_descent = d;
+ m_xHeight = SkScalarToFloat(-metrics.fAscent) * 0.56f; // hack I stole from the window's port
+ m_lineSpacing = a + d;
+ m_lineGap = SkScalarRound(metrics.fLeading);
+}
+
+void SimpleFontData::platformDestroy()
+{
+ delete m_smallCapsFontData;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, fontDescription.computedSize() * 0.7f));
+ }
+ return m_smallCapsFontData;
+}
+
+#define kMaxBufferCount 64
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ SkPaint paint;
+ uint16_t glyphs[kMaxBufferCount];
+
+ m_font.setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ while (length > 0) {
+ int n = SkMin32(length, SK_ARRAY_COUNT(glyphs));
+
+ int count = paint.textToGlyphs(characters, n << 1, 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 = false;
+}
+
+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);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h
new file mode 100644
index 0000000..2bb8834
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontPlatformData.h
@@ -0,0 +1,72 @@
+/*
+ * 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 2009, The Android Open Source Project
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef FontPlatformData_H
+#define FontPlatformData_H
+
+#include "StringImpl.h"
+
+class SkPaint;
+class SkTypeface;
+
+namespace WebCore {
+
+class FontPlatformData {
+public:
+ static FontPlatformData Deleted() {
+ return FontPlatformData(NULL, -1, false, false);
+ }
+
+ FontPlatformData();
+ FontPlatformData(const FontPlatformData&);
+ FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic);
+ FontPlatformData(const FontPlatformData& src, float textSize);
+ ~FontPlatformData();
+
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : mTypeface(hashTableDeletedFontValue()) { }
+ bool isHashTableDeletedValue() const {
+ return mTypeface == hashTableDeletedFontValue();
+ }
+
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool operator==(const FontPlatformData& a) const;
+
+ void setupPaint(SkPaint*) const;
+ unsigned hash() const;
+
+private:
+ SkTypeface* mTypeface;
+ float mTextSize;
+ bool mFakeBold;
+ bool mFakeItalic;
+
+ static SkTypeface* hashTableDeletedFontValue() {
+ return reinterpret_cast<SkTypeface*>(-1);
+ }
+};
+
+} /* namespace */
+
+#endif
diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
new file mode 100644
index 0000000..e82c1f6
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
@@ -0,0 +1,176 @@
+/*
+ * 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 2009, The Android Open Source Project
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+
+//#define TRACE_FONTPLATFORMDATA_LIFE
+//#define COUNT_FONTPLATFORMDATA_LIFE
+
+#ifdef COUNT_FONTPLATFORMDATA_LIFE
+static int gCount;
+static int gMaxCount;
+
+static void inc_count()
+{
+ if (++gCount > gMaxCount)
+ {
+ gMaxCount = gCount;
+ SkDebugf("---------- FontPlatformData %d\n", gMaxCount);
+ }
+}
+
+static void dec_count() { --gCount; }
+#else
+ #define inc_count()
+ #define dec_count()
+#endif
+
+#ifdef TRACE_FONTPLATFORMDATA_LIFE
+ #define trace(num) SkDebugf("FontPlatformData%d %p %g %d %d\n", num, mTypeface, mTextSize, mFakeBold, mFakeItalic)
+#else
+ #define trace(num)
+#endif
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData()
+ : mTypeface(NULL), mTextSize(0), mFakeBold(false), mFakeItalic(false)
+{
+ inc_count();
+ trace(1);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src)
+{
+ if (hashTableDeletedFontValue() != src.mTypeface) {
+ src.mTypeface->safeRef();
+ }
+
+ mTypeface = src.mTypeface;
+
+ mTextSize = src.mTextSize;
+ mFakeBold = src.mFakeBold;
+ mFakeItalic = src.mFakeItalic;
+
+ inc_count();
+ trace(2);
+}
+
+FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic)
+ : mTypeface(tf), mTextSize(textSize), mFakeBold(fakeBold), mFakeItalic(fakeItalic)
+{
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeRef();
+ }
+
+ inc_count();
+ trace(3);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
+ : mTypeface(src.mTypeface), mTextSize(textSize), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic)
+{
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeRef();
+ }
+
+ inc_count();
+ trace(4);
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ dec_count();
+#ifdef TRACE_FONTPLATFORMDATA_LIFE
+ SkDebugf("----------- ~FontPlatformData\n");
+#endif
+
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeUnref();
+ }
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
+{
+ if (hashTableDeletedFontValue() != src.mTypeface) {
+ src.mTypeface->safeRef();
+ }
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeUnref();
+ }
+
+ mTypeface = src.mTypeface;
+ mTextSize = src.mTextSize;
+ mFakeBold = src.mFakeBold;
+ mFakeItalic = src.mFakeItalic;
+
+ return *this;
+}
+
+void FontPlatformData::setupPaint(SkPaint* paint) const
+{
+ float ts = mTextSize;
+ if (!(ts > 0))
+ ts = 12;
+
+ paint->setAntiAlias(true);
+ paint->setSubpixelText(true);
+ paint->setTextSize(SkFloatToScalar(ts));
+ paint->setTypeface(mTypeface);
+ paint->setFakeBoldText(mFakeBold);
+ paint->setTextSkewX(mFakeItalic ? -SK_Scalar1/4 : 0);
+ paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& a) const
+{
+ return mTypeface == a.mTypeface &&
+ mTextSize == a.mTextSize &&
+ mFakeBold == a.mFakeBold &&
+ mFakeItalic == a.mFakeItalic;
+}
+
+unsigned FontPlatformData::hash() const
+{
+ unsigned h;
+
+ if (hashTableDeletedFontValue() == mTypeface) {
+ h = reinterpret_cast<unsigned>(mTypeface);
+ } else {
+ h = SkTypeface::UniqueID(mTypeface);
+ }
+
+ uint32_t sizeAsInt = *reinterpret_cast<const uint32_t*>(&mTextSize);
+
+ h ^= 0x01010101 * (((int)mFakeBold << 1) | (int)mFakeItalic);
+ h ^= sizeAsInt;
+ return h;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/android/GlyphMapAndroid.cpp b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp
new file mode 100644
index 0000000..1df06b1
--- /dev/null
+++ b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2006 Apple Computer, 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 "GlyphPageTreeNode.h"
+#include "SimpleFontData.h"
+
+#include "SkTemplates.h"
+#include "SkPaint.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+#define NO_BREAK_SPACE_UNICHAR 0xA0
+
+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();
+ unsigned count = paint.textToGlyphs(buffer, bufferLength << 1, 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], fontData);
+ allGlyphs |= glyphs[i];
+ }
+ return allGlyphs != 0;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/android/GradientAndroid.cpp b/WebCore/platform/graphics/android/GradientAndroid.cpp
new file mode 100644
index 0000000..71b7f73
--- /dev/null
+++ b/WebCore/platform/graphics/android/GradientAndroid.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "Gradient.h"
+
+#include "android_graphics.h"
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "SkCanvas.h"
+#include "SkColorShader.h"
+#include "SkGradientShader.h"
+#include "SkPaint.h"
+
+class PlatformGradientRec {
+public:
+ PlatformGradientRec() : m_shader(NULL) {}
+ ~PlatformGradientRec() { m_shader->safeUnref(); }
+
+ SkShader* m_shader;
+ SkShader::TileMode m_tileMode;
+};
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ delete m_gradient;
+ m_gradient = 0;
+}
+
+static U8CPU F2B(float x)
+{
+ return (int)(x * 255);
+}
+
+SkShader* Gradient::getShader(SkShader::TileMode mode) {
+ if (NULL == m_gradient) {
+ m_gradient = new PlatformGradientRec;
+ } else if (m_gradient->m_tileMode == mode) {
+ return m_gradient->m_shader;
+ }
+
+ SkPoint pts[2];
+
+ android_setpt(&pts[0], m_p0);
+ android_setpt(&pts[1], m_p1);
+ size_t count = m_stops.size();
+ SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
+ SkColor* colors = (SkColor*)storage.get();
+ SkScalar* pos = (SkScalar*)(colors + count);
+
+ Vector<ColorStop>::iterator iter = m_stops.begin();
+ int i = -1;
+ while (i++, iter != m_stops.end()) {
+ pos[i] = SkFloatToScalar(iter->stop);
+ colors[i] = SkColorSetARGB(F2B(iter->alpha), F2B(iter->red),
+ F2B(iter->green), F2B(iter->blue));
+ ++iter;
+ }
+
+ SkShader* s;
+ if (0 == count) {
+ // it seems the spec says a zero-size gradient draws transparent
+ s = new SkColorShader(0);
+ } else if (m_radial) {
+ s = SkGradientShader::CreateRadial(pts[0], SkFloatToScalar(m_r0),
+ colors, pos, count, mode);
+ } else {
+ s = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ }
+
+ m_gradient->m_shader->safeUnref();
+ m_gradient->m_shader = s;
+ m_gradient->m_tileMode = mode;
+ return s;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ SkRect r;
+ SkPaint paint;
+ // we don't care about the mode, so try to use the existing one
+ SkShader::TileMode mode = m_gradient ? m_gradient->m_tileMode :
+ SkShader::kClamp_TileMode;
+
+ paint.setAntiAlias(true);
+ paint.setShader(this->getShader(mode));
+ android_gc2canvas(context)->drawRect(*android_setrect(&r, rect), paint);
+}
+
+
+} //namespace
diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
new file mode 100644
index 0000000..c2e0f02
--- /dev/null
+++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -0,0 +1,1118 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "Gradient.h"
+#include "GraphicsContext.h"
+#include "GraphicsContextPrivate.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pattern.h"
+
+#include "SkBlurDrawLooper.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkDashPathEffect.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkPorterDuff.h"
+#include "PlatformGraphicsContext.h"
+#include "AffineTransform.h"
+
+#include "android_graphics.h"
+#include "SkGradientShader.h"
+#include "SkBitmapRef.h"
+#include "SkString.h"
+
+using namespace std;
+
+#define GC2Canvas(ctx) (ctx)->m_data->mPgc->mCanvas
+
+namespace WebCore {
+
+static int RoundToInt(float x)
+{
+ return (int)roundf(x);
+}
+
+template <typename T> T* deepCopyPtr(const T* src) {
+ return src ? new T(*src) : NULL;
+}
+
+/* TODO / questions
+
+ mAlpha: how does this interact with the alpha in Color? multiply them together?
+ mPorterDuffMode: do I always respect this? If so, then
+ the rgb() & 0xFF000000 check will abort drawing too often
+ Is Color premultiplied or not? If it is, then I can't blindly pass it to paint.setColor()
+*/
+
+struct ShadowRec {
+ SkScalar mBlur; // >0 means valid shadow
+ SkScalar mDx;
+ SkScalar mDy;
+ SkColor mColor;
+};
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContext* mCG; // back-ptr to our parent
+ PlatformGraphicsContext* mPgc;
+
+ struct State {
+ SkPath* mPath;
+ float mMiterLimit;
+ float mAlpha;
+ float mStrokeThickness;
+ SkPaint::Cap mLineCap;
+ SkPaint::Join mLineJoin;
+ SkPorterDuff::Mode mPorterDuffMode;
+ int mDashRatio; //ratio of the length of a dash to its width
+ ShadowRec mShadow;
+ SkColor mFillColor;
+ SkColor mStrokeColor;
+ bool mUseAA;
+
+ State() {
+ mPath = NULL; // lazily allocated
+ mMiterLimit = 4;
+ mAlpha = 1;
+ mStrokeThickness = 0.0f; // Same as default in GraphicsContextPrivate.h
+ mLineCap = SkPaint::kDefault_Cap;
+ mLineJoin = SkPaint::kDefault_Join;
+ mPorterDuffMode = SkPorterDuff::kSrcOver_Mode;
+ mDashRatio = 3;
+ mUseAA = true;
+ mShadow.mBlur = 0;
+ mFillColor = SK_ColorBLACK;
+ mStrokeColor = SK_ColorBLACK;
+ }
+
+ State(const State& other) {
+ memcpy(this, &other, sizeof(State));
+ mPath = deepCopyPtr<SkPath>(other.mPath);
+ }
+
+ ~State() {
+ delete mPath;
+ }
+
+ void setShadow(int radius, int dx, int dy, SkColor c) {
+ // cut the radius in half, to visually match the effect seen in
+ // safari browser
+ mShadow.mBlur = SkScalarHalf(SkIntToScalar(radius));
+ mShadow.mDx = SkIntToScalar(dx);
+ mShadow.mDy = SkIntToScalar(dy);
+ mShadow.mColor = c;
+ }
+
+ bool setupShadowPaint(SkPaint* paint, SkPoint* offset) {
+ if (mShadow.mBlur > 0) {
+ paint->setAntiAlias(true);
+ paint->setDither(true);
+ paint->setPorterDuffXfermode(mPorterDuffMode);
+ paint->setColor(mShadow.mColor);
+ paint->setMaskFilter(SkBlurMaskFilter::Create(mShadow.mBlur,
+ SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+ offset->set(mShadow.mDx, mShadow.mDy);
+ return true;
+ }
+ return false;
+ }
+
+ SkColor applyAlpha(SkColor c) const
+ {
+ int s = RoundToInt(mAlpha * 256);
+ if (s >= 256)
+ return c;
+ if (s < 0)
+ return 0;
+
+ int a = SkAlphaMul(SkColorGetA(c), s);
+ return (c & 0x00FFFFFF) | (a << 24);
+ }
+ };
+
+ SkDeque mStateStack;
+ State* mState;
+
+ GraphicsContextPlatformPrivate(GraphicsContext* cg, PlatformGraphicsContext* pgc)
+ : mCG(cg)
+ , mPgc(pgc), mStateStack(sizeof(State)) {
+ State* state = (State*)mStateStack.push_back();
+ new (state) State();
+ mState = state;
+ }
+
+ ~GraphicsContextPlatformPrivate() {
+ if (mPgc && mPgc->deleteUs())
+ delete mPgc;
+
+ // we force restores so we don't leak any subobjects owned by our
+ // stack of State records.
+ while (mStateStack.count() > 0)
+ this->restore();
+ }
+
+ void save() {
+ State* newState = (State*)mStateStack.push_back();
+ new (newState) State(*mState);
+ mState = newState;
+ }
+
+ void restore() {
+ mState->~State();
+ mStateStack.pop_back();
+ mState = (State*)mStateStack.back();
+ }
+
+ void setFillColor(const Color& c) {
+ mState->mFillColor = c.rgb();
+ }
+
+ void setStrokeColor(const Color& c) {
+ mState->mStrokeColor = c.rgb();
+ }
+
+ void setStrokeThickness(float f) {
+ mState->mStrokeThickness = f;
+ }
+
+ void beginPath() {
+ if (mState->mPath) {
+ mState->mPath->reset();
+ }
+ }
+
+ void addPath(const SkPath& other) {
+ if (!mState->mPath) {
+ mState->mPath = new SkPath(other);
+ } else {
+ mState->mPath->addPath(other);
+ }
+ }
+
+ // may return null
+ SkPath* getPath() const { return mState->mPath; }
+
+ void setup_paint_common(SkPaint* paint) const {
+ paint->setAntiAlias(mState->mUseAA);
+ paint->setDither(true);
+ paint->setPorterDuffXfermode(mState->mPorterDuffMode);
+ if (mState->mShadow.mBlur > 0) {
+ SkDrawLooper* looper = new SkBlurDrawLooper(mState->mShadow.mBlur,
+ mState->mShadow.mDx,
+ mState->mShadow.mDy,
+ mState->mShadow.mColor);
+ paint->setLooper(looper)->unref();
+ }
+
+ /* need to sniff textDrawingMode(), which returns the bit_OR of...
+ const int cTextInvisible = 0;
+ const int cTextFill = 1;
+ const int cTextStroke = 2;
+ const int cTextClip = 4;
+ */
+ }
+
+ void setup_paint_fill(SkPaint* paint) const {
+ this->setup_paint_common(paint);
+ paint->setColor(mState->mFillColor);
+ }
+
+ /* sets up the paint for stroking. Returns true if the style is really
+ just a dash of squares (the size of the paint's stroke-width.
+ */
+ bool setup_paint_stroke(SkPaint* paint, SkRect* rect) {
+ this->setup_paint_common(paint);
+ paint->setColor(mState->mStrokeColor);
+
+ float width = mState->mStrokeThickness;
+
+ // this allows dashing and dotting to work properly for hairline strokes
+ // FIXME: Should we only do this for dashed and dotted strokes?
+ if (0 == width) {
+ width = 1;
+ }
+
+// paint->setColor(mState->applyAlpha(mCG->strokeColor().rgb()));
+ paint->setStyle(SkPaint::kStroke_Style);
+ paint->setStrokeWidth(SkFloatToScalar(width));
+ paint->setStrokeCap(mState->mLineCap);
+ paint->setStrokeJoin(mState->mLineJoin);
+ paint->setStrokeMiter(SkFloatToScalar(mState->mMiterLimit));
+
+ if (rect != NULL && (RoundToInt(width) & 1)) {
+ rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
+ }
+
+ switch (mCG->strokeStyle()) {
+ case NoStroke:
+ case SolidStroke:
+ width = 0;
+ break;
+ case DashedStroke:
+ width = mState->mDashRatio * width;
+ break;
+ /* no break */
+ case DottedStroke:
+ break;
+ }
+
+ if (width > 0) {
+ SkScalar intervals[] = { width, width };
+ SkPathEffect* pe = new SkDashPathEffect(intervals, 2, 0);
+ paint->setPathEffect(pe)->unref();
+ // return true if we're basically a dotted dash of squares
+ return RoundToInt(width) == RoundToInt(paint->getStrokeWidth());
+ }
+ return false;
+ }
+
+private:
+ // not supported yet
+ State& operator=(const State&);
+};
+
+static SkShader::TileMode SpreadMethod2TileMode(GradientSpreadMethod sm) {
+ SkShader::TileMode mode = SkShader::kClamp_TileMode;
+
+ switch (sm) {
+ case SpreadMethodPad:
+ mode = SkShader::kClamp_TileMode;
+ break;
+ case SpreadMethodReflect:
+ mode = SkShader::kMirror_TileMode;
+ break;
+ case SpreadMethodRepeat:
+ mode = SkShader::kRepeat_TileMode;
+ break;
+ }
+ return mode;
+}
+
+static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat,
+ Gradient* grad, GradientSpreadMethod sm) {
+ switch (cs) {
+ case PatternColorSpace:
+ // createPlatformPattern() returns a new inst
+ paint->setShader(pat->createPlatformPattern(
+ AffineTransform()))->safeUnref();
+ break;
+ case GradientColorSpace: {
+ // grad->getShader() returns a cached obj
+ paint->setShader(grad->getShader(SpreadMethod2TileMode(sm)));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
+{
+ PlatformGraphicsContext* pgc = new PlatformGraphicsContext();
+
+ SkBitmap bitmap;
+
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+ pgc->mCanvas->setBitmapDevice(bitmap);
+
+ GraphicsContext* ctx = new GraphicsContext(pgc);
+//printf("-------- create offscreen <canvas> %p\n", ctx);
+ return ctx;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext *gc)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(this, gc))
+{
+ setPaintingDisabled(NULL == gc || NULL == gc->mCanvas);
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ delete m_data;
+ this->destroyGraphicsContextPrivate(m_common);
+}
+
+void GraphicsContext::savePlatformState()
+{
+ // save our private State
+ m_data->save();
+ // save our native canvas
+ GC2Canvas(this)->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ // restore our native canvas
+ GC2Canvas(this)->restore();
+ // restore our private State
+ m_data->restore();
+}
+
+bool GraphicsContext::willFill() const {
+ return m_data->mState->mFillColor != 0;
+}
+
+bool GraphicsContext::willStroke() const {
+ return m_data->mState->mStrokeColor != 0;
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+
+ if (fillColor().alpha()) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+
+ if (strokeStyle() != NoStroke && strokeColor().alpha()) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, &r);
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ if (style == NoStroke)
+ return;
+
+ SkPaint paint;
+ SkCanvas* canvas = GC2Canvas(this);
+ const int idx = SkAbs32(point2.x() - point1.x());
+ const int idy = SkAbs32(point2.y() - point1.y());
+
+ // special-case horizontal and vertical lines that are really just dots
+ if (m_data->setup_paint_stroke(&paint, NULL) && (0 == idx || 0 == idy)) {
+ const SkScalar diameter = paint.getStrokeWidth();
+ const SkScalar radius = SkScalarHalf(diameter);
+ SkScalar x = SkIntToScalar(SkMin32(point1.x(), point2.x()));
+ SkScalar y = SkIntToScalar(SkMin32(point1.y(), point2.y()));
+ SkScalar dx, dy;
+ int count;
+ SkRect bounds;
+
+ if (0 == idy) { // horizontal
+ bounds.set(x, y - radius, x + SkIntToScalar(idx), y + radius);
+ x += radius;
+ dx = diameter * 2;
+ dy = 0;
+ count = idx;
+ } else { // vertical
+ bounds.set(x - radius, y, x + radius, y + SkIntToScalar(idy));
+ y += radius;
+ dx = 0;
+ dy = diameter * 2;
+ count = idy;
+ }
+
+ // the actual count is the number of ONs we hit alternating
+ // ON(diameter), OFF(diameter), ...
+ {
+ SkScalar width = SkScalarDiv(SkIntToScalar(count), diameter);
+ // now computer the number of cells (ON and OFF)
+ count = SkScalarRound(width);
+ // now compute the number of ONs
+ count = (count + 1) >> 1;
+ }
+
+ SkAutoMalloc storage(count * sizeof(SkPoint));
+ SkPoint* verts = (SkPoint*)storage.get();
+ // now build the array of vertices to past to drawPoints
+ for (int i = 0; i < count; i++) {
+ verts[i].set(x, y);
+ x += dx;
+ y += dy;
+ }
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setPathEffect(NULL);
+
+ // clipping to bounds is not required for correctness, but it does
+ // allow us to reject the entire array of points if we are completely
+ // offscreen. This is common in a webpage for android, where most of
+ // the content is clipped out. If drawPoints took an (optional) bounds
+ // parameter, that might even be better, as we would *just* use it for
+ // culling, and not both wacking the canvas' save/restore stack.
+ canvas->save(SkCanvas::kClip_SaveFlag);
+ canvas->clipRect(bounds);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint);
+ canvas->restore();
+ } else {
+ SkPoint pts[2];
+ android_setpt(&pts[0], point1);
+ android_setpt(&pts[1], point2);
+ canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+ }
+}
+
+static void setrect_for_underline(SkRect* r, GraphicsContext* context, const IntPoint& point, int yOffset, int width)
+{
+ float lineThickness = context->strokeThickness();
+// if (lineThickness < 1) // do we really need/want this?
+// lineThickness = 1;
+
+ yOffset += 1; // we add 1 to have underlines appear below the text
+
+ r->fLeft = SkIntToScalar(point.x());
+ r->fTop = SkIntToScalar(point.y() + yOffset);
+ r->fRight = r->fLeft + SkIntToScalar(width);
+ r->fBottom = r->fTop + SkFloatToScalar(lineThickness);
+}
+
+void GraphicsContext::drawLineForText(IntPoint const& pt, int width, bool)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ setrect_for_underline(&r, this, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(this->strokeColor().rgb());
+
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ setrect_for_underline(&r, this, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorRED); // is this specified somewhere?
+
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect oval;
+
+ android_setrect(&oval, rect);
+
+ if (fillColor().rgb() & 0xFF000000) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawOval(oval, paint);
+ }
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, &oval);
+ GC2Canvas(this)->drawOval(oval, paint);
+ }
+}
+
+static inline int fast_mod(int value, int max)
+{
+ int sign = SkExtractSign(value);
+
+ value = SkApplySign(value, sign);
+ if (value >= max) {
+ value %= max;
+ }
+ return SkApplySign(value, sign);
+}
+
+void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPath path;
+ SkPaint paint;
+ SkRect oval;
+
+ android_setrect(&oval, r);
+
+ if (strokeStyle() == NoStroke) {
+ m_data->setup_paint_fill(&paint); // we want the fill color
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkFloatToScalar(this->strokeThickness()));
+ }
+ else {
+ m_data->setup_paint_stroke(&paint, NULL);
+ }
+
+ // we do this before converting to scalar, so we don't overflow SkFixed
+ startAngle = fast_mod(startAngle, 360);
+ angleSpan = fast_mod(angleSpan, 360);
+
+ path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ SkPaint paint;
+ SkPath path;
+
+ path.incReserve(numPoints);
+ path.moveTo(SkFloatToScalar(points[0].x()), SkFloatToScalar(points[0].y()));
+ for (size_t i = 1; i < numPoints; i++)
+ path.lineTo(SkFloatToScalar(points[i].x()), SkFloatToScalar(points[i].y()));
+
+ if (GC2Canvas(this)->quickReject(path, shouldAntialias ?
+ SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) {
+ return;
+ }
+
+ if (fillColor().rgb() & 0xFF000000) {
+ m_data->setup_paint_fill(&paint);
+ paint.setAntiAlias(shouldAntialias);
+ GC2Canvas(this)->drawPath(path, paint);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, NULL);
+ paint.setAntiAlias(shouldAntialias);
+ GC2Canvas(this)->drawPath(path, 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;
+
+ SkPaint paint;
+ SkPath path;
+ SkScalar radii[8];
+ SkRect r;
+
+ radii[0] = SkIntToScalar(topLeft.width());
+ radii[1] = SkIntToScalar(topLeft.height());
+ radii[2] = SkIntToScalar(topRight.width());
+ radii[3] = SkIntToScalar(topRight.height());
+ radii[4] = SkIntToScalar(bottomRight.width());
+ radii[5] = SkIntToScalar(bottomRight.height());
+ radii[6] = SkIntToScalar(bottomLeft.width());
+ radii[7] = SkIntToScalar(bottomLeft.height());
+ path.addRoundRect(*android_setrect(&r, rect), radii);
+
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_fill(&paint);
+
+ extactShader(&paint, m_common->state.fillColorSpace,
+ m_common->state.fillPattern.get(),
+ m_common->state.fillGradient.get(), spreadMethod());
+
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (color.rgb() & 0xFF000000) {
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_common(&paint);
+ paint.setColor(color.rgb()); // punch in the specified color
+ paint.setShader(NULL); // in case we had one set
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+
+ GC2Canvas(this)->clipRect(*android_setrect(&r, rect));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+// path.platformPath()->dump(false, "clip path");
+
+ GC2Canvas(this)->clipPath(*path.platformPath());
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+//printf("-------- addInnerRoundedRectClip: [%d %d %d %d] thickness=%d\n", rect.x(), rect.y(), rect.width(), rect.height(), thickness);
+
+ SkPath path;
+ SkRect r;
+ android_setrect(&r, rect);
+ 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);
+ }
+ GC2Canvas(this)->clipPath(path);
+}
+
+void GraphicsContext::clipOut(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect rect;
+
+ GC2Canvas(this)->clipRect(*android_setrect(&rect, r), SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect oval;
+ SkPath path;
+
+ path.addOval(*android_setrect(&oval, r), SkPath::kCCW_Direction);
+ GC2Canvas(this)->clipPath(path, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOut(const Path& p)
+{
+ if (paintingDisabled())
+ return;
+
+ GC2Canvas(this)->clipPath(*p.platformPath(), SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) {
+ SkDebugf("xxxxxxxxxxxxxxxxxx clipToImageBuffer not implemented\n");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if SVG_SUPPORT
+KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext()
+{
+ return new KRenderingDeviceContextQuartz(platformContext());
+}
+#endif
+
+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();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ GC2Canvas(this)->restore();
+}
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ void GraphicsContext::setupFillPaint(SkPaint* paint) {
+ m_data->setup_paint_fill(paint);
+ }
+
+ void GraphicsContext::setupStrokePaint(SkPaint* paint) {
+ m_data->setup_paint_stroke(paint, NULL);
+ }
+
+ bool GraphicsContext::setupShadowPaint(SkPaint* paint, SkPoint* offset) {
+ return m_data->mState->setupShadowPaint(paint, offset);
+ }
+
+ // referenced from CanvasStyle.cpp
+ void GraphicsContext::setCMYKAFillColor(float c, float m, float y, float k, float a) {
+ float r = 1 - (c + k);
+ float g = 1 - (m + k);
+ float b = 1 - (y + k);
+ return this->setFillColor(Color(r, g, b, a));
+ }
+
+ // referenced from CanvasStyle.cpp
+ void GraphicsContext::setCMYKAStrokeColor(float c, float m, float y, float k, float a) {
+ float r = 1 - (c + k);
+ float g = 1 - (m + k);
+ float b = 1 - (y + k);
+ return this->setStrokeColor(Color(r, g, b, a));
+ }
+
+ void GraphicsContext::setPlatformStrokeColor(const Color& c) {
+ m_data->setStrokeColor(c);
+ }
+
+ void GraphicsContext::setPlatformStrokeThickness(float f) {
+ m_data->setStrokeThickness(f);
+ }
+
+ void GraphicsContext::setPlatformFillColor(const Color& c) {
+ m_data->setFillColor(c);
+ }
+
+void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (blur <= 0) {
+ this->clearPlatformShadow();
+ }
+
+ SkColor c;
+ if (color.isValid()) {
+ c = color.rgb();
+ } else {
+ c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" Apple shadow color
+ }
+ m_data->mState->setShadow(blur, size.width(), size.height(), c);
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->mState->setShadow(0, 0, 0, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ // Do nothing, since we draw the focus ring independently.
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ ASSERT(!paintingDisabled());
+ return m_data->mPgc;
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ m_data->mState->mMiterLimit = limit;
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_data->mState->mAlpha = alpha;
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ m_data->mState->mPorterDuffMode = android_convert_compositeOp(op);
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_fill(&paint);
+ paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+
+ m_data->setup_paint_stroke(&paint, NULL);
+ paint.setStrokeWidth(SkFloatToScalar(lineWidth));
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::setLineCap(LineCap cap)
+{
+ switch (cap) {
+ case ButtCap:
+ m_data->mState->mLineCap = SkPaint::kButt_Cap;
+ break;
+ case RoundCap:
+ m_data->mState->mLineCap = SkPaint::kRound_Cap;
+ break;
+ case SquareCap:
+ m_data->mState->mLineCap = SkPaint::kSquare_Cap;
+ break;
+ default:
+ SkDEBUGF(("GraphicsContext::setLineCap: unknown LineCap %d\n", cap));
+ break;
+ }
+}
+
+void GraphicsContext::setLineJoin(LineJoin join)
+{
+ switch (join) {
+ case MiterJoin:
+ m_data->mState->mLineJoin = SkPaint::kMiter_Join;
+ break;
+ case RoundJoin:
+ m_data->mState->mLineJoin = SkPaint::kRound_Join;
+ break;
+ case BevelJoin:
+ m_data->mState->mLineJoin = SkPaint::kBevel_Join;
+ break;
+ default:
+ SkDEBUGF(("GraphicsContext::setLineJoin: unknown LineJoin %d\n", join));
+ break;
+ }
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->scale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+}
+
+void GraphicsContext::rotate(float angleInRadians)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->rotate(SkFloatToScalar(angleInRadians * (180.0f / 3.14159265f)));
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->translate(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& xform)
+{
+ if (paintingDisabled())
+ return;
+
+//printf("-------------- GraphicsContext::concatCTM\n");
+ GC2Canvas(this)->concat((SkMatrix) xform);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return FloatRect();
+
+ const SkMatrix& matrix = GC2Canvas(this)->getTotalMatrix();
+ SkRect r;
+ android_setrect(&r, rect);
+ matrix.mapRect(&r);
+ FloatRect result(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+// appears to be PDF specific, so we ignore it
+#if 0
+if (paintingDisabled())
+ return;
+
+CFURLRef urlRef = link.createCFURL();
+if (urlRef) {
+ CGContextRef context = platformContext();
+
+ // Get the bounding box to handle clipping.
+ CGRect box = CGContextGetClipBoundingBox(context);
+
+ IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
+ IntRect rect = destRect;
+ rect.intersect(intBox);
+
+ CGPDFContextSetURLForRect(context, urlRef,
+ CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+
+ CFRelease(urlRef);
+}
+#endif
+}
+
+void GraphicsContext::setUseAntialiasing(bool useAA) {
+ if (paintingDisabled())
+ return;
+ m_data->mState->mUseAA = useAA;
+}
+
+AffineTransform GraphicsContext::getCTM() const {
+ return AffineTransform(GC2Canvas(this)->getTotalMatrix());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GraphicsContext::beginPath() {
+ m_data->beginPath();
+}
+
+void GraphicsContext::addPath(const Path& p) {
+ m_data->addPath(*p.platformPath());
+}
+
+void GraphicsContext::drawPath() {
+ this->fillPath();
+ this->strokePath();
+}
+
+void GraphicsContext::fillPath() {
+ SkPath* path = m_data->getPath();
+ if (paintingDisabled() || !path)
+ return;
+
+ switch (this->fillRule()) {
+ case RULE_NONZERO:
+ path->setFillType(SkPath::kWinding_FillType);
+ break;
+ case RULE_EVENODD:
+ path->setFillType(SkPath::kEvenOdd_FillType);
+ break;
+ }
+
+ SkPaint paint;
+ m_data->setup_paint_fill(&paint);
+
+ extactShader(&paint, m_common->state.fillColorSpace,
+ m_common->state.fillPattern.get(),
+ m_common->state.fillGradient.get(), spreadMethod());
+
+ GC2Canvas(this)->drawPath(*path, paint);
+}
+
+void GraphicsContext::strokePath() {
+ const SkPath* path = m_data->getPath();
+ if (paintingDisabled() || !path || strokeStyle() == NoStroke)
+ return;
+
+ SkPaint paint;
+ m_data->setup_paint_stroke(&paint, NULL);
+
+ extactShader(&paint, m_common->state.strokeColorSpace,
+ m_common->state.strokePattern.get(),
+ m_common->state.strokeGradient.get(), spreadMethod());
+
+ GC2Canvas(this)->drawPath(*path, paint);
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
+{
+ /*
+ enum InterpolationQuality {
+ InterpolationDefault,
+ InterpolationNone,
+ InterpolationLow,
+ InterpolationMedium,
+ InterpolationHigh
+ };
+
+ TODO: record this, so we can know when to use bitmap-filtering when we draw
+ ... not sure how meaningful this will be given our playback model.
+
+ Certainly safe to do nothing for the present.
+ */
+}
+
+} // namespace WebCore
+
+///////////////////////////////////////////////////////////////////////////////
+
+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
new file mode 100644
index 0000000..04235d5
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "AffineTransform.h"
+#include "BitmapImage.h"
+#include "Image.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformString.h"
+#include "SharedBuffer.h"
+
+#include "android_graphics.h"
+#include "SkBitmapRef.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkImageDecoder.h"
+#include "SkShader.h"
+#include "SkString.h"
+#include "SkTemplates.h"
+
+#include <utils/AssetManager.h>
+
+//#define TRACE_SUBSAMPLED_BITMAPS
+//#define TRACE_SKIPPED_BITMAPS
+
+android::AssetManager* globalAssetManager() {
+ static android::AssetManager* gGlobalAssetMgr;
+ if (!gGlobalAssetMgr) {
+ gGlobalAssetMgr = new android::AssetManager();
+ gGlobalAssetMgr->addDefaultAssets();
+ }
+ return gGlobalAssetMgr;
+}
+
+namespace WebCore {
+
+void FrameData::clear()
+{
+ if (m_frame) {
+ m_frame->unref();
+ m_frame = 0;
+ m_duration = 0.;
+ m_hasAlpha = true;
+ }
+}
+
+BitmapImage::BitmapImage(SkBitmapRef* ref, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(0)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ m_size = IntSize(ref->bitmap().width(), ref->bitmap().height());
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = ref;
+ m_frames[0].m_hasAlpha = !ref->bitmap().isOpaque();
+ checkForSolidColor();
+ ref->ref();
+}
+
+
+void BitmapImage::initPlatformData()
+{
+ m_source.clearURL();
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ if (frameCount() == 1) {
+ SkBitmapRef* ref = frameAtIndex(0);
+ if (!ref) {
+ return; // keep solid == false
+ }
+
+ const SkBitmap& bm = ref->bitmap();
+ if (bm.width() != 1 || bm.height() != 1) {
+ return; // keep solid == false
+ }
+
+ SkAutoLockPixels alp(bm);
+ if (!bm.readyToDraw()) {
+ return; // keep solid == false
+ }
+
+ SkPMColor color;
+ switch (bm.getConfig()) {
+ case SkBitmap::kARGB_8888_Config:
+ color = *bm.getAddr32(0, 0);
+ break;
+ case SkBitmap::kRGB_565_Config:
+ color = SkPixel16ToPixel32(*bm.getAddr16(0, 0));
+ break;
+ case SkBitmap::kIndex8_Config: {
+ SkColorTable* ctable = bm.getColorTable();
+ if (!ctable) {
+ return;
+ }
+ color = (*ctable)[*bm.getAddr8(0, 0)];
+ break;
+ }
+ default:
+ return; // keep solid == false
+ }
+ m_isSolidColor = true;
+ m_solidColor = android_SkPMColorToWebCoreColor(color);
+ }
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
+ const FloatRect& srcRect, CompositeOperator compositeOp)
+{
+ SkBitmapRef* image = this->nativeImageForCurrentFrame();
+ if (!image) { // If it's too early we won't have an image yet.
+ return;
+ }
+
+ // in case we get called with an incomplete bitmap
+ const SkBitmap& bitmap = image->bitmap();
+ if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
+#ifdef TRACE_SKIPPED_BITMAPS
+ SkDebugf("----- skip bitmapimage: [%d %d] pixels %p pixelref %p\n",
+ bitmap.width(), bitmap.height(),
+ bitmap.getPixels(), bitmap.pixelRef());
+#endif
+ return;
+ }
+
+ SkIRect srcR;
+ SkRect dstR;
+ float invScaleX = (float)bitmap.width() / image->origWidth();
+ float invScaleY = (float)bitmap.height() / image->origHeight();
+
+ android_setrect(&dstR, dstRect);
+ android_setrect_scaled(&srcR, srcRect, invScaleX, invScaleY);
+ if (srcR.isEmpty() || dstR.isEmpty()) {
+#ifdef TRACE_SKIPPED_BITMAPS
+ SkDebugf("----- skip bitmapimage: [%d %d] src-empty %d dst-empty %d\n",
+ bitmap.width(), bitmap.height(),
+ srcR.isEmpty(), dstR.isEmpty());
+#endif
+ return;
+ }
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ SkPaint paint;
+
+ paint.setFilterBitmap(true);
+ paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
+
+ startAnimation();
+
+#ifdef TRACE_SUBSAMPLED_BITMAPS
+ if (bitmap.width() != image->origWidth() ||
+ bitmap.height() != image->origHeight()) {
+ SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
+ bitmap.width(), bitmap.height(),
+ image->origWidth(), image->origHeight());
+ }
+#endif
+}
+
+void BitmapImage::setURL(const String& str)
+{
+ m_source.setURL(str);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
+ const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator compositeOp,
+ const FloatRect& destRect)
+{
+ SkBitmapRef* image = this->nativeImageForCurrentFrame();
+ if (!image) { // If it's too early we won't have an image yet.
+ return;
+ }
+
+ // in case we get called with an incomplete bitmap
+ const SkBitmap& bitmap = image->bitmap();
+ if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
+ return;
+ }
+
+ SkRect dstR;
+ android_setrect(&dstR, destRect);
+ if (dstR.isEmpty()) {
+ return;
+ }
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ SkPaint paint;
+
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ paint.setShader(shader)->unref();
+ // now paint is the only owner of shader
+ paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ paint.setFilterBitmap(true);
+
+ SkMatrix matrix(patternTransform);
+
+ float scaleX = (float)image->origWidth() / bitmap.width();
+ float scaleY = (float)image->origHeight() / bitmap.height();
+ matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
+
+ matrix.postTranslate(SkFloatToScalar(phase.x()),
+ SkFloatToScalar(phase.y()));
+ shader->setLocalMatrix(matrix);
+ canvas->drawRect(dstR, paint);
+
+#ifdef TRACE_SUBSAMPLED_BITMAPS
+ if (bitmap.width() != image->origWidth() ||
+ bitmap.height() != image->origHeight()) {
+ SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n",
+ bitmap.width(), bitmap.height(),
+ image->origWidth(), image->origHeight(),
+ SkScalarToFloat(dstR.width()), SkScalarToFloat(dstR.height()));
+ }
+#endif
+}
+
+// missingImage, textAreaResizeCorner
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ android::AssetManager* am = globalAssetManager();
+
+ SkString path("webkit/");
+ path.append(name);
+ path.append(".png");
+
+ android::Asset* a = am->open(path.c_str(),
+ android::Asset::ACCESS_BUFFER);
+ if (a == NULL) {
+ SkDebugf("---------------- failed to open image asset %s\n", name);
+ return NULL;
+ }
+
+ SkAutoTDelete<android::Asset> ad(a);
+
+ SkBitmap bm;
+ if (SkImageDecoder::DecodeMemory(a->getBuffer(false), a->getLength(), &bm)) {
+ SkBitmapRef* ref = new SkBitmapRef(bm);
+ // create will call ref(), so we need aur() to release ours upon return
+ SkAutoUnref aur(ref);
+ return BitmapImage::create(ref, 0);
+ }
+ return Image::nullImage();
+}
+
+} // namespace
+
diff --git a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
new file mode 100644
index 0000000..de88b33
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "BitmapImage.h"
+#include "ImageBuffer.h"
+#include "ImageData.h"
+#include "NotImplemented.h"
+
+#include "android_graphics.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContext.h"
+#include "SkBitmapRef.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkDevice.h"
+#include "SkUnPreMultiply.h"
+
+using namespace std;
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize&)
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ m_context.set(GraphicsContext::createOffscreenContext(size.width(), size.height()));
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+/* This guy needs to make a deep copy of the bitmap, so that the returned
+ image doesn't reflect any subsequent changes to the canvas' backend.
+ e.g. this is called when <canvas> wants to make a Pattern, which needs
+ to snapshot the current pixels when it is created.
+ */
+Image* ImageBuffer::image() const
+{
+ if (!m_image) {
+ ASSERT(context());
+ SkCanvas* canvas = context()->platformContext()->mCanvas;
+ SkDevice* device = canvas->getDevice();
+ const SkBitmap& orig = device->accessBitmap(false);
+
+ SkBitmap copy;
+ orig.copyTo(&copy, orig.config());
+
+ SkBitmapRef* ref = new SkBitmapRef(copy);
+ m_image = BitmapImage::create(ref, 0);
+ ref->unref();
+ }
+ return m_image.get();
+}
+
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
+{
+ GraphicsContext* gc = this->context();
+ if (!gc) {
+ return 0;
+ }
+
+ const SkBitmap& src = android_gc2canvas(gc)->getDevice()->accessBitmap(false);
+ SkAutoLockPixels alp(src);
+ if (!src.getPixels()) {
+ return 0;
+ }
+
+ PassRefPtr<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());
+
+ 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;
+
+ unsigned srcPixelsPerRow = src.rowBytesAsPixels();
+ unsigned destBytesPerRow = 4 * rect.width();
+
+ const SkPMColor* srcRows = src.getAddr32(originx, originy);
+ unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ // ugh, it appears they want unpremultiplied pixels
+ SkColor c = SkUnPreMultiply::PMColorToColor(srcRows[x]);
+ int basex = x * 4;
+ destRows[basex + 0] = SkColorGetR(c);
+ destRows[basex + 1] = SkColorGetG(c);
+ destRows[basex + 2] = SkColorGetB(c);
+ destRows[basex + 3] = SkColorGetA(c);
+ }
+ srcRows += srcPixelsPerRow;
+ destRows += destBytesPerRow;
+ }
+ return result;
+}
+
+void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ GraphicsContext* gc = this->context();
+ if (!gc) {
+ return;
+ }
+
+ const SkBitmap& dst = android_gc2canvas(gc)->getDevice()->accessBitmap(true);
+ SkAutoLockPixels alp(dst);
+ if (!dst.getPixels()) {
+ return;
+ }
+
+ 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;
+
+ unsigned srcBytesPerRow = 4 * source->width();
+ unsigned dstPixelsPerRow = dst.rowBytesAsPixels();
+
+ 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++) {
+ int basex = x * 4;
+ dstRows[x] = SkPackARGB32(srcRows[basex + 3],
+ srcRows[basex + 0],
+ srcRows[basex + 1],
+ srcRows[basex + 2]);
+ }
+ dstRows += dstPixelsPerRow;
+ srcRows += srcBytesPerRow;
+ }
+}
+
+
+String ImageBuffer::toDataURL(const String&) const
+{
+ // leaving this unimplemented, until I understand what its for (and what it
+ // really is).
+ return "data:,"; // I think this means we couldn't make the data url
+}
+
+}
diff --git a/WebCore/platform/graphics/android/ImageBufferData.h b/WebCore/platform/graphics/android/ImageBufferData.h
new file mode 100644
index 0000000..7d8cd3b
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageBufferData.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
new file mode 100644
index 0000000..a6bf6c6
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "ImageDecoder.h"
+#include "ImageSource.h"
+#include "IntSize.h"
+#include "NotImplemented.h"
+#include "SharedBuffer.h"
+#include "PlatformString.h"
+
+#include "JavaSharedClient.h"
+
+#include "SkBitmapRef.h"
+#include "SkImageRef.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src);
+
+//#define TRACE_SUBSAMPLE_BITMAPS
+//#define TRACE_RLE_BITMAPS
+
+#include "SkImageRef_GlobalPool.h"
+#include "SkImageRef_ashmem.h"
+
+// made this up, so we don't waste a file-descriptor on small images, plus
+// we don't want to lose too much on the round-up to a page size (4K)
+#define MIN_ASHMEM_ALLOC_SIZE (32*1024)
+
+// don't use RLE for images smaller than this, since they incur a drawing cost
+// (and don't work as patterns yet) we only want to use RLE when we must
+#define MIN_RLE_ALLOC_SIZE (512*1024)
+
+static bool should_use_ashmem(const SkBitmap& bm) {
+ return bm.getSize() >= MIN_ASHMEM_ALLOC_SIZE;
+}
+
+/* Images larger than this should be subsampled. Using ashmem, the decoded
+ pixels will be purged as needed, so this value can be pretty large. Making
+ it too small hurts image quality (e.g. abc.com background). 2Meg works for
+ the sites I've tested, but if we hit important sites that need more, we
+ should try increasing it and see if it has negative impact on performance
+ (i.e. we end up thrashing because we need to keep decoding images that have
+ been purged.
+
+ Perhaps this value should be some fraction of the available RAM...
+*/
+static size_t computeMaxBitmapSizeForCache() {
+ return 2*1024*1024;
+}
+
+/* 8bit images larger than this should be recompressed in RLE, to reduce
+ on the imageref cache.
+
+ Downside: performance, since we have to decode/encode
+ and then rle-decode when we draw.
+*/
+static bool shouldReencodeAsRLE(const SkBitmap& bm) {
+ const SkBitmap::Config c = bm.config();
+ return (SkBitmap::kIndex8_Config == c || SkBitmap::kA8_Config == c)
+ &&
+ bm.width() >= 64 // narrower than this won't compress well in RLE
+ &&
+ bm.getSize() > MIN_RLE_ALLOC_SIZE;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class PrivateAndroidImageSourceRec : public SkBitmapRef {
+public:
+ PrivateAndroidImageSourceRec(const SkBitmap& bm, int origWidth,
+ int origHeight, int sampleSize)
+ : SkBitmapRef(bm), fSampleSize(sampleSize), fAllDataReceived(false) {
+ this->setOrigSize(origWidth, origHeight);
+ }
+
+ int fSampleSize;
+ bool fAllDataReceived;
+};
+
+using namespace android;
+
+namespace WebCore {
+
+class SharedBufferStream : public SkMemoryStream {
+public:
+ SharedBufferStream(SharedBuffer* buffer)
+ : SkMemoryStream(buffer->data(), buffer->size(), false) {
+ fBuffer = buffer;
+ buffer->ref();
+ }
+
+ virtual ~SharedBufferStream() {
+ // we can't necessarily call fBuffer->deref() here, as we may be
+ // in a different thread from webkit, and SharedBuffer is not
+ // threadsafe. Therefore we defer it until it can be executed in the
+ // webkit thread.
+// SkDebugf("-------- enqueue buffer %p for deref\n", fBuffer);
+ JavaSharedClient::EnqueueFunctionPtr(CallDeref, fBuffer);
+ }
+
+private:
+ // don't allow this to change our data. should not get called, but we
+ // override here just to be sure
+ virtual void setMemory(const void* data, size_t length, bool copyData) {
+ sk_throw();
+ }
+
+ // we share ownership of this with webkit
+ SharedBuffer* fBuffer;
+
+ // will be invoked in the webkit thread
+ static void CallDeref(void* buffer) {
+// SkDebugf("-------- call deref on buffer %p\n", buffer);
+ ((SharedBuffer*)buffer)->deref();
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+ImageSource::ImageSource() {
+ m_decoder.m_image = NULL;
+}
+
+ImageSource::~ImageSource() {
+ delete m_decoder.m_image;
+}
+
+bool ImageSource::initialized() const {
+ return m_decoder.m_image != NULL;
+}
+
+static int computeSampleSize(const SkBitmap& bitmap) {
+ const size_t maxSize = computeMaxBitmapSizeForCache();
+ size_t size = bitmap.getSize();
+ int sampleSize = 1;
+
+ while (size > maxSize) {
+ sampleSize <<= 1;
+ size >>= 2;
+ }
+
+#ifdef TRACE_SUBSAMPLE_BITMAPS
+ if (sampleSize > 1) {
+ SkDebugf("------- bitmap [%d %d] config=%d origSize=%d predictSize=%d sampleSize=%d\n",
+ bitmap.width(), bitmap.height(), bitmap.config(),
+ bitmap.getSize(), size, sampleSize);
+ }
+#endif
+ return sampleSize;
+}
+
+static SkPixelRef* convertToRLE(SkBitmap* bm, const void* data, size_t len) {
+ if (!shouldReencodeAsRLE(*bm)) {
+ return NULL;
+ }
+
+ SkBitmap tmp;
+
+ if (!SkImageDecoder::DecodeMemory(data, len, &tmp) || !tmp.getPixels()) {
+ return NULL;
+ }
+
+ SkPixelRef* ref = SkCreateRLEPixelRef(tmp);
+ if (NULL == ref) {
+ return NULL;
+ }
+
+#ifdef TRACE_RLE_BITMAPS
+ SkDebugf("---- reencode bitmap as RLE: [%d %d] encodeSize=%d\n",
+ tmp.width(), tmp.height(), len);
+#endif
+
+ bm->setConfig(SkBitmap::kRLE_Index8_Config, tmp.width(), tmp.height());
+ return ref;
+}
+
+void ImageSource::clearURL()
+{
+ m_decoder.m_url.reset();
+}
+
+void ImageSource::setURL(const String& url)
+{
+ if (url.startsWith("data:")) {
+ clearURL();
+ } else {
+ m_decoder.m_url.setUTF16(url.characters(), url.length());
+ }
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (NULL == m_decoder.m_image) {
+ SkBitmap tmp;
+
+ SkMemoryStream stream(data->data(), data->size(), false);
+ SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
+ SkAutoTDelete<SkImageDecoder> ad(codec);
+
+ if (!codec || !codec->decode(&stream, &tmp, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return;
+ }
+
+ int origW = tmp.width();
+ int origH = tmp.height();
+ int sampleSize = computeSampleSize(tmp);
+ if (sampleSize > 1) {
+ codec->setSampleSize(sampleSize);
+ stream.rewind();
+ if (!codec->decode(&stream, &tmp, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return;
+ }
+ }
+
+ m_decoder.m_image = new PrivateAndroidImageSourceRec(tmp, origW, origH,
+ sampleSize);
+
+// SkDebugf("----- started: [%d %d] %s\n", origW, origH, m_decoder.m_url.c_str());
+ }
+
+ PrivateAndroidImageSourceRec* decoder = m_decoder.m_image;
+ if (allDataReceived && !decoder->fAllDataReceived) {
+ decoder->fAllDataReceived = true;
+
+ SkBitmap* bm = &decoder->bitmap();
+ SkPixelRef* ref = convertToRLE(bm, data->data(), data->size());
+
+ if (NULL == ref) {
+ SkStream* strm = new SharedBufferStream(data);
+ // imageref now owns the stream object
+ if (should_use_ashmem(*bm)) {
+// SkDebugf("---- use ashmem for image [%d %d]\n", bm->width(), bm->height());
+ ref = new SkImageRef_ashmem(strm, bm->config(), decoder->fSampleSize);
+ } else {
+// SkDebugf("---- use globalpool for image [%d %d]\n", bm->width(), bm->height());
+ ref = new SkImageRef_GlobalPool(strm, bm->config(), decoder->fSampleSize);
+ }
+
+ // SkDebugf("----- allDataReceived [%d %d]\n", bm->width(), bm->height());
+ }
+
+ // we promise to never change the pixels (makes picture recording fast)
+ ref->setImmutable();
+ // give it the URL if we have one
+ ref->setURI(m_decoder.m_url);
+ // our bitmap is now the only owner of the imageref
+ bm->setPixelRef(ref)->unref();
+
+// SkDebugf("---- finished: [%d %d] %s\n", bm->width(), bm->height(), ref->getURI());
+ }
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ return m_decoder.m_image != NULL;
+}
+
+IntSize ImageSource::size() const
+{
+ if (m_decoder.m_image) {
+ return IntSize(m_decoder.m_image->origWidth(), m_decoder.m_image->origHeight());
+ }
+ return IntSize(0, 0);
+}
+
+int ImageSource::repetitionCount()
+{
+ return 1;
+ // A property with value 0 means loop forever.
+}
+
+size_t ImageSource::frameCount() const
+{
+ // i.e. 0 frames if we're not decoded, or 1 frame if we are
+ return m_decoder.m_image != NULL;
+}
+
+SkBitmapRef* ImageSource::createFrameAtIndex(size_t index)
+{
+ SkASSERT(index == 0);
+ SkASSERT(m_decoder.m_image != NULL);
+ m_decoder.m_image->ref();
+ return m_decoder.m_image;
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ SkASSERT(index == 0);
+ float duration = 0;
+
+ // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
+ // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
+ // a duration of <= 10 ms. See gfxImageFrame::GetTimeout in Gecko or Radar 4051389 for more.
+ if (duration <= 0.010f)
+ duration = 0.100f;
+ return duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ SkASSERT(0 == index);
+
+ if (NULL == m_decoder.m_image)
+ return true; // if we're not sure, assume the worse-case
+ const PrivateAndroidImageSourceRec& decoder = *m_decoder.m_image;
+ // if we're 16bit, we know even without all the data available
+ if (decoder.bitmap().getConfig() == SkBitmap::kRGB_565_Config)
+ return false;
+
+ if (!decoder.fAllDataReceived)
+ return true; // if we're not sure, assume the worse-case
+
+ return !decoder.bitmap().isOpaque();
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ SkASSERT(0 == index);
+ return m_decoder.m_image && m_decoder.m_image->fAllDataReceived;
+}
+
+void ImageSource::clear()
+{
+ // do nothing, since the cache is managed elsewhere
+}
+
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
+{
+ // for now, all (1) of our frames are the same size
+ return this->size();
+}
+
+}
diff --git a/WebCore/platform/graphics/android/PathAndroid.cpp b/WebCore/platform/graphics/android/PathAndroid.cpp
new file mode 100644
index 0000000..819173b
--- /dev/null
+++ b/WebCore/platform/graphics/android/PathAndroid.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "Path.h"
+#include "FloatRect.h"
+#include "AffineTransform.h"
+
+#include "SkPath.h"
+#include "SkRegion.h"
+
+#include "android_graphics.h"
+
+namespace WebCore {
+
+Path::Path()
+{
+ m_path = new SkPath;
+// m_path->setFlags(SkPath::kWinding_FillType);
+}
+
+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
+{
+ SkRegion rgn, clip;
+
+ int x = (int)floorf(point.x());
+ int y = (int)floorf(point.y());
+ clip.setRect(x, y, x + 1, y + 1);
+
+ SkPath::FillType ft = m_path->getFillType(); // save
+ m_path->setFillType(rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
+
+ bool contains = rgn.setPath(*m_path, clip);
+
+ m_path->setFillType(ft); // restore
+ return contains;
+}
+
+void Path::translate(const FloatSize& size)
+{
+ m_path->offset(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+}
+
+FloatRect Path::boundingRect() const
+{
+ SkRect r;
+
+ m_path->computeBounds(&r, SkPath::kExact_BoundsType);
+ return FloatRect( SkScalarToFloat(r.fLeft),
+ SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.width()),
+ SkScalarToFloat(r.height()));
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path->moveTo(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()));
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ m_path->lineTo(SkFloatToScalar(p.x()), SkFloatToScalar(p.y()));
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
+{
+ m_path->quadTo( SkFloatToScalar(cp.x()), SkFloatToScalar(cp.y()),
+ SkFloatToScalar(ep.x()), SkFloatToScalar(ep.y()));
+}
+
+void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep)
+{
+ m_path->cubicTo(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()),
+ SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()),
+ SkFloatToScalar(ep.x()), SkFloatToScalar(ep.y()));
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ m_path->arcTo(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()),
+ SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()),
+ SkFloatToScalar(radius));
+}
+
+void Path::closeSubpath()
+{
+ m_path->close();
+}
+
+static const float gPI = 3.14159265f;
+static const float g2PI = 6.28318531f;
+static const float g180OverPI = 57.29577951308f;
+
+static float fast_mod(float angle, float max) {
+ if (angle >= max || angle <= -max) {
+ angle = fmodf(angle, max);
+ }
+ return angle;
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea,
+ bool clockwise) {
+ SkScalar cx = SkFloatToScalar(p.x());
+ SkScalar cy = SkFloatToScalar(p.y());
+ SkScalar radius = SkFloatToScalar(r);
+
+ SkRect oval;
+ oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
+
+ float sweep = ea - sa;
+ bool prependOval = false;
+
+ /* Note if clockwise and the sign of the sweep disagree. This particular
+ logic was deduced from http://canvex.lazyilluminati.com/misc/arc.html
+ */
+ if (clockwise && (sweep > 0 || sweep < -g2PI)) {
+ sweep = fmodf(sweep, g2PI) - g2PI;
+ } else if (!clockwise && (sweep < 0 || sweep > g2PI)) {
+ sweep = fmodf(sweep, g2PI) + g2PI;
+ }
+
+ // If the abs(sweep) >= 2PI, then we need to add a circle before we call
+ // arcTo, since it treats the sweep mod 2PI. We don't have a prepend call,
+ // so we just remember this, and at the end create a new path with an oval
+ // and our current path, and then swap then.
+ //
+ if (sweep >= g2PI || sweep <= -g2PI) {
+ prependOval = true;
+// SkDebugf("addArc sa=%g ea=%g cw=%d sweep %g treat as circle\n", sa, ea, clockwise, sweep);
+
+ // now reduce sweep to just the amount we need, so that the current
+ // point is left where the caller expects it.
+ sweep = fmodf(sweep, g2PI);
+ }
+
+ sa = fast_mod(sa, g2PI);
+ SkScalar startDegrees = SkFloatToScalar(sa * g180OverPI);
+ SkScalar sweepDegrees = SkFloatToScalar(sweep * g180OverPI);
+
+// SkDebugf("addArc sa=%g ea=%g cw=%d sweep=%g ssweep=%g\n", sa, ea, clockwise, sweep, SkScalarToFloat(sweepDegrees));
+ m_path->arcTo(oval, startDegrees, sweepDegrees, false);
+
+ if (prependOval) {
+ SkPath tmp;
+ tmp.addOval(oval);
+ tmp.addPath(*m_path);
+ m_path->swap(tmp);
+ }
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_path->addRect(r);
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_path->addOval(r);
+}
+
+void Path::clear()
+{
+ m_path->reset();
+}
+
+static FloatPoint* setfpts(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 elem;
+ FloatPoint fpts[3];
+
+ for (;;)
+ {
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ elem.type = PathElementMoveToPoint;
+ elem.points = setfpts(fpts, &pts[0], 1);
+ break;
+ case SkPath::kLine_Verb:
+ elem.type = PathElementAddLineToPoint;
+ elem.points = setfpts(fpts, &pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ elem.type = PathElementAddQuadCurveToPoint;
+ elem.points = setfpts(fpts, &pts[1], 2);
+ break;
+ case SkPath::kCubic_Verb:
+ elem.type = PathElementAddCurveToPoint;
+ elem.points = setfpts(fpts, &pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ elem.type = PathElementCloseSubpath;
+ elem.points = NULL;
+ break;
+ case SkPath::kDone_Verb:
+ return;
+ }
+ function(info, &elem);
+ }
+}
+
+void Path::transform(const AffineTransform& xform)
+{
+ m_path->transform(xform);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/PatternAndroid.cpp b/WebCore/platform/graphics/android/PatternAndroid.cpp
new file mode 100644
index 0000000..2840faa
--- /dev/null
+++ b/WebCore/platform/graphics/android/PatternAndroid.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "Pattern.h"
+
+#include "android_graphics.h"
+#include "GraphicsContext.h"
+#include "SkBitmapRef.h"
+#include "SkCanvas.h"
+#include "SkColorShader.h"
+#include "SkShader.h"
+#include "SkPaint.h"
+
+namespace WebCore {
+
+static SkShader::TileMode toTileMode(bool doRepeat) {
+ return doRepeat ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+}
+
+SkShader* Pattern::createPlatformPattern(const AffineTransform& transform) const
+{
+ SkBitmapRef* ref = tileImage()->nativeImageForCurrentFrame();
+ SkShader* s = SkShader::CreateBitmapShader(ref->bitmap(),
+ toTileMode(m_repeatX),
+ toTileMode(m_repeatY));
+
+ // TODO: do I treat transform as a local matrix???
+ return s;
+}
+
+} //namespace
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
new file mode 100644
index 0000000..b13f45f
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "Node.h"
+#include "PlatformGraphicsContext.h"
+#include "SkCanvas.h"
+
+namespace WebCore {
+
+PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas, WTF::Vector<Container>* buttons)
+ : mCanvas(canvas), m_deleteCanvas(false), m_buttons(buttons)
+{
+}
+
+PlatformGraphicsContext::PlatformGraphicsContext() : m_deleteCanvas(true)
+{
+ mCanvas = new SkCanvas;
+ // Since this is our own private SkCanvas, and has no relation to a picture
+ // storing button references would be meaningless.
+ m_buttons = NULL;
+}
+
+PlatformGraphicsContext::~PlatformGraphicsContext()
+{
+ if (m_deleteCanvas) {
+// printf("-------------------- deleting offscreen canvas\n");
+ delete mCanvas;
+ }
+}
+
+void PlatformGraphicsContext::storeButtonInfo(Node* node, const IntRect& r)
+{
+ if (m_buttons == NULL)
+ return;
+ // Check to see if we already have a Container for this node. If so, update
+ // it with the new rectangle and make the new recording canvas reference
+ // its picture.
+ Container* end = m_buttons->end();
+ for (Container* ptr = m_buttons->begin(); ptr != end; ptr++) {
+ if (ptr->matches(node)) {
+ mCanvas->drawPicture(*(ptr->picture()));
+ ptr->setRect(r);
+ return;
+ }
+ }
+ // We did not have a Container representing this node, so create a new one.
+ Container container(node, r);
+ // Place a reference to our subpicture in the Picture.
+ mCanvas->drawPicture(*(container.picture()));
+ // Keep track of the information about the button.
+ m_buttons->append(container);
+}
+
+} // WebCore
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
new file mode 100644
index 0000000..dce8ef3
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef platform_graphics_context_h
+#define platform_graphics_context_h
+
+#include "IntRect.h"
+#include "RenderSkinAndroid.h"
+#include "RenderSkinButton.h"
+#include "SkCanvas.h"
+#include "SkPicture.h"
+#include "SkTDArray.h"
+
+class SkCanvas;
+class WebCore::Node;
+
+class Container {
+public:
+ Container(WebCore::Node* node, const WebCore::IntRect& r)
+ : m_node(node), m_rect(r), m_state(WebCore::RenderSkinAndroid::kDisabled)
+ {
+ m_picture = new SkPicture;
+ }
+
+ ~Container()
+ {
+ m_picture->unref();
+ }
+
+ Container& operator=(const Container& src)
+ {
+ if (this != &src) {
+ m_node = src.m_node;
+ if (m_picture)
+ m_picture->unref();
+ m_picture = src.m_picture;
+ m_picture->ref();
+ m_rect = src.m_rect;
+ m_state = WebCore::RenderSkinAndroid::kDisabled;
+ }
+ return *this;
+ }
+
+ Container(const Container& src)
+ {
+ m_node = src.m_node;
+ m_picture = src.m_picture;
+ m_picture->ref();
+ m_rect = src.m_rect;
+ m_state = WebCore::RenderSkinAndroid::kDisabled;
+ }
+
+ // m_picture has a ref count of 1 to begin with. It will increase each time
+ // m_picture is referenced by another picture. When the other pictures are
+ // deleted, the ref count gets decremented. If the ref count is one, then
+ // no other pictures reference this one, so the button is no longer being
+ // used, and therefore can be removed.
+ bool canBeRemoved()
+ {
+ return m_picture->getRefCnt() == 1;
+ }
+
+ bool matches(const WebCore::Node* match) { return m_node == match; }
+
+ const WebCore::Node* node() const { return m_node; }
+
+ // Provide a pointer to our SkPicture.
+ SkPicture* picture() { return m_picture; }
+
+ WebCore::IntRect rect() { return m_rect; }
+
+ // Update the rectangle with a new rectangle, as the positioning of this
+ // button may have changed due to a new layout. If it is a new rectangle,
+ // set its state to disabled, so that it will be redrawn when we cycle
+ // through the list of buttons.
+ void setRect(WebCore::IntRect r)
+ {
+ if (m_rect != r) {
+ m_rect = r;
+ m_state = WebCore::RenderSkinAndroid::kDisabled;
+ }
+ }
+
+ // Update the focus state of this button, depending on whether it
+ // corresponds to the focused node passed in. If its state has changed,
+ // re-record to the subpicture, so the master picture will reflect the
+ // change.
+ void updateFocusState(WebCore::RenderSkinAndroid::State state)
+ {
+ if (state == m_state)
+ return;
+ // If this button is being told to draw focused, but it is already in a
+ // pressed state, leave it in the pressed state, to show that it is
+ // being followed.
+ if (m_state == WebCore::RenderSkinAndroid::kPressed &&
+ state == WebCore::RenderSkinAndroid::kFocused)
+ return;
+ m_state = state;
+ SkCanvas* canvas = m_picture->beginRecording(m_rect.width(), m_rect.height());
+ WebCore::RenderSkinButton::Draw(canvas, m_rect, state);
+ m_picture->endRecording();
+ }
+private:
+ // Only used for comparison, since after it is stored it will be transferred
+ // to the UI thread.
+ WebCore::Node* m_node;
+ // The rectangle representing the bounds of the button.
+ WebCore::IntRect m_rect;
+ // An SkPicture that, thanks to storeButtonInfo, is pointed to by the master
+ // picture, so that we can rerecord this button without rerecording the
+ // world.
+ SkPicture* m_picture;
+ // The state of the button - Currently kFocused or kNormal (and kDisabled
+ // as an initial value), but could be expanded to include other states.
+ WebCore::RenderSkinAndroid::State m_state;
+};
+
+namespace WebCore {
+
+ class GraphicsContext;
+
+class PlatformGraphicsContext {
+public:
+ PlatformGraphicsContext();
+ // Pass in a recording canvas, and an array of button information to be
+ // updated.
+ PlatformGraphicsContext(SkCanvas* canvas, WTF::Vector<Container>* buttons);
+ ~PlatformGraphicsContext();
+
+ void setupFillPaint(GraphicsContext*, SkPaint*);
+ void setupStrokePaint(GraphicsContext*, SkPaint*);
+
+ SkCanvas* mCanvas;
+
+ bool deleteUs() const { return m_deleteCanvas; }
+ // If our graphicscontext has a button list, add a new container for the
+ // nod/rect, and record a new subpicture for this node/button in the current
+ // mCanvas
+ void storeButtonInfo(Node* node, const IntRect& r);
+private:
+ bool m_deleteCanvas;
+ WTF::Vector<Container>* m_buttons;
+};
+
+}
+#endif
+
diff --git a/WebCore/platform/graphics/android/SkBitmapRef.h b/WebCore/platform/graphics/android/SkBitmapRef.h
new file mode 100644
index 0000000..094102b
--- /dev/null
+++ b/WebCore/platform/graphics/android/SkBitmapRef.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SkBitmapRef_DEFINED
+#define SkBitmapRef_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkBitmap.h"
+
+class SkBitmapRef : public SkRefCnt {
+public:
+ SkBitmapRef() : fOrigWidth(0), fOrigHeight(0), fAccessed(false) {}
+ explicit SkBitmapRef(const SkBitmap& src)
+ : fBitmap(src),
+ fOrigWidth(src.width()),
+ fOrigHeight(src.height()),
+ fAccessed(false) {}
+
+ const SkBitmap& bitmap() const { return fBitmap; }
+ SkBitmap& bitmap() { return fBitmap; }
+
+ int origWidth() const { return fOrigWidth; }
+ int origHeight() const { return fOrigHeight; }
+
+ void setOrigSize(int width, int height) {
+ fOrigWidth = width;
+ fOrigHeight = height;
+ }
+ // return true if this is not the first access
+ // mark it true so all subsequent calls return true
+ bool accessed() { bool result = fAccessed;
+ fAccessed = true; return result; }
+
+private:
+ SkBitmap fBitmap;
+ int fOrigWidth, fOrigHeight;
+ bool fAccessed;
+};
+
+#endif
diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp
new file mode 100644
index 0000000..2bc0c8f
--- /dev/null
+++ b/WebCore/platform/graphics/android/android_graphics.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 "android_graphics.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src)
+{
+ dst->set(SkIntToScalar(src.x()), SkIntToScalar(src.y()));
+ return dst;
+}
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src)
+{
+ dst->set(SkFloatToScalar(src.x()), SkFloatToScalar(src.y()));
+ return dst;
+}
+
+SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src)
+{
+ dst->set(SkIntToScalar(src.x()),
+ SkIntToScalar(src.y()),
+ SkIntToScalar(src.x() + src.width()),
+ SkIntToScalar(src.y() + src.height()));
+ return dst;
+}
+
+SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src)
+{
+ dst->set(src.x(), src.y(),
+ src.x() + src.width(),
+ src.y() + src.height());
+ return dst;
+}
+
+SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src)
+{
+ dst->set(SkFloatToScalar(src.x()),
+ SkFloatToScalar(src.y()),
+ SkFloatToScalar(src.x() + src.width()),
+ SkFloatToScalar(src.y() + src.height()));
+ return dst;
+}
+
+SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x())),
+ SkScalarRound(SkFloatToScalar(src.y())),
+ SkScalarRound(SkFloatToScalar(src.x() + src.width())),
+ SkScalarRound(SkFloatToScalar(src.y() + src.height())));
+ return dst;
+}
+
+SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
+ float sx, float sy)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
+ SkScalarRound(SkFloatToScalar(src.y() * sy)),
+ SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
+ SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
+ return dst;
+}
+
+static const struct CompositOpToPorterDuffMode {
+ uint8_t mCompositOp;
+ uint8_t mPorterDuffMode;
+} gMapCompositOpsToPorterDuffModes[] = {
+ { WebCore::CompositeClear, SkPorterDuff::kClear_Mode },
+ { WebCore::CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
+ { WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
+ { WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
+ { WebCore::CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode },
+ { WebCore::CompositeDestinationOver, SkPorterDuff::kDstOver_Mode },
+ { WebCore::CompositeDestinationIn, SkPorterDuff::kDstIn_Mode },
+ { WebCore::CompositeDestinationOut, SkPorterDuff::kDstOut_Mode },
+ { WebCore::CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode },
+ { WebCore::CompositeXOR, SkPorterDuff::kXor_Mode },
+ { WebCore::CompositePlusDarker, SkPorterDuff::kDarken_Mode },
+ { WebCore::CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { WebCore::CompositePlusLighter, SkPorterDuff::kLighten_Mode }
+};
+
+SkPorterDuff::Mode android_convert_compositeOp(WebCore::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 CompositOperator %d\n", op));
+ return SkPorterDuff::kSrcOver_Mode; // fall-back
+}
+
+SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule rule)
+{
+ // stretch == clamp
+ // repeat == repeat
+ // RoundTile???
+
+ return WebCore::Image::RepeatTile == rule ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
+{
+ SkASSERT(component == (uint8_t)component);
+ return (component * scale + 0x8000) >> 16;
+}
+
+// move this guy into SkColor.h
+static 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));
+}
+
+WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm)
+{
+ SkColor c = SkPMColorToColor(pm);
+
+ // need the cast to find the right constructor
+ return WebCore::Color((int)SkColorGetR(c), (int)SkColorGetG(c),
+ (int)SkColorGetB(c), (int)SkColorGetA(c));
+}
+
+const static SkColor focusOuterColors[] = {
+ SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal focus ring select
+ SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake focus ring select, for phone, email, text
+ SkColorSetARGB(0xff, 0xb0, 0x16, 0x00), // invalid focus ring color
+ SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal focus ring pressed
+ SkColorSetARGB(0xff, 0x36, 0xc0, 0x00) // fake focus ring pressed
+};
+
+const static SkColor focusInnerColors[] = {
+ SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal focus ring select
+ SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake focus ring select, for phone, email, text
+ SkColorSetARGB(0xff, 0xd9, 0x2c, 0x00), // invalid focus ring color
+ SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal focus ring pressed
+ SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00) // fake focus ring pressed
+};
+
+const static SkColor focusPressedColors[] = {
+ SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal focus ring pressed
+ SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00) // fake focus ring pressed
+};
+
+#define FOCUS_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
+#define FOCUS_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
+#define FOCUS_RING_OUTER_OUTSET 2 // used to inflate rects added to region
+
+void FocusRing::DrawRing(SkCanvas* canvas,
+ const Vector<WebCore::IntRect>& rects, Flavor flavor)
+{
+ unsigned rectCount = rects.size();
+ SkRegion rgn;
+ SkPath path;
+ for (unsigned i = 0; i < rectCount; i++)
+ {
+ SkIRect r;
+
+ android_setrect(&r, rects[i]);
+ r.inset(-FOCUS_RING_OUTER_OUTSET, -FOCUS_RING_OUTER_OUTSET);
+ rgn.op(r, SkRegion::kUnion_Op);
+ }
+ rgn.getBoundaryPath(&path);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setPathEffect(new SkCornerPathEffect(FOCUS_RING_ROUNDEDNESS))->unref();
+ if (flavor >= NORMAL_ANIMATING) { // pressed
+ paint.setColor(focusPressedColors[flavor - NORMAL_ANIMATING]);
+ canvas->drawPath(path, paint);
+ }
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(FOCUS_RING_OUTER_DIAMETER);
+ paint.setColor(focusOuterColors[flavor]);
+ canvas->drawPath(path, paint);
+ paint.setStrokeWidth(FOCUS_RING_INNER_DIAMETER);
+ paint.setColor(focusInnerColors[flavor]);
+ canvas->drawPath(path, paint);
+}
+
+
diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h
new file mode 100644
index 0000000..21492cf
--- /dev/null
+++ b/WebCore/platform/graphics/android/android_graphics.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2007, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef android_graphics_DEFINED
+#define android_graphics_DEFINED
+
+#include "Color.h"
+#include "Image.h"
+#include "wtf/Vector.h"
+
+#include "SkColor.h"
+#include "SkPorterDuff.h"
+#include "SkScalar.h"
+#include "SkShader.h"
+
+class SkCanvas;
+struct SkPoint;
+struct SKRect;
+
+namespace WebCore {
+ class FloatRect;
+ class IntPoint;
+ class IntRect;
+ class GraphicsContext;
+}
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src);
+SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src);
+SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src);
+SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src);
+SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src);
+SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src);
+SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
+ float sx, float sy);
+
+SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator);
+SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule);
+
+WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm);
+
+SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc);
+
+// Data and methods for focus rings
+
+// used to inflate node cache entry
+#define FOCUS_RING_HIT_TEST_RADIUS 5
+
+// used to inval rectangle enclosing pressed state of focus ring
+#define FOCUS_RING_OUTER_DIAMETER SkFixedToScalar(SkIntToFixed(13)>>2) // 13/4 == 3.25
+
+struct FocusRing {
+public:
+ enum Flavor {
+ NORMAL_FLAVOR,
+ FAKE_FLAVOR,
+ INVALID_FLAVOR,
+ NORMAL_ANIMATING,
+ FAKE_ANIMATING,
+ ANIMATING_COUNT = 2
+ };
+
+ static void DrawRing(SkCanvas* ,
+ const Vector<WebCore::IntRect>& rects, Flavor );
+};
+
+#endif
+
diff --git a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp b/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp
new file mode 100644
index 0000000..0f2fccd
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp
@@ -0,0 +1,281 @@
+/*
+ *
+ * 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 "AffineTransform.h"
+
+#include "IntRect.h"
+#include "FloatRect.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+AffineTransform::AffineTransform()
+{
+ cairo_matrix_init_identity(&m_transform);
+}
+
+AffineTransform::AffineTransform(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)
+{
+ m_transform = matrix;
+}
+
+void AffineTransform::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
+{
+ *x2 = x;
+ *y2 = y;
+ cairo_matrix_transform_point(&m_transform, x2, y2);
+}
+
+IntRect AffineTransform::mapRect(const IntRect &rect) const
+{
+ FloatRect floatRect(rect);
+ FloatRect enclosingFloatRect = this->mapRect(floatRect);
+
+ return enclosingIntRect(enclosingFloatRect);
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+{
+ double rectMinX = rect.x();
+ double rectMaxX = rect.x() + rect.width();
+ double rectMinY = rect.y();
+ double rectMaxY = rect.y() + rect.height();
+
+ double px = rectMinX;
+ double py = rectMinY;
+ cairo_matrix_transform_point(&m_transform, &px, &py);
+
+ double enclosingRectMinX = px;
+ double enclosingRectMinY = py;
+ double enclosingRectMaxX = px;
+ double enclosingRectMaxY = py;
+
+ px = rectMaxX;
+ py = rectMinY;
+ cairo_matrix_transform_point(&m_transform, &px, &py);
+ if (px < enclosingRectMinX)
+ enclosingRectMinX = px;
+ else if (px > enclosingRectMaxX)
+ enclosingRectMaxX = px;
+ if (py < enclosingRectMinY)
+ enclosingRectMinY = py;
+ else if (py > enclosingRectMaxY)
+ enclosingRectMaxY = py;
+
+ px = rectMaxX;
+ py = rectMaxY;
+ cairo_matrix_transform_point(&m_transform, &px, &py);
+ if (px < enclosingRectMinX)
+ enclosingRectMinX = px;
+ else if (px > enclosingRectMaxX)
+ enclosingRectMaxX = px;
+ if (py < enclosingRectMinY)
+ enclosingRectMinY = py;
+ else if (py > enclosingRectMaxY)
+ enclosingRectMaxY = py;
+
+ px = rectMinX;
+ py = rectMaxY;
+ cairo_matrix_transform_point(&m_transform, &px, &py);
+ if (px < enclosingRectMinX)
+ enclosingRectMinX = px;
+ else if (px > enclosingRectMaxX)
+ enclosingRectMaxX = px;
+ if (py < enclosingRectMinY)
+ enclosingRectMinY = py;
+ else if (py > enclosingRectMaxY)
+ enclosingRectMaxY = py;
+
+
+ double enclosingRectWidth = enclosingRectMaxX - enclosingRectMinX;
+ double enclosingRectHeight = enclosingRectMaxY - enclosingRectMinY;
+
+ return FloatRect(enclosingRectMinX, enclosingRectMinY, enclosingRectWidth, enclosingRectHeight);
+}
+
+bool AffineTransform::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
+{
+ return m_transform.xx;
+}
+
+void AffineTransform::setA(double a)
+{
+ m_transform.xx = a;
+}
+
+double AffineTransform::b() const
+{
+ return m_transform.yx;
+}
+
+void AffineTransform::setB(double b)
+{
+ m_transform.yx = b;
+}
+
+double AffineTransform::c() const
+{
+ return m_transform.xy;
+}
+
+void AffineTransform::setC(double c)
+{
+ m_transform.xy = c;
+}
+
+double AffineTransform::d() const
+{
+ return m_transform.yy;
+}
+
+void AffineTransform::setD(double d)
+{
+ m_transform.yy = d;
+}
+
+double AffineTransform::e() const
+{
+ return m_transform.x0;
+}
+
+void AffineTransform::setE(double e)
+{
+ m_transform.x0 = e;
+}
+
+double AffineTransform::f() const
+{
+ return m_transform.y0;
+}
+
+void AffineTransform::setF(double f)
+{
+ m_transform.y0 = f;
+}
+
+void AffineTransform::reset()
+{
+ cairo_matrix_init_identity(&m_transform);
+}
+
+AffineTransform &AffineTransform::scale(double sx, double sy)
+{
+ cairo_matrix_scale(&m_transform, sx, sy);
+ return *this;
+}
+
+AffineTransform &AffineTransform::rotate(double d)
+{
+ cairo_matrix_rotate(&m_transform, d * deg2rad);
+ return *this;
+}
+
+AffineTransform &AffineTransform::translate(double tx, double ty)
+{
+ cairo_matrix_translate(&m_transform, tx, ty);
+ return *this;
+}
+
+AffineTransform &AffineTransform::shear(double sx, double sy)
+{
+ cairo_matrix_t shear;
+ cairo_matrix_init(&shear, 1, sy, sx, 1, 0, 0);
+
+ cairo_matrix_t result;
+ cairo_matrix_multiply(&result, &shear, &m_transform);
+ m_transform = result;
+
+ return *this;
+}
+
+double AffineTransform::det() const
+{
+ return m_transform.xx * m_transform.yy - m_transform.xy * m_transform.yx;
+}
+
+AffineTransform AffineTransform::inverse() const
+{
+ if (!isInvertible()) return AffineTransform();
+
+ cairo_matrix_t result = m_transform;
+ cairo_matrix_invert(&result);
+ return AffineTransform(result);
+}
+
+AffineTransform::operator cairo_matrix_t() const
+{
+ return m_transform;
+}
+
+bool AffineTransform::operator== (const AffineTransform &m2) const
+{
+ return ((m_transform.xx == m2.m_transform.xx)
+ && (m_transform.yy == m2.m_transform.yy)
+ && (m_transform.xy == m2.m_transform.xy)
+ && (m_transform.yx == m2.m_transform.yx)
+ && (m_transform.x0 == m2.m_transform.x0)
+ && (m_transform.y0 == m2.m_transform.y0));
+
+}
+
+AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+{
+ cairo_matrix_t result;
+ cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
+ m_transform = result;
+
+ return *this;
+}
+
+AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+{
+ cairo_matrix_t result;
+ cairo_matrix_multiply(&result, &m_transform, &m2.m_transform);
+ return result;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/cairo/CairoPath.h b/WebCore/platform/graphics/cairo/CairoPath.h
new file mode 100644
index 0000000..b761ce6
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/CairoPath.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+
+ 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
+ aint 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 CairoPath_h
+#define CairoPath_h
+
+#include <cairo.h>
+
+namespace WebCore {
+
+ // This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API.
+ struct CairoPath {
+ cairo_t* m_cr;
+
+ CairoPath()
+ {
+ static cairo_surface_t* pathSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
+ m_cr = cairo_create(pathSurface);
+ }
+
+ ~CairoPath()
+ {
+ cairo_destroy(m_cr);
+ }
+ };
+
+} // namespace WebCore
+
+#endif // CairoPath_h
diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp
new file mode 100644
index 0000000..9da9426
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/FontCairo.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+
+ font->setFont(cr);
+
+ GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
+
+ float offset = point.x();
+ for (int i = 0; i < numGlyphs; i++) {
+ glyphs[i].x = offset;
+ glyphs[i].y = point.y();
+ offset += glyphBuffer.advanceAt(from + i);
+ }
+
+ Color fillColor = context->fillColor();
+
+ // Text shadow, inspired by FontMac
+ IntSize shadowSize;
+ int shadowBlur = 0;
+ Color shadowColor;
+ bool hasShadow = context->textDrawingMode() == cTextFill &&
+ context->getShadow(shadowSize, shadowBlur, shadowColor);
+
+ // TODO: Blur support
+ if (hasShadow) {
+ // Disable graphics context shadows (not yet implemented) and paint them manually
+ context->clearShadow();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ cairo_save(cr);
+
+ float red, green, blue, alpha;
+ shadowFillColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+
+ cairo_translate(cr, shadowSize.width(), shadowSize.height());
+ cairo_show_glyphs(cr, glyphs, numGlyphs);
+
+ cairo_restore(cr);
+ }
+
+ if (context->textDrawingMode() & cTextFill) {
+ float red, green, blue, alpha;
+ fillColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+
+ cairo_show_glyphs(cr, glyphs, numGlyphs);
+ }
+
+ if (context->textDrawingMode() & cTextStroke) {
+ Color strokeColor = context->strokeColor();
+ float red, green, blue, alpha;
+ strokeColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+ cairo_glyph_path(cr, glyphs, numGlyphs);
+ cairo_set_line_width(cr, context->strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ // Re-enable the platform shadow we disabled earlier
+ if (hasShadow)
+ context->setShadow(shadowSize, shadowBlur, shadowColor);
+
+ cairo_restore(cr);
+}
+
+}
diff --git a/WebCore/platform/graphics/cairo/GradientCairo.cpp b/WebCore/platform/graphics/cairo/GradientCairo.cpp
new file mode 100644
index 0000000..7776424
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/GradientCairo.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+#include <cairo.h>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ if (m_gradient) {
+ cairo_pattern_destroy(m_gradient);
+ m_gradient = 0;
+ }
+}
+
+cairo_pattern_t* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ if (m_radial)
+ m_gradient = cairo_pattern_create_radial(m_p0.x(), m_p0.y(), m_r0, m_p1.x(), m_p1.y(), m_r1);
+ else
+ m_gradient = cairo_pattern_create_linear(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());
+
+ Vector<ColorStop>::iterator stopIterator = m_stops.begin();
+ while (stopIterator != m_stops.end()) {
+ cairo_pattern_add_color_stop_rgba(m_gradient, stopIterator->stop, stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
+ ++stopIterator;
+ }
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ cairo_t* cr = context->platformContext();
+
+ cairo_save(cr);
+ cairo_set_source(cr, platformGradient());
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+} //namespace
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
new file mode 100644
index 0000000..c403f44
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -0,0 +1,1104 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * 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 "GraphicsContext.h"
+
+#if PLATFORM(CAIRO)
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "FloatRect.h"
+#include "Font.h"
+#include "ImageBuffer.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "SimpleFontData.h"
+
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(GTK)
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+#elif PLATFORM(WIN)
+#include <cairo-win32.h>
+#endif
+#include "GraphicsContextPrivate.h"
+#include "GraphicsContextPlatformPrivateCairo.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+static inline void setColor(cairo_t* cr, const Color& col)
+{
+ float red, green, blue, alpha;
+ col.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+}
+
+// A fillRect helper
+static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col)
+{
+ setColor(cr, col);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_fill(cr);
+}
+
+static inline cairo_pattern_t* applySpreadMethod(cairo_pattern_t* pattern, GradientSpreadMethod spreadMethod)
+{
+ switch (spreadMethod) {
+ case SpreadMethodPad:
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD);
+ break;
+ case SpreadMethodReflect:
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REFLECT);
+ break;
+ case SpreadMethodRepeat:
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+ break;
+ default:
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_NONE);
+ break;
+ }
+ return pattern;
+}
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate)
+{
+ m_data->cr = cairo_reference(cr);
+ setPaintingDisabled(!cr);
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ destroyGraphicsContextPrivate(m_common);
+ delete m_data;
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ cairo_t* cr = platformContext();
+ cairo_matrix_t m;
+ cairo_get_matrix(cr, &m);
+ return m;
+}
+
+cairo_t* GraphicsContext::platformContext() const
+{
+ return m_data->cr;
+}
+
+void GraphicsContext::savePlatformState()
+{
+ cairo_save(m_data->cr);
+ m_data->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ cairo_restore(m_data->cr);
+ m_data->restore();
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ if (fillColor().alpha())
+ fillRectSourceOver(cr, rect, fillColor());
+
+ if (strokeStyle() != NoStroke) {
+ setColor(cr, strokeColor());
+ FloatRect r(rect);
+ r.inflate(-.5f);
+ cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
+ cairo_set_line_width(cr, 1.0);
+ cairo_stroke(cr);
+ }
+
+ cairo_restore(cr);
+}
+
+// FIXME: Now that this is refactored, it should be shared by all contexts.
+static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle style)
+{
+ // 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.
+ if (style == DottedStroke || style == DashedStroke) {
+ if (p1.x() == p2.x()) {
+ p1.setY(p1.y() + strokeWidth);
+ p2.setY(p2.y() - strokeWidth);
+ }
+ else {
+ p1.setX(p1.x() + strokeWidth);
+ p2.setX(p2.x() - strokeWidth);
+ }
+ }
+
+ if (static_cast<int>(strokeWidth) % 2) {
+ if (p1.x() == p2.x()) {
+ // We're a vertical line. Adjust our x.
+ p1.setX(p1.x() + 0.5);
+ p2.setX(p2.x() + 0.5);
+ }
+ else {
+ // We're a horizontal line. Adjust our y.
+ p1.setY(p1.y() + 0.5);
+ p2.setY(p2.y() + 0.5);
+ }
+ }
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ if (style == NoStroke)
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ float width = strokeThickness();
+ if (width < 1)
+ width = 1;
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ adjustLineToPixelBoundaries(p1, p2, width, style);
+ cairo_set_line_width(cr, width);
+
+ int patWidth = 0;
+ switch (style) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = static_cast<int>(width);
+ break;
+ case DashedStroke:
+ patWidth = 3*static_cast<int>(width);
+ break;
+ }
+
+ setColor(cr, strokeColor());
+
+ cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+
+ if (patWidth) {
+ // 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.
+ if (isVerticalLine) {
+ fillRectSourceOver(cr, FloatRect(p1.x() - width/2, p1.y() - width, width, width), strokeColor());
+ fillRectSourceOver(cr, FloatRect(p2.x() - width/2, p2.y(), width, width), strokeColor());
+ } else {
+ fillRectSourceOver(cr, FloatRect(p1.x() - width, p1.y() - width/2, width, width), strokeColor());
+ fillRectSourceOver(cr, FloatRect(p2.x(), p2.y() - width/2, width, width), strokeColor());
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*static_cast<int>(width);
+ int remainder = distance%patWidth;
+ int coverage = distance-remainder;
+ int numSegments = coverage/patWidth;
+
+ float patternOffset = 0;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0;
+ else {
+ bool evenNumberOfSegments = numSegments%2 == 0;
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder/2;
+ }
+ else
+ patternOffset = patWidth/2;
+ }
+ else if (!evenNumberOfSegments) {
+ if (remainder)
+ patternOffset = (patWidth - remainder)/2;
+ }
+ }
+
+ double dash = patWidth;
+ cairo_set_dash(cr, &dash, 1, patternOffset);
+ }
+
+ cairo_move_to(cr, p1.x(), p1.y());
+ cairo_line_to(cr, p2.x(), p2.y());
+
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ float yRadius = .5 * rect.height();
+ float xRadius = .5 * rect.width();
+ cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);
+ cairo_scale(cr, xRadius, yRadius);
+ cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI);
+ cairo_restore(cr);
+
+ if (fillColor().alpha()) {
+ setColor(cr, fillColor());
+ cairo_fill_preserve(cr);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ setColor(cr, strokeColor());
+ cairo_set_line_width(cr, strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ cairo_new_path(cr);
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled() || strokeStyle() == NoStroke)
+ return;
+
+ int x = rect.x();
+ int y = rect.y();
+ float w = rect.width();
+ float h = rect.height();
+ float scaleFactor = h / w;
+ float reverseScaleFactor = w / h;
+
+ float hRadius = w / 2;
+ float vRadius = h / 2;
+ float fa = startAngle;
+ float falen = fa + angleSpan;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ if (w != h)
+ cairo_scale(cr, 1., scaleFactor);
+
+ cairo_arc_negative(cr, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, -fa * M_PI/180, -falen * M_PI/180);
+
+ if (w != h)
+ cairo_scale(cr, 1., reverseScaleFactor);
+
+ float width = strokeThickness();
+ int patWidth = 0;
+
+ switch (strokeStyle()) {
+ case DottedStroke:
+ patWidth = static_cast<int>(width / 2);
+ break;
+ case DashedStroke:
+ patWidth = 3 * static_cast<int>(width / 2);
+ break;
+ default:
+ break;
+ }
+
+ setColor(cr, strokeColor());
+
+ if (patWidth) {
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance;
+ if (hRadius == vRadius)
+ distance = static_cast<int>((M_PI * hRadius) / 2.0);
+ else // We are elliptical and will have to estimate the distance
+ distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0);
+
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0;
+ else {
+ bool evenNumberOfSegments = numSegments % 2 == 0;
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2.0;
+ } else
+ patternOffset = patWidth / 2.0;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2.0;
+ }
+ }
+
+ double dash = patWidth;
+ cairo_set_dash(cr, &dash, 1, patternOffset);
+ }
+
+ cairo_stroke(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_save(cr);
+ cairo_set_antialias(cr, shouldAntialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+ cairo_move_to(cr, points[0].x(), points[0].y());
+ for (size_t i = 1; i < npoints; i++)
+ cairo_line_to(cr, points[i].x(), points[i].y());
+ cairo_close_path(cr);
+
+ if (fillColor().alpha()) {
+ setColor(cr, fillColor());
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_fill_preserve(cr);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ setColor(cr, strokeColor());
+ cairo_set_line_width(cr, strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ cairo_new_path(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::fillPath()
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ 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);
+ }
+ break;
+ case PatternColorSpace:
+ cairo_set_source(cr, m_common->state.fillPattern.get()->createPlatformPattern(getCTM()));
+ 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();
+ pattern = applySpreadMethod(pattern, spreadMethod());
+ cairo_set_source(cr, pattern);
+ cairo_clip(cr);
+ cairo_paint_with_alpha(cr, m_common->state.globalAlpha);
+ break;
+ }
+ cairo_restore(cr);
+}
+
+void GraphicsContext::strokePath()
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ 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);
+ }
+ break;
+ case PatternColorSpace:
+ cairo_set_source(cr, m_common->state.strokePattern.get()->createPlatformPattern(getCTM()));
+ 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);
+ break;
+ case GradientColorSpace:
+ cairo_pattern_t* pattern = m_common->state.strokeGradient.get()->platformGradient();
+ pattern = applySpreadMethod(pattern, spreadMethod());
+ cairo_set_source(cr, pattern);
+ 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);
+ break;
+ }
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawPath()
+{
+ fillPath();
+ strokePath();
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ fillPath();
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (color.alpha())
+ fillRectSourceOver(m_data->cr, rect, color);
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+ m_data->clip(rect);
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_push_group(cr);
+ cairo_new_path(cr);
+
+#if PLATFORM(GTK)
+ GdkRegion* reg = gdk_region_new();
+ for (unsigned i = 0; i < rectCount; i++) {
+ GdkRectangle rect = rects[i];
+ gdk_region_union_with_rect(reg, &rect);
+ }
+ gdk_cairo_region(cr, reg);
+ gdk_region_destroy(reg);
+
+ setColor(cr, color);
+ cairo_set_line_width(cr, 2.0f);
+ setPlatformStrokeStyle(DottedStroke);
+#else
+ int radius = (focusRingWidth() - 1) / 2;
+ for (unsigned i = 0; i < rectCount; i++)
+ addPath(Path::createRoundedRectangle(rects[i], FloatSize(radius, radius)));
+
+ // Force the alpha to 50%. This matches what the Mac does with outline rings.
+ Color ringColor(color.red(), color.green(), color.blue(), 127);
+ setColor(cr, ringColor);
+ cairo_set_line_width(cr, focusRingWidth());
+ setPlatformStrokeStyle(SolidStroke);
+#endif
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_stroke_preserve(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_fill(cr);
+
+ cairo_pop_group_to_source(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_paint(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ // This is a workaround for http://bugs.webkit.org/show_bug.cgi?id=15659
+ StrokeStyle savedStrokeStyle = strokeStyle();
+ setStrokeStyle(SolidStroke);
+
+ IntPoint endPoint = origin + IntSize(width, 0);
+ drawLine(origin, endPoint);
+
+ setStrokeStyle(savedStrokeStyle);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+
+ // Convention is green for grammar, red for spelling
+ // These need to become configurable
+ if (grammar)
+ cairo_set_source_rgb(cr, 0, 1, 0);
+ else
+ cairo_set_source_rgb(cr, 1, 0, 0);
+
+#if PLATFORM(GTK)
+ // We ignore most of the provided constants in favour of the platform style
+ pango_cairo_show_error_underline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
+#else
+ notImplemented();
+#endif
+
+ cairo_restore(cr);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ FloatRect result;
+ double x = frect.x();
+ double y = frect.y();
+ cairo_t* cr = m_data->cr;
+ cairo_user_to_device(cr, &x, &y);
+ x = round(x);
+ y = round(y);
+ cairo_device_to_user(cr, &x, &y);
+ result.setX(static_cast<float>(x));
+ result.setY(static_cast<float>(y));
+ x = frect.width();
+ y = frect.height();
+ cairo_user_to_device_distance(cr, &x, &y);
+ x = round(x);
+ y = round(y);
+ cairo_device_to_user_distance(cr, &x, &y);
+ result.setWidth(static_cast<float>(x));
+ result.setHeight(static_cast<float>(y));
+ return result;
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_translate(cr, x, y);
+ m_data->translate(x, y);
+}
+
+IntPoint GraphicsContext::origin()
+{
+ cairo_matrix_t matrix;
+ cairo_t* cr = m_data->cr;
+ cairo_get_matrix(cr, &matrix);
+ return IntPoint(static_cast<int>(matrix.x0), static_cast<int>(matrix.y0));
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& col)
+{
+ // Cairo contexts can't hold separate fill and stroke colors
+ // so we set them just before we actually fill or stroke
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& col)
+{
+ // Cairo contexts can't hold separate fill and stroke colors
+ // so we set them just before we actually fill or stroke
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_line_width(m_data->cr, strokeThickness);
+}
+
+void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle)
+{
+ static double dashPattern[] = {5.0, 5.0};
+ static double dotPattern[] = {1.0, 1.0};
+
+ if (paintingDisabled())
+ return;
+
+ switch (strokeStyle) {
+ case NoStroke:
+ // FIXME: is it the right way to emulate NoStroke?
+ cairo_set_line_width(m_data->cr, 0);
+ break;
+ case SolidStroke:
+ cairo_set_dash(m_data->cr, 0, 0, 0);
+ break;
+ case DottedStroke:
+ cairo_set_dash(m_data->cr, dotPattern, 2, 0);
+ break;
+ case DashedStroke:
+ cairo_set_dash(m_data->cr, dashPattern, 2, 0);
+ break;
+ }
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ notImplemented();
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
+ cairo_transform(cr, matrix);
+ m_data->concatCTM(transform);
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ clip(rect);
+
+ Path p;
+ FloatRect r(rect);
+ // Add outer ellipse
+ p.addEllipse(r);
+ // Add inner ellipse
+ r.inflate(-thickness);
+ p.addEllipse(r);
+ addPath(p);
+
+ cairo_t* cr = m_data->cr;
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ notImplemented();
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_push_group(cr);
+ m_data->layers.append(opacity);
+ m_data->beginTransparencyLayer();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_pop_group_to_source(cr);
+ cairo_paint_with_alpha(cr, m_data->layers.last());
+ m_data->layers.removeLast();
+ m_data->endTransparencyLayer();
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float width)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_set_line_width(cr, width);
+ strokePath();
+ cairo_restore(cr);
+}
+
+void GraphicsContext::setLineCap(LineCap lineCap)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT;
+ switch (lineCap) {
+ case ButtCap:
+ // no-op
+ break;
+ case RoundCap:
+ cairoCap = CAIRO_LINE_CAP_ROUND;
+ break;
+ case SquareCap:
+ cairoCap = CAIRO_LINE_CAP_SQUARE;
+ break;
+ }
+ cairo_set_line_cap(m_data->cr, cairoCap);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ cairo_set_dash(m_data->cr, dashes.data(), dashes.size(), dashOffset);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lineJoin)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER;
+ switch (lineJoin) {
+ case MiterJoin:
+ // no-op
+ break;
+ case RoundJoin:
+ cairoJoin = CAIRO_LINE_JOIN_ROUND;
+ break;
+ case BevelJoin:
+ cairoJoin = CAIRO_LINE_JOIN_BEVEL;
+ break;
+ }
+ cairo_set_line_join(m_data->cr, cairoJoin);
+}
+
+void GraphicsContext::setMiterLimit(float miter)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_miter_limit(m_data->cr, miter);
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_common->state.globalAlpha = alpha;
+}
+
+float GraphicsContext::getAlpha()
+{
+ return m_common->state.globalAlpha;
+}
+
+static inline cairo_operator_t toCairoOperator(CompositeOperator op)
+{
+ switch (op) {
+ case CompositeClear:
+ return CAIRO_OPERATOR_CLEAR;
+ case CompositeCopy:
+ return CAIRO_OPERATOR_SOURCE;
+ case CompositeSourceOver:
+ return CAIRO_OPERATOR_OVER;
+ case CompositeSourceIn:
+ return CAIRO_OPERATOR_IN;
+ case CompositeSourceOut:
+ return CAIRO_OPERATOR_OUT;
+ case CompositeSourceAtop:
+ return CAIRO_OPERATOR_ATOP;
+ case CompositeDestinationOver:
+ return CAIRO_OPERATOR_DEST_OVER;
+ case CompositeDestinationIn:
+ return CAIRO_OPERATOR_DEST_IN;
+ case CompositeDestinationOut:
+ return CAIRO_OPERATOR_DEST_OUT;
+ case CompositeDestinationAtop:
+ return CAIRO_OPERATOR_DEST_ATOP;
+ case CompositeXOR:
+ return CAIRO_OPERATOR_XOR;
+ case CompositePlusDarker:
+ return CAIRO_OPERATOR_SATURATE;
+ case CompositeHighlight:
+ // There is no Cairo equivalent for CompositeHighlight.
+ return CAIRO_OPERATOR_OVER;
+ case CompositePlusLighter:
+ return CAIRO_OPERATOR_ADD;
+ default:
+ return CAIRO_OPERATOR_SOURCE;
+ }
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_set_operator(m_data->cr, toCairoOperator(op));
+}
+
+void GraphicsContext::beginPath()
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_new_path(cr);
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_path_t* p = cairo_copy_path(path.platformPath()->m_cr);
+ cairo_append_path(cr, p);
+ cairo_path_destroy(p);
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_path_t* p = cairo_copy_path(path.platformPath()->m_cr);
+ cairo_append_path(cr, p);
+ cairo_path_destroy(p);
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+ m_data->clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0)
+ cairo_t* cr = m_data->cr;
+ double x1, y1, x2, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
+ addPath(path);
+
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+#else
+ notImplemented();
+#endif
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_rotate(m_data->cr, radians);
+ m_data->rotate(radians);
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_scale(m_data->cr, size.width(), size.height());
+ m_data->scale(size);
+}
+
+void GraphicsContext::clipOut(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0)
+ cairo_t* cr = m_data->cr;
+ double x1, y1, x2, y2;
+ cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+ cairo_rectangle(cr, x1, x2, x2 - x1, y2 - y1);
+ cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height());
+ cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_clip(cr);
+ cairo_set_fill_rule(cr, savedFillRule);
+#else
+ notImplemented();
+#endif
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ Path p;
+ p.addEllipse(r);
+ clipOut(p);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ cairo_t* cr = m_data->cr;
+ cairo_save(cr);
+ beginPath();
+ addPath(Path::createRoundedRectangle(r, topLeft, topRight, bottomLeft, bottomRight));
+ setColor(cr, color);
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+#if PLATFORM(GTK)
+void GraphicsContext::setGdkExposeEvent(GdkEventExpose* expose)
+{
+ m_data->expose = expose;
+}
+
+GdkEventExpose* GraphicsContext::gdkExposeEvent() const
+{
+ return m_data->expose;
+}
+
+GdkDrawable* GraphicsContext::gdkDrawable() const
+{
+ if (!m_data->expose)
+ return 0;
+
+ return GDK_DRAWABLE(m_data->expose->window);
+}
+#endif
+
+void GraphicsContext::setUseAntialiasing(bool enable)
+{
+ if (paintingDisabled())
+ return;
+
+ // When true, use the default Cairo backend antialias mode (usually this
+ // enables standard 'grayscale' antialiasing); false to explicitly disable
+ // antialiasing. This is the same strategy as used in drawConvexPolygon().
+ cairo_set_antialias(m_data->cr, enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return InterpolationDefault;
+}
+
+} // namespace WebCore
+
+#endif // PLATFORM(CAIRO)
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
new file mode 100644
index 0000000..9a14555
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Brent Fulgham <bfulgham@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "GraphicsContext.h"
+
+#include <cairo.h>
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if PLATFORM(GTK)
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+#elif PLATFORM(WIN)
+#include <cairo-win32.h>
+#endif
+
+namespace WebCore {
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate()
+ : cr(0)
+#if PLATFORM(GTK)
+ , expose(0)
+#elif PLATFORM(WIN)
+ // NOTE: These may note be needed: review and remove once Cairo implementation is complete
+ , m_hdc(0)
+ , m_transparencyCount(0)
+#endif
+ {
+ }
+
+ ~GraphicsContextPlatformPrivate()
+ {
+ cairo_destroy(cr);
+ }
+
+#if PLATFORM(WIN)
+ // On Windows, we need to update the HDC for form controls to draw in the right place.
+ void save();
+ void restore();
+ void clip(const FloatRect&);
+ void clip(const Path&);
+ void scale(const FloatSize&);
+ void rotate(float);
+ void translate(float, float);
+ void concatCTM(const AffineTransform&);
+ void beginTransparencyLayer() { m_transparencyCount++; }
+ void endTransparencyLayer() { m_transparencyCount--; }
+#else
+ // On everything else, we do nothing.
+ void save() {}
+ void restore() {}
+ void clip(const FloatRect&) {}
+ void clip(const Path&) {}
+ void scale(const FloatSize&) {}
+ void rotate(float) {}
+ void translate(float, float) {}
+ void concatCTM(const AffineTransform&) {}
+ void beginTransparencyLayer() {}
+ void endTransparencyLayer() {}
+#endif
+
+ cairo_t* cr;
+ Vector<float> layers;
+
+#if PLATFORM(GTK)
+ GdkEventExpose* expose;
+#elif PLATFORM(WIN)
+ HDC m_hdc;
+ unsigned m_transparencyCount;
+#endif
+};
+
+} // namespace WebCore
+
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
new file mode 100644
index 0000000..5f65ed2
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2007 Holger Hans Peter Freyther <zecke@selfish.org>
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "Pattern.h"
+#include "PlatformString.h"
+
+#include <cairo.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_surface(0)
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ success = false; // Make early return mean error.
+ m_data.m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ size.width(),
+ size.height());
+ if (cairo_surface_status(m_data.m_surface) != CAIRO_STATUS_SUCCESS)
+ return; // create will notice we didn't set m_initialized and fail.
+
+ cairo_t* cr = cairo_create(m_data.m_surface);
+ m_context.set(new GraphicsContext(cr));
+ cairo_destroy(cr); // The context is now owned by the GraphicsContext.
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+ cairo_surface_destroy(m_data.m_surface);
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+Image* ImageBuffer::image() const
+{
+ if (!m_image) {
+ // It's assumed that if image() is called, the actual rendering to the
+ // GraphicsContext must be done.
+ ASSERT(context());
+ // BitmapImage will release the passed in surface on destruction
+ m_image = BitmapImage::create(cairo_surface_reference(m_data.m_surface));
+ }
+ return m_image.get();
+}
+
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
+{
+ ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ 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();
+
+ 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());
+
+ 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;
+
+ int stride = cairo_image_surface_get_stride(m_data.m_surface);
+ unsigned destBytesPerRow = 4 * rect.width();
+
+ unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ unsigned char *row = dataSrc + stride * (y + originy);
+ for (int x = 0; x < numColumns; x++) {
+ uint32_t *pixel = (uint32_t *) row + x + originx;
+ int basex = x * 4;
+ if (unsigned int alpha = (*pixel & 0xff000000) >> 24) {
+ destRows[basex] = (*pixel & 0x00ff0000) >> 16;
+ destRows[basex + 1] = (*pixel & 0x0000ff00) >> 8;
+ destRows[basex + 2] = (*pixel & 0x000000ff);
+ destRows[basex + 3] = alpha;
+ } else
+ reinterpret_cast<uint32_t*>(destRows + basex)[0] = pixel[0];
+ }
+ destRows += destBytesPerRow;
+ }
+
+ return result;
+}
+
+void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+ unsigned char* dataDst = cairo_image_surface_get_data(m_data.m_surface);
+
+ 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;
+
+ 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;
+ for (int y = 0; y < numRows; ++y) {
+ unsigned char *row = dataDst + stride * (y + desty);
+ for (int x = 0; x < numColumns; x++) {
+ uint32_t *pixel = (uint32_t *) row + x + destx;
+ int basex = x * 4;
+ if (unsigned int alpha = srcRows[basex + 3]) {
+ *pixel = alpha << 24 | srcRows[basex] << 16 | srcRows[basex + 1] << 8 | srcRows[basex + 2];
+ } else
+ pixel[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ }
+ srcRows += srcBytesPerRow;
+ }
+}
+
+static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length)
+{
+ Vector<char>* in = reinterpret_cast<Vector<char>*>(closure);
+ in->append(data, length);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+String ImageBuffer::toDataURL(const String& mimeType) const
+{
+ cairo_surface_t* image = cairo_get_target(context()->platformContext());
+ if (!image)
+ return "data:,";
+
+ String actualMimeType("image/png");
+ if (MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
+ actualMimeType = mimeType;
+
+ Vector<char> in;
+ // Only PNG output is supported for now.
+ cairo_surface_write_to_png_stream(image, writeFunction, &in);
+
+ Vector<char> out;
+ base64Encode(in, out);
+
+ return "data:" + actualMimeType + ";base64," + String(out.data(), out.size());
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cairo/ImageBufferData.h b/WebCore/platform/graphics/cairo/ImageBufferData.h
new file mode 100644
index 0000000..49f15df
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/ImageBufferData.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+#include "cairo.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ cairo_surface_t* m_surface;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp
new file mode 100644
index 0000000..0a35cf2
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "BitmapImage.h"
+
+#if PLATFORM(CAIRO)
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include <cairo.h>
+#include <math.h>
+
+namespace WebCore {
+
+void FrameData::clear()
+{
+ 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.
+ }
+}
+
+BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ // TODO: check to be sure this is an image surface
+
+ int width = cairo_image_surface_get_width(surface);
+ int height = cairo_image_surface_get_height(surface);
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = surface;
+ m_frames[0].m_hasAlpha = cairo_surface_get_content(surface) != CAIRO_CONTENT_COLOR;
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op)
+{
+ startAnimation();
+
+ cairo_surface_t* image = frameAtIndex(m_currentFrame);
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ FloatRect srcRect(src);
+ FloatRect dstRect(dst);
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(context, dstRect, solidColor(), op);
+ return;
+ }
+
+ IntSize selfSize = size();
+
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+
+ // Set the compositing operation.
+ if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame))
+ context->setCompositeOperation(CompositeCopy);
+ else
+ context->setCompositeOperation(op);
+
+ // If we're drawing a sub portion of the image or scaling then create
+ // a pattern transformation on the image and draw the transformed pattern.
+ // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
+
+ // To avoid the unwanted gradient effect (#14017) we use
+ // CAIRO_FILTER_NEAREST now, but the real fix will be to have
+ // CAIRO_EXTEND_PAD implemented for surfaces in Cairo allowing us to still
+ // use bilinear filtering
+ cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
+
+ float scaleX = srcRect.width() / dstRect.width();
+ float scaleY = srcRect.height() / dstRect.height();
+ cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() };
+ cairo_pattern_set_matrix(pattern, &matrix);
+
+ // Draw the image.
+ cairo_translate(cr, dstRect.x(), dstRect.y());
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+ cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height());
+ cairo_clip(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
+
+ cairo_restore(cr);
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
+{
+ cairo_surface_t* image = nativeImageForCurrentFrame();
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ cairo_t* cr = context->platformContext();
+ context->save();
+
+ // TODO: Make use of tileRect.
+
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+
+ // Workaround to avoid the unwanted gradient effect (#14017)
+ cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
+
+ cairo_matrix_t pattern_matrix = cairo_matrix_t(patternTransform);
+ cairo_matrix_t phase_matrix = {1, 0, 0, 1, phase.x(), phase.y()};
+ cairo_matrix_t combined;
+ cairo_matrix_multiply(&combined, &pattern_matrix, &phase_matrix);
+ cairo_matrix_invert(&combined);
+ cairo_pattern_set_matrix(pattern, &combined);
+
+ context->setCompositeOperation(op);
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+ cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height());
+ cairo_fill(cr);
+
+ context->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1.
+ m_isSolidColor = false;
+}
+
+}
+
+#endif // PLATFORM(CAIRO)
diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
new file mode 100644
index 0000000..b7a4cbb
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ *
+ * 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 "ImageSource.h"
+
+#if PLATFORM(CAIRO)
+
+#include "BMPImageDecoder.h"
+#include "GIFImageDecoder.h"
+#include "ICOImageDecoder.h"
+#include "JPEGImageDecoder.h"
+#include "PNGImageDecoder.h"
+#include "SharedBuffer.h"
+#include <cairo.h>
+
+#if !PLATFORM(WIN)
+#include "XBMImageDecoder.h"
+#endif
+
+namespace WebCore {
+
+ImageDecoder* createDecoder(const Vector<char>& data)
+{
+ // We need at least 4 bytes to figure out what kind of image we're dealing with.
+ int length = data.size();
+ 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();
+
+#if !PLATFORM(WIN)
+ // XBMs require 8 bytes of info.
+ if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
+ return new XBMImageDecoder();
+#endif
+
+ // Give up. We don't know what the heck this is.
+ return 0;
+}
+
+ImageSource::ImageSource()
+ : m_decoder(0)
+{
+}
+
+ImageSource::~ImageSource()
+{
+ clear();
+}
+
+void ImageSource::clear()
+{
+ delete m_decoder;
+ m_decoder = 0;
+}
+
+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());
+
+ if (!m_decoder)
+ 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
+{
+ return size();
+}
+
+int ImageSource::repetitionCount()
+{
+ if (!m_decoder)
+ return cAnimationNone;
+
+ return m_decoder->repetitionCount();
+}
+
+size_t ImageSource::frameCount() const
+{
+ return m_decoder ? m_decoder->frameCount() : 0;
+}
+
+NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!initialized())
+ return 0;
+
+ if (!m_decoder)
+ return 0;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return 0;
+
+ // Cairo does not like zero height images.
+ // If we have a zero height image, just pretend we don't have enough data yet.
+ if (!buffer->height())
+ return 0;
+
+ return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(),
+ CAIRO_FORMAT_ARGB32,
+ size().width(),
+ buffer->height(),
+ size().width()*4);
+}
+
+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)
+{
+ // When a frame has not finished decoding, always mark it as having alpha,
+ // so we don't get a black background for the undecoded sections.
+ // TODO: A better solution is probably to have the underlying buffer's
+ // hasAlpha() return true in these cases, since it is, in fact, technically
+ // true.
+ if (!frameIsCompleteAtIndex(index))
+ return true;
+
+ return m_decoder->frameBufferAtIndex(index)->hasAlpha();
+}
+
+}
+
+#endif // PLATFORM(CAIRO)
diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp
new file mode 100644
index 0000000..3f8d588
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -0,0 +1,285 @@
+/*
+ Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+ Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org>
+ 2004, 2005, 2006 Rob Buis <buis@kde.org>
+ 2005, 2007 Apple Inc. All Rights reserved.
+ 2007 Alp Toker <alp@atoker.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
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "CairoPath.h"
+#include "FloatRect.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+#include <cairo.h>
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+Path::Path()
+ : m_path(new CairoPath())
+{
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path::Path(const Path& other)
+ : m_path(new CairoPath())
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_path_t* p = cairo_copy_path(other.platformPath()->m_cr);
+ cairo_append_path(cr, p);
+ cairo_path_destroy(p);
+}
+
+Path& Path::operator=(const Path& other)
+{
+ if (&other == this)
+ return *this;
+
+ clear();
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_path_t* p = cairo_copy_path(other.platformPath()->m_cr);
+ cairo_append_path(cr, p);
+ cairo_path_destroy(p);
+ return *this;
+}
+
+void Path::clear()
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_new_path(cr);
+}
+
+bool Path::isEmpty() const
+{
+ cairo_t* cr = platformPath()->m_cr;
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,5,10)
+ return !cairo_has_current_point(cr);
+#else
+ cairo_path_t* p = cairo_copy_path(cr);
+ bool hasData = p->num_data;
+ cairo_path_destroy(p);
+ return !hasData;
+#endif
+}
+
+void Path::translate(const FloatSize& p)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_translate(cr, p.width(), p.height());
+}
+
+void Path::moveTo(const FloatPoint& p)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_move_to(cr, p.x(), p.y());
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_line_to(cr, p.x(), p.y());
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+/*
+ * inspired by libsvg-cairo
+ */
+void Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ double x, y;
+ double x1 = controlPoint.x();
+ double y1 = controlPoint.y();
+ double x2 = point.x();
+ double y2 = point.y();
+ cairo_get_current_point(cr, &x, &y);
+ cairo_curve_to(cr,
+ x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y),
+ x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2),
+ x2, y2);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& controlPoint3)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_curve_to(cr, controlPoint1.x(), controlPoint1.y(),
+ controlPoint2.x(), controlPoint2.y(),
+ controlPoint3.x(), controlPoint3.y());
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise)
+{
+ // http://bugs.webkit.org/show_bug.cgi?id=16449
+ // cairo_arc() functions hang or crash when passed inf as radius or start/end angle
+ if (!isfinite(r) || !isfinite(sa) || !isfinite(ea))
+ return;
+
+ cairo_t* cr = platformPath()->m_cr;
+ if (anticlockwise)
+ cairo_arc_negative(cr, p.x(), p.y(), r, sa, ea);
+ else
+ cairo_arc(cr, p.x(), p.y(), r, sa, ea);
+}
+
+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();
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_save(cr);
+ float yRadius = .5 * rect.height();
+ float xRadius = .5 * rect.width();
+ cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius);
+ cairo_scale(cr, xRadius, yRadius);
+ cairo_arc(cr, 0., 0., 1., 0., 2 * piDouble);
+ cairo_restore(cr);
+}
+
+void Path::closeSubpath()
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_close_path(cr);
+}
+
+FloatRect Path::boundingRect() const
+{
+ cairo_t* cr = platformPath()->m_cr;
+ double x0, x1, y0, y1;
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
+ cairo_path_extents(cr, &x0, &y0, &x1, &y1);
+#else
+ cairo_stroke_extents(cr, &x0, &y0, &x1, &y1);
+#endif
+ return FloatRect(x0, y0, x1 - x0, y1 - y0);
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ if (!boundingRect().contains(point))
+ return false;
+
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_fill_rule_t cur = cairo_get_fill_rule(cr);
+ cairo_set_fill_rule(cr, rule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
+ bool contains = cairo_in_fill(cr, point.x(), point.y());
+ cairo_set_fill_rule(cr, cur);
+ return contains;
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ cairo_t* cr = platformPath()->m_cr;
+ cairo_path_t* path = cairo_copy_path(cr);
+ cairo_path_data_t* data;
+ PathElement pelement;
+ FloatPoint points[3];
+ pelement.points = points;
+
+ 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:
+ pelement.type = PathElementMoveToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_LINE_TO:
+ pelement.type = PathElementAddLineToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_CURVE_TO:
+ pelement.type = PathElementAddCurveToPoint;
+ pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y);
+ pelement.points[1] = FloatPoint(data[2].point.x,data[2].point.y);
+ pelement.points[2] = FloatPoint(data[3].point.x,data[3].point.y);
+ function(info, &pelement);
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ pelement.type = PathElementCloseSubpath;
+ function(info, &pelement);
+ break;
+ }
+ }
+ cairo_path_destroy(path);
+}
+
+void Path::transform(const AffineTransform& trans)
+{
+ cairo_t* m_cr = platformPath()->m_cr;
+ cairo_matrix_t c_matrix = cairo_matrix_t(trans);
+ cairo_matrix_invert(&c_matrix);
+ cairo_transform(m_cr, &c_matrix);
+}
+
+String Path::debugString() const
+{
+ String string = "";
+ 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",
+ data[1].point.x, data[1].point.y);
+ break;
+ case CAIRO_PATH_LINE_TO:
+ string += 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",
+ 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";
+ break;
+ }
+ }
+ cairo_path_destroy(path);
+ return string;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cairo/PatternCairo.cpp b/WebCore/platform/graphics/cairo/PatternCairo.cpp
new file mode 100644
index 0000000..16cebf8
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/PatternCairo.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 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
+ * 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 "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+cairo_pattern_t* Pattern::createPlatformPattern(const AffineTransform& 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);
+ cairo_pattern_set_matrix(pattern, pattern_matrix);
+ if (m_repeatX || m_repeatY)
+ cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+ return pattern;
+}
+
+}
diff --git a/WebCore/platform/graphics/cairo/rgb24-hacks.txt b/WebCore/platform/graphics/cairo/rgb24-hacks.txt
new file mode 100644
index 0000000..59f8070
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/rgb24-hacks.txt
@@ -0,0 +1,32 @@
+Index: cairo/src/cairo-win32-surface.c
+===================================================================
+--- cairo/src/cairo-win32-surface.c (revision 14498)
++++ cairo/src/cairo-win32-surface.c (working copy)
+@@ -824,8 +824,13 @@
+ * to figure out when we can use GDI. We don't have that checking
+ * anywhere at the moment, so just bail and use the fallback
+ * paths. */
+- if (surface->format != CAIRO_FORMAT_RGB24)
+- return CAIRO_INT_STATUS_UNSUPPORTED;
++ //if (surface->format != CAIRO_FORMAT_RGB24)
++ // return CAIRO_INT_STATUS_UNSUPPORTED;
++ // FIXME: We'll go ahead and optimize this now and just assume we're ok if
++ // the color has no alpha. Probably need to check various composite operators to
++ // get this exactly right.
++ if (color->alpha != 1.0)
++ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
+ * surfaces with alpha.)
+@@ -1016,8 +1021,9 @@
+
+ /* We can only handle operator SOURCE or OVER with the destination
+ * having no alpha */
+- if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
+- (dst->format != CAIRO_FORMAT_RGB24))
++ if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER))
++ // FIXME: It's not clear why ExtTextOut can't be called when the
++ // destination has alpha. Remove the RGB24 restriction. || (dst->format != CAIRO_FORMAT_RGB24))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* If we have a fallback mask clip set on the dst, we have
diff --git a/WebCore/platform/graphics/cairo/scale-removal.txt b/WebCore/platform/graphics/cairo/scale-removal.txt
new file mode 100644
index 0000000..47c0d70
--- /dev/null
+++ b/WebCore/platform/graphics/cairo/scale-removal.txt
@@ -0,0 +1,13 @@
+Index: cairo/src/cairo-win32-private.h
+===================================================================
+--- cairo/src/cairo-win32-private.h (revision 14582)
++++ cairo/src/cairo-win32-private.h (working copy)
+@@ -39,7 +39,7 @@
+ #include <cairo-win32.h>
+ #include <cairoint.h>
+
+-#define WIN32_FONT_LOGICAL_SCALE 32
++#define WIN32_FONT_LOGICAL_SCALE 1
+
+ typedef struct _cairo_win32_surface {
+ cairo_surface_t base;
diff --git a/WebCore/platform/graphics/cg/AffineTransformCG.cpp b/WebCore/platform/graphics/cg/AffineTransformCG.cpp
new file mode 100644
index 0000000..4f0bca0
--- /dev/null
+++ b/WebCore/platform/graphics/cg/AffineTransformCG.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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 "AffineTransform.h"
+
+#if PLATFORM(CG)
+
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+AffineTransform::AffineTransform()
+ : m_transform(CGAffineTransformIdentity)
+{
+}
+
+AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+{
+ m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
+ narrowPrecisionToCGFloat(b),
+ narrowPrecisionToCGFloat(c),
+ narrowPrecisionToCGFloat(d),
+ narrowPrecisionToCGFloat(tx),
+ narrowPrecisionToCGFloat(ty));
+}
+
+AffineTransform::AffineTransform(const PlatformAffineTransform& t)
+ : m_transform(t)
+{
+}
+
+void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
+{
+ m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a),
+ narrowPrecisionToCGFloat(b),
+ narrowPrecisionToCGFloat(c),
+ narrowPrecisionToCGFloat(d),
+ narrowPrecisionToCGFloat(tx),
+ narrowPrecisionToCGFloat(ty));
+}
+
+void AffineTransform::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
+{
+ return enclosingIntRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+{
+ return FloatRect(CGRectApplyAffineTransform(CGRect(rect), m_transform));
+}
+
+bool AffineTransform::isIdentity() const
+{
+ return CGAffineTransformIsIdentity(m_transform);
+}
+
+double AffineTransform::a() const
+{
+ return m_transform.a;
+}
+
+void AffineTransform::setA(double a)
+{
+ m_transform.a = narrowPrecisionToCGFloat(a);
+}
+
+double AffineTransform::b() const
+{
+ return m_transform.b;
+}
+
+void AffineTransform::setB(double b)
+{
+ m_transform.b = narrowPrecisionToCGFloat(b);
+}
+
+double AffineTransform::c() const
+{
+ return m_transform.c;
+}
+
+void AffineTransform::setC(double c)
+{
+ m_transform.c = narrowPrecisionToCGFloat(c);
+}
+
+double AffineTransform::d() const
+{
+ return m_transform.d;
+}
+
+void AffineTransform::setD(double d)
+{
+ m_transform.d = narrowPrecisionToCGFloat(d);
+}
+
+double AffineTransform::e() const
+{
+ return m_transform.tx;
+}
+
+void AffineTransform::setE(double e)
+{
+ m_transform.tx = narrowPrecisionToCGFloat(e);
+}
+
+double AffineTransform::f() const
+{
+ return m_transform.ty;
+}
+
+void AffineTransform::setF(double f)
+{
+ m_transform.ty = narrowPrecisionToCGFloat(f);
+}
+
+void AffineTransform::reset()
+{
+ m_transform = CGAffineTransformIdentity;
+}
+
+AffineTransform &AffineTransform::scale(double sx, double sy)
+{
+ m_transform = CGAffineTransformScale(m_transform, narrowPrecisionToCGFloat(sx), narrowPrecisionToCGFloat(sy));
+ return *this;
+}
+
+AffineTransform &AffineTransform::rotate(double d)
+{
+ m_transform = CGAffineTransformRotate(m_transform, narrowPrecisionToCGFloat(deg2rad(d)));
+ return *this;
+}
+
+AffineTransform &AffineTransform::translate(double tx, double ty)
+{
+ m_transform = CGAffineTransformTranslate(m_transform, narrowPrecisionToCGFloat(tx), narrowPrecisionToCGFloat(ty));
+ return *this;
+}
+
+AffineTransform &AffineTransform::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
+{
+ return m_transform.a * m_transform.d - m_transform.b * m_transform.c;
+}
+
+AffineTransform AffineTransform::inverse() const
+{
+ if (isInvertible())
+ return AffineTransform(CGAffineTransformInvert(m_transform));
+ return AffineTransform();
+}
+
+AffineTransform::operator PlatformAffineTransform() const
+{
+ return m_transform;
+}
+
+bool AffineTransform::operator== (const AffineTransform &m2) const
+{
+ return CGAffineTransformEqualToTransform(m_transform, CGAffineTransform(m2));
+}
+
+AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+{
+ m_transform = CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
+ return *this;
+}
+
+AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+{
+ return CGAffineTransformConcat(m_transform, CGAffineTransform(m2));
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp
new file mode 100644
index 0000000..48ce9f2
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ColorCG.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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"
+
+#if PLATFORM(CG)
+
+#include <wtf/Assertions.h>
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+Color::Color(CGColorRef color)
+{
+ if (!color) {
+ m_color = 0;
+ m_valid = false;
+ return;
+ }
+
+ size_t numComponents = CGColorGetNumberOfComponents(color);
+ const CGFloat* components = CGColorGetComponents(color);
+
+ float r = 0;
+ float g = 0;
+ float b = 0;
+ float a = 0;
+
+ switch (numComponents) {
+ case 2:
+ r = g = b = components[0];
+ a = components[1];
+ break;
+ case 4:
+ r = components[0];
+ g = components[1];
+ b = components[2];
+ a = components[3];
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255);
+}
+
+#if !PLATFORM(MAC)
+
+CGColorRef cgColor(const Color& c)
+{
+ CGColorRef color = NULL;
+ CMProfileRef prof = NULL;
+ CMGetSystemProfile(&prof);
+
+ CGColorSpaceRef rgbSpace = CGColorSpaceCreateWithPlatformColorSpace(prof);
+
+ if (rgbSpace != NULL)
+ {
+ float components[4] = {c.red() / 255.0f, c.green() / 255.0f, c.blue() / 255.0f, c.alpha() / 255.0f};
+ color = CGColorCreate(rgbSpace, components);
+ CGColorSpaceRelease(rgbSpace);
+ }
+
+ CMCloseProfile(prof);
+
+ return color;
+}
+
+#endif // !PLATFORM(MAC)
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/FloatPointCG.cpp b/WebCore/platform/graphics/cg/FloatPointCG.cpp
new file mode 100644
index 0000000..f9c3353
--- /dev/null
+++ b/WebCore/platform/graphics/cg/FloatPointCG.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatPoint.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const CGPoint& p) : m_x(p.x), m_y(p.y)
+{
+}
+
+FloatPoint::operator CGPoint() const
+{
+ return CGPointMake(m_x, m_y);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/FloatRectCG.cpp b/WebCore/platform/graphics/cg/FloatRectCG.cpp
new file mode 100644
index 0000000..a1ce367
--- /dev/null
+++ b/WebCore/platform/graphics/cg/FloatRectCG.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatRect.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+FloatRect::FloatRect(const CGRect& r) : m_location(r.origin), m_size(r.size)
+{
+}
+
+FloatRect::operator CGRect() const
+{
+ return CGRectMake(x(), y(), width(), height());
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/FloatSizeCG.cpp b/WebCore/platform/graphics/cg/FloatSizeCG.cpp
new file mode 100644
index 0000000..383af21
--- /dev/null
+++ b/WebCore/platform/graphics/cg/FloatSizeCG.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatSize.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+FloatSize::FloatSize(const CGSize& s) : m_width(s.width), m_height(s.height)
+{
+}
+
+FloatSize::operator CGSize() const
+{
+ return CGSizeMake(m_width, m_height);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp
new file mode 100644
index 0000000..c189fd5
--- /dev/null
+++ b/WebCore/platform/graphics/cg/GradientCG.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ CGShadingRelease(m_gradient);
+ m_gradient = 0;
+}
+
+static void gradientCallback(void* info, const CGFloat* in, CGFloat* out)
+{
+ float r, g, b, a;
+ static_cast<const Gradient*>(info)->getColor(*in, &r, &g, &b, &a);
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = a;
+}
+
+CGShadingRef Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ const CGFloat intervalRanges[2] = { 0, 1 };
+ const CGFloat colorComponentRanges[4 * 2] = { 0, 1, 0, 1, 0, 1, 0, 1 };
+ const CGFunctionCallbacks gradientCallbacks = { 0, gradientCallback, 0 };
+ CGFunctionRef colorFunction = CGFunctionCreate(this, 1, intervalRanges, 4, colorComponentRanges, &gradientCallbacks);
+
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+
+ if (m_radial)
+ m_gradient = CGShadingCreateRadial(colorSpace, m_p0, m_r0, m_p1, m_r1, colorFunction, true, true);
+ else
+ m_gradient = CGShadingCreateAxial(colorSpace, m_p0, m_p1, colorFunction, true, true);
+
+ CGColorSpaceRelease(colorSpace);
+ CGFunctionRelease(colorFunction);
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->clip(rect);
+ CGContextDrawShading(context->platformContext(), platformGradient());
+}
+
+} //namespace
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
new file mode 100644
index 0000000..3f0e6e7
--- /dev/null
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -0,0 +1,1144 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 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
+ * 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.
+ */
+
+#define _USE_MATH_DEFINES 1
+#include "config.h"
+#include "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "FloatConversion.h"
+#include "GraphicsContextPrivate.h"
+#include "GraphicsContextPlatformPrivateCG.h"
+#include "ImageBuffer.h"
+#include "KURL.h"
+#include "Path.h"
+#include "Pattern.h"
+#include <CoreGraphics/CGBitmapContext.h>
+#include <CoreGraphics/CGPDFContext.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RetainPtr.h>
+
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+#define HAVE_CG_INTERPOLATION_MEDIUM 1
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static void setCGFillColor(CGContextRef context, const Color& color)
+{
+ CGFloat red, green, blue, alpha;
+ color.getRGBA(red, green, blue, alpha);
+ CGContextSetRGBFillColor(context, red, green, blue, alpha);
+}
+
+static void setCGStrokeColor(CGContextRef context, const Color& color)
+{
+ CGFloat red, green, blue, alpha;
+ color.getRGBA(red, green, blue, alpha);
+ CGContextSetRGBStrokeColor(context, red, green, blue, alpha);
+}
+
+GraphicsContext::GraphicsContext(CGContextRef cgContext)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(cgContext))
+{
+ setPaintingDisabled(!cgContext);
+ if (cgContext) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor());
+ setPlatformStrokeColor(strokeColor());
+ }
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ destroyGraphicsContextPrivate(m_common);
+ delete m_data;
+}
+
+CGContextRef GraphicsContext::platformContext() const
+{
+ ASSERT(!paintingDisabled());
+ ASSERT(m_data->m_cgContext);
+ return m_data->m_cgContext;
+}
+
+void GraphicsContext::savePlatformState()
+{
+ // Note: Do not use this function within this class implementation, since we want to avoid the extra
+ // save of the secondary context (in GraphicsContextPlatformPrivateCG.h).
+ CGContextSaveGState(platformContext());
+ m_data->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ // Note: Do not use this function within this class implementation, since we want to avoid the extra
+ // restore of the secondary context (in GraphicsContextPlatformPrivateCG.h).
+ CGContextRestoreGState(platformContext());
+ m_data->restore();
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ // FIXME: this function does not handle patterns and gradients
+ // like drawPath does, it probably should.
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+
+ if (fillColor().alpha())
+ CGContextFillRect(context, rect);
+
+ if (strokeStyle() != NoStroke && strokeColor().alpha()) {
+ // We do a fill of four rects to simulate the stroke of a border.
+ Color oldFillColor = fillColor();
+ if (oldFillColor != strokeColor())
+ setCGFillColor(context, strokeColor());
+ CGRect rects[4] = {
+ FloatRect(rect.x(), rect.y(), rect.width(), 1),
+ FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1),
+ FloatRect(rect.x(), rect.y() + 1, 1, rect.height() - 2),
+ FloatRect(rect.right() - 1, rect.y() + 1, 1, rect.height() - 2)
+ };
+ CGContextFillRects(context, rects, 4);
+ if (oldFillColor != strokeColor())
+ setCGFillColor(context, oldFillColor);
+ }
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ if (strokeStyle() == NoStroke || !strokeColor().alpha())
+ return;
+
+ float width = strokeThickness();
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ // 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.
+ if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) {
+ if (isVerticalLine) {
+ p1.move(0, width);
+ p2.move(0, -width);
+ } else {
+ p1.move(width, 0);
+ p2.move(-width, 0);
+ }
+ }
+
+ if (((int)width) % 2) {
+ if (isVerticalLine) {
+ // We're a vertical line. Adjust our x.
+ p1.move(0.5f, 0.0f);
+ p2.move(0.5f, 0.0f);
+ } else {
+ // We're a horizontal line. Adjust our y.
+ p1.move(0.0f, 0.5f);
+ p2.move(0.0f, 0.5f);
+ }
+ }
+
+ int patWidth = 0;
+ switch (strokeStyle()) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = (int)width;
+ break;
+ case DashedStroke:
+ patWidth = 3 * (int)width;
+ break;
+ }
+
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+
+ CGContextSetShouldAntialias(context, false);
+
+ if (patWidth) {
+ // 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.
+ if (isVerticalLine) {
+ CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width));
+ CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width));
+ } else {
+ CGContextFillRect(context, FloatRect(p1.x() - width, p1.y() - width / 2, width, width));
+ CGContextFillRect(context, FloatRect(p2.x(), p2.y() - width / 2, width, width));
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = numSegments % 2 == 0;
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder)/2;
+ }
+ }
+
+ const CGFloat dottedLine[2] = { patWidth, patWidth };
+ CGContextSetLineDash(context, patternOffset, dottedLine, 2);
+ }
+
+ CGContextBeginPath(context);
+ CGContextMoveToPoint(context, p1.x(), p1.y());
+ CGContextAddLineToPoint(context, p2.x(), p2.y());
+
+ CGContextStrokePath(context);
+
+ CGContextRestoreGState(context);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ // FIXME: CG added CGContextAddEllipseinRect in Tiger, so we should be able to quite easily draw an ellipse.
+ // This code can only handle circles, not ellipses. But khtml only
+ // uses it for circles.
+ ASSERT(rect.width() == rect.height());
+
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ CGContextBeginPath(context);
+ float r = (float)rect.width() / 2;
+ CGContextAddArc(context, rect.x() + r, rect.y() + r, r, 0.0f, 2.0f * piFloat, 0);
+ CGContextClosePath(context);
+
+ drawPath();
+}
+
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha())
+ return;
+
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+ CGContextBeginPath(context);
+ CGContextSetShouldAntialias(context, false);
+
+ int x = rect.x();
+ int y = rect.y();
+ float w = (float)rect.width();
+ float h = (float)rect.height();
+ float scaleFactor = h / w;
+ float reverseScaleFactor = w / h;
+
+ if (w != h)
+ scale(FloatSize(1, scaleFactor));
+
+ float hRadius = w / 2;
+ float vRadius = h / 2;
+ float fa = startAngle;
+ float falen = fa + angleSpan;
+ float start = -fa * piFloat / 180.0f;
+ float end = -falen * piFloat / 180.0f;
+ CGContextAddArc(context, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, start, end, true);
+
+ if (w != h)
+ scale(FloatSize(1, reverseScaleFactor));
+
+
+ float width = strokeThickness();
+ int patWidth = 0;
+
+ switch (strokeStyle()) {
+ case DottedStroke:
+ patWidth = (int)(width / 2);
+ break;
+ case DashedStroke:
+ patWidth = 3 * (int)(width / 2);
+ break;
+ default:
+ break;
+ }
+
+ if (patWidth) {
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance;
+ if (hRadius == vRadius)
+ distance = static_cast<int>((piFloat * hRadius) / 2.0f);
+ else // We are elliptical and will have to estimate the distance
+ distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f);
+
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = numSegments % 2 == 0;
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2.0f;
+ } else
+ patternOffset = patWidth / 2.0f;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2.0f;
+ }
+ }
+
+ const CGFloat dottedLine[2] = { patWidth, patWidth };
+ CGContextSetLineDash(context, patternOffset, dottedLine, 2);
+ }
+
+ CGContextStrokePath(context);
+
+ CGContextRestoreGState(context);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled() || !fillColor().alpha() && (strokeThickness() <= 0 || strokeStyle() == NoStroke))
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ CGContextRef context = platformContext();
+
+ CGContextSaveGState(context);
+
+ CGContextSetShouldAntialias(context, shouldAntialias);
+
+ CGContextBeginPath(context);
+ CGContextMoveToPoint(context, points[0].x(), points[0].y());
+ for (size_t i = 1; i < npoints; i++)
+ CGContextAddLineToPoint(context, points[i].x(), points[i].y());
+ CGContextClosePath(context);
+
+ drawPath();
+
+ CGContextRestoreGState(context);
+}
+
+static void applyStrokePattern(GraphicsContext* context, Pattern* pattern)
+{
+ CGContextRef cgContext = context->platformContext();
+
+ CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM());
+ if (!platformPattern)
+ return;
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0);
+ CGContextSetStrokeColorSpace(cgContext, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+
+ const CGFloat patternAlpha = 1;
+ CGContextSetStrokePattern(cgContext, platformPattern, &patternAlpha);
+ CGPatternRelease(platformPattern);
+}
+
+static void applyFillPattern(GraphicsContext* context, Pattern* pattern)
+{
+ CGContextRef cgContext = context->platformContext();
+
+ CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM());
+ if (!platformPattern)
+ return;
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0);
+ CGContextSetFillColorSpace(cgContext, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+
+ const CGFloat patternAlpha = 1;
+ CGContextSetFillPattern(cgContext, platformPattern, &patternAlpha);
+ CGPatternRelease(platformPattern);
+}
+
+static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode)
+{
+ bool shouldFill = state.fillColorSpace == PatternColorSpace || state.fillColor.alpha();
+ bool shouldStroke = state.strokeColorSpace == PatternColorSpace || (state.strokeStyle != NoStroke && state.strokeColor.alpha());
+ bool useEOFill = state.fillRule == RULE_EVENODD;
+
+ if (shouldFill) {
+ if (shouldStroke) {
+ if (useEOFill)
+ mode = kCGPathEOFillStroke;
+ else
+ mode = kCGPathFillStroke;
+ } else { // fill, no stroke
+ if (useEOFill)
+ mode = kCGPathEOFill;
+ else
+ mode = kCGPathFill;
+ }
+ } else {
+ // Setting mode to kCGPathStroke even if shouldStroke is false. In that case, we return false and mode will not be used,
+ // but the compiler will not compain about an uninitialized variable.
+ mode = kCGPathStroke;
+ }
+
+ return shouldFill || shouldStroke;
+}
+
+void GraphicsContext::drawPath()
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ const GraphicsContextState& state = m_common->state;
+
+ if (state.fillColorSpace == GradientColorSpace || state.strokeColorSpace == GradientColorSpace) {
+ // We don't have any optimized way to fill & stroke a path using gradients
+ fillPath();
+ strokePath();
+ return;
+ }
+
+ if (state.fillColorSpace == PatternColorSpace)
+ applyFillPattern(this, m_common->state.fillPattern.get());
+ if (state.strokeColorSpace == PatternColorSpace)
+ applyStrokePattern(this, m_common->state.strokePattern.get());
+
+ CGPathDrawingMode drawingMode;
+ if (calculateDrawingMode(state, drawingMode))
+ CGContextDrawPath(context, drawingMode);
+}
+
+static inline void fillPathWithFillRule(CGContextRef context, WindRule fillRule)
+{
+ if (fillRule == RULE_EVENODD)
+ CGContextEOFillPath(context);
+ else
+ CGContextFillPath(context);
+}
+
+void GraphicsContext::fillPath()
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ switch (m_common->state.fillColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ fillPathWithFillRule(context, fillRule());
+ break;
+ case PatternColorSpace:
+ applyFillPattern(this, m_common->state.fillPattern.get());
+ fillPathWithFillRule(context, fillRule());
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ if (fillRule() == RULE_EVENODD)
+ CGContextEOClip(context);
+ else
+ CGContextClip(context);
+ CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
+ }
+}
+
+void GraphicsContext::strokePath()
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextRef context = platformContext();
+ switch (m_common->state.strokeColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ CGContextStrokePath(context);
+ break;
+ case PatternColorSpace:
+ applyStrokePattern(this, m_common->state.strokePattern.get());
+ CGContextStrokePath(context);
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ CGContextReplacePathWithStrokedPath(context);
+ CGContextClip(context);
+ CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+ switch (m_common->state.fillColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ CGContextFillRect(context, rect);
+ break;
+ case PatternColorSpace:
+ applyFillPattern(this, m_common->state.fillPattern.get());
+ CGContextFillRect(context, rect);
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ CGContextClipToRect(context, rect);
+ CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+ if (color.alpha()) {
+ CGContextRef context = platformContext();
+ Color oldFillColor = fillColor();
+ if (oldFillColor != color)
+ setCGFillColor(context, color);
+ CGContextFillRect(context, rect);
+ if (oldFillColor != color)
+ setCGFillColor(context, oldFillColor);
+ }
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
+{
+ if (paintingDisabled() || !color.alpha())
+ return;
+
+ CGContextRef context = platformContext();
+ Color oldFillColor = fillColor();
+ if (oldFillColor != color)
+ setCGFillColor(context, color);
+
+ addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
+ fillPath();
+
+ if (oldFillColor != color)
+ setCGFillColor(context, oldFillColor);
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+ CGContextClipToRect(platformContext(), rect);
+ m_data->clip(rect);
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect };
+ CGContextBeginPath(platformContext());
+ CGContextAddRects(platformContext(), rects, 2);
+ CGContextEOClip(platformContext());
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextBeginPath(platformContext());
+ CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
+ CGContextAddEllipseInRect(platformContext(), rect);
+ CGContextEOClip(platformContext());
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ clip(rect);
+ CGContextRef context = platformContext();
+
+ // Add outer ellipse
+ CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
+ // Add inner ellipse.
+ CGContextAddEllipseInRect(context, CGRectMake(rect.x() + thickness, rect.y() + thickness,
+ rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
+
+ CGContextEOClip(context);
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextTranslateCTM(platformContext(), rect.x(), rect.y() + rect.height());
+ CGContextScaleCTM(platformContext(), 1, -1);
+ CGContextClipToMask(platformContext(), FloatRect(FloatPoint(), rect.size()), imageBuffer->image()->getCGImageRef());
+ CGContextScaleCTM(platformContext(), 1, -1);
+ CGContextTranslateCTM(platformContext(), -rect.x(), -rect.y() - rect.height());
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+ CGContextSetAlpha(context, opacity);
+ CGContextBeginTransparencyLayer(context, 0);
+ m_data->beginTransparencyLayer();
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+ CGContextEndTransparencyLayer(context);
+ CGContextRestoreGState(context);
+ m_data->endTransparencyLayer();
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+ 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;
+
+ CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D)))));
+
+ // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
+ CGFloat blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0));
+
+ CGSize sizeInDeviceSpace = CGSizeApplyAffineTransform(size, transform);
+
+ CGFloat width = sizeInDeviceSpace.width;
+ CGFloat height = sizeInDeviceSpace.height;
+
+ // Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated
+ // to the desired integer.
+ static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128);
+ if (width > 0)
+ width += extraShadowOffset;
+ else if (width < 0)
+ width -= extraShadowOffset;
+
+ if (height > 0)
+ height += extraShadowOffset;
+ else if (height < 0)
+ height -= extraShadowOffset;
+
+ // Check for an invalid color, as this means that the color was not set for the shadow
+ // and we should therefore just use the default shadow color.
+ if (!color.isValid())
+ CGContextSetShadow(context, CGSizeMake(width, height), blurRadius);
+ else {
+ CGColorRef colorCG = cgColor(color);
+ CGContextSetShadowWithColor(context,
+ CGSizeMake(width, height),
+ blurRadius,
+ colorCG);
+ CGColorRelease(colorCG);
+ }
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0);
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetMiterLimit(platformContext(), limit);
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetAlpha(platformContext(), alpha);
+}
+
+void GraphicsContext::clearRect(const FloatRect& r)
+{
+ if (paintingDisabled())
+ return;
+ CGContextClearRect(platformContext(), r);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+ CGContextStrokeRectWithWidth(platformContext(), r, lineWidth);
+}
+
+void GraphicsContext::setLineCap(LineCap cap)
+{
+ if (paintingDisabled())
+ return;
+ switch (cap) {
+ case ButtCap:
+ CGContextSetLineCap(platformContext(), kCGLineCapButt);
+ break;
+ case RoundCap:
+ CGContextSetLineCap(platformContext(), kCGLineCapRound);
+ break;
+ case SquareCap:
+ CGContextSetLineCap(platformContext(), kCGLineCapSquare);
+ break;
+ }
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ CGContextSetLineDash(platformContext(), dashOffset, dashes.data(), dashes.size());
+}
+
+void GraphicsContext::setLineJoin(LineJoin join)
+{
+ if (paintingDisabled())
+ return;
+ switch (join) {
+ case MiterJoin:
+ CGContextSetLineJoin(platformContext(), kCGLineJoinMiter);
+ break;
+ case RoundJoin:
+ CGContextSetLineJoin(platformContext(), kCGLineJoinRound);
+ break;
+ case BevelJoin:
+ CGContextSetLineJoin(platformContext(), kCGLineJoinBevel);
+ break;
+ }
+}
+
+void GraphicsContext::beginPath()
+{
+ CGContextBeginPath(platformContext());
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ CGContextAddPath(platformContext(), path.platformPath());
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRef context = platformContext();
+ CGContextBeginPath(context);
+ CGContextAddPath(context, path.platformPath());
+ CGContextClip(context);
+ m_data->clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ CGContextBeginPath(platformContext());
+ CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext()));
+ CGContextAddPath(platformContext(), path.platformPath());
+ CGContextEOClip(platformContext());
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+ CGContextScaleCTM(platformContext(), size.width(), size.height());
+ m_data->scale(size);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::rotate(float angle)
+{
+ if (paintingDisabled())
+ return;
+ CGContextRotateCTM(platformContext(), angle);
+ m_data->rotate(angle);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+ CGContextTranslateCTM(platformContext(), x, y);
+ m_data->translate(x, y);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+ CGContextConcatCTM(platformContext(), transform);
+ m_data->concatCTM(transform);
+ m_data->m_userToDeviceTransformKnownToBeIdentity = false;
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ return CGContextGetCTM(platformContext());
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ // 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.
+
+ if (m_data->m_userToDeviceTransformKnownToBeIdentity)
+ return rect;
+
+ CGAffineTransform deviceMatrix = CGContextGetUserSpaceToDeviceSpaceTransform(platformContext());
+ if (CGAffineTransformIsIdentity(deviceMatrix)) {
+ m_data->m_userToDeviceTransformKnownToBeIdentity = true;
+ return rect;
+ }
+
+ float deviceScaleX = sqrtf(deviceMatrix.a * deviceMatrix.a + deviceMatrix.b * deviceMatrix.b);
+ float deviceScaleY = sqrtf(deviceMatrix.c * deviceMatrix.c + deviceMatrix.d * deviceMatrix.d);
+
+ CGPoint deviceOrigin = CGPointMake(rect.x() * deviceScaleX, rect.y() * deviceScaleY);
+ CGPoint deviceLowerRight = CGPointMake((rect.x() + rect.width()) * deviceScaleX,
+ (rect.y() + rect.height()) * deviceScaleY);
+
+ deviceOrigin.x = roundf(deviceOrigin.x);
+ deviceOrigin.y = roundf(deviceOrigin.y);
+ deviceLowerRight.x = roundf(deviceLowerRight.x);
+ deviceLowerRight.y = 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.y += 1;
+ if (deviceOrigin.x == deviceLowerRight.x && rect.width() != 0)
+ deviceLowerRight.x += 1;
+
+ FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY);
+ FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x / deviceScaleX, deviceLowerRight.y / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ if (width <= 0)
+ return;
+
+ CGContextSaveGState(platformContext());
+
+ float x = point.x();
+ float y = point.y();
+ float lineLength = width;
+
+ // Use a minimum thickness of 0.5 in user space.
+ // 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);
+
+ 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);
+
+ // FIXME: This should be done a better way.
+ // We try to round all parameters to integer boundaries in device space. If rounding pixels in device space
+ // makes our thickness more than double, then there must be a shrinking-scale factor and rounding to pixels
+ // in device space will make the underlines too thick.
+ CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness));
+ if (lineRect.size.height < thickness * 2.0) {
+ x = lineRect.origin.x;
+ y = lineRect.origin.y;
+ lineLength = lineRect.size.width;
+ thickness = lineRect.size.height;
+ CGContextSetShouldAntialias(platformContext(), false);
+ }
+ }
+
+ if (fillColor() != strokeColor())
+ setCGFillColor(platformContext(), strokeColor());
+ CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness));
+
+ CGContextRestoreGState(platformContext());
+}
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ if (paintingDisabled())
+ return;
+
+ CFURLRef urlRef = link.createCFURL();
+ if (urlRef) {
+ CGContextRef context = platformContext();
+
+ // Get the bounding box to handle clipping.
+ CGRect box = CGContextGetClipBoundingBox(context);
+
+ IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
+ IntRect rect = destRect;
+ rect.intersect(intBox);
+
+ CGPDFContextSetURLForRect(context, urlRef,
+ CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+
+ CFRelease(urlRef);
+ }
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
+{
+ if (paintingDisabled())
+ return;
+
+ CGInterpolationQuality quality = kCGInterpolationDefault;
+ switch (mode) {
+ case InterpolationDefault:
+ quality = kCGInterpolationDefault;
+ break;
+ case InterpolationNone:
+ quality = kCGInterpolationNone;
+ break;
+ case InterpolationLow:
+ quality = kCGInterpolationLow;
+ break;
+
+ // Fall through to InterpolationHigh if kCGInterpolationMedium is not available
+ case InterpolationMedium:
+#if HAVE(CG_INTERPOLATION_MEDIUM)
+ quality = kCGInterpolationMedium;
+ break;
+#endif
+ case InterpolationHigh:
+ quality = kCGInterpolationHigh;
+ break;
+ }
+ CGContextSetInterpolationQuality(platformContext(), quality);
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ if (paintingDisabled())
+ return InterpolationDefault;
+
+ CGInterpolationQuality quality = CGContextGetInterpolationQuality(platformContext());
+ switch (quality) {
+ case kCGInterpolationDefault:
+ return InterpolationDefault;
+ case kCGInterpolationNone:
+ return InterpolationNone;
+ case kCGInterpolationLow:
+ return InterpolationLow;
+#if HAVE(CG_INTERPOLATION_MEDIUM)
+ case kCGInterpolationMedium:
+ return InterpolationMedium;
+#endif
+ case kCGInterpolationHigh:
+ return InterpolationHigh;
+ }
+ return InterpolationDefault;
+}
+
+void GraphicsContext::setPlatformTextDrawingMode(int mode)
+{
+ if (paintingDisabled())
+ return;
+
+ // Wow, wish CG had used bits here.
+ CGContextRef context = platformContext();
+ switch (mode) {
+ case cTextInvisible: // Invisible
+ CGContextSetTextDrawingMode(context, kCGTextInvisible);
+ break;
+ case cTextFill: // Fill
+ CGContextSetTextDrawingMode(context, kCGTextFill);
+ break;
+ case cTextStroke: // Stroke
+ CGContextSetTextDrawingMode(context, kCGTextStroke);
+ break;
+ case 3: // Fill | Stroke
+ CGContextSetTextDrawingMode(context, kCGTextFillStroke);
+ break;
+ case cTextClip: // Clip
+ CGContextSetTextDrawingMode(context, kCGTextClip);
+ break;
+ case 5: // Fill | Clip
+ CGContextSetTextDrawingMode(context, kCGTextFillClip);
+ break;
+ case 6: // Stroke | Clip
+ CGContextSetTextDrawingMode(context, kCGTextStrokeClip);
+ break;
+ case 7: // Fill | Stroke | Clip
+ CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip);
+ break;
+ default:
+ break;
+ }
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+ setCGStrokeColor(platformContext(), color);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetLineWidth(platformContext(), thickness);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+ setCGFillColor(platformContext(), color);
+}
+
+void GraphicsContext::setUseAntialiasing(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ CGContextSetShouldAntialias(platformContext(), enable);
+}
+
+#ifndef BUILDING_ON_TIGER // Tiger's setCompositeOperation() is defined in GraphicsContextMac.mm.
+void GraphicsContext::setCompositeOperation(CompositeOperator mode)
+{
+ if (paintingDisabled())
+ return;
+
+ CGBlendMode target = kCGBlendModeNormal;
+ switch (mode) {
+ case CompositeClear:
+ target = kCGBlendModeClear;
+ break;
+ case CompositeCopy:
+ target = kCGBlendModeCopy;
+ break;
+ case CompositeSourceOver:
+ //kCGBlendModeNormal
+ break;
+ case CompositeSourceIn:
+ target = kCGBlendModeSourceIn;
+ break;
+ case CompositeSourceOut:
+ target = kCGBlendModeSourceOut;
+ break;
+ case CompositeSourceAtop:
+ target = kCGBlendModeSourceAtop;
+ break;
+ case CompositeDestinationOver:
+ target = kCGBlendModeDestinationOver;
+ break;
+ case CompositeDestinationIn:
+ target = kCGBlendModeDestinationIn;
+ break;
+ case CompositeDestinationOut:
+ target = kCGBlendModeDestinationOut;
+ break;
+ case CompositeDestinationAtop:
+ target = kCGBlendModeDestinationAtop;
+ break;
+ case CompositeXOR:
+ target = kCGBlendModeXOR;
+ break;
+ case CompositePlusDarker:
+ target = kCGBlendModePlusDarker;
+ break;
+ case CompositeHighlight:
+ // currently unsupported
+ break;
+ case CompositePlusLighter:
+ target = kCGBlendModePlusLighter;
+ break;
+ }
+ CGContextSetBlendMode(platformContext(), target);
+}
+#endif
+
+}
+
diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
new file mode 100644
index 0000000..8827ff7
--- /dev/null
+++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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 <CoreGraphics/CGContext.h>
+
+namespace WebCore {
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate(CGContextRef cgContext)
+ : m_cgContext(cgContext)
+#if PLATFORM(WIN)
+ , m_hdc(0)
+ , m_transparencyCount(0)
+#endif
+ , m_userToDeviceTransformKnownToBeIdentity(false)
+ {
+ CGContextRetain(m_cgContext);
+ }
+
+ ~GraphicsContextPlatformPrivate()
+ {
+ CGContextRelease(m_cgContext);
+ }
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+ // These methods do nothing on Mac.
+ void save() {}
+ void restore() {}
+ void clip(const FloatRect&) {}
+ void clip(const Path&) {}
+ void scale(const FloatSize&) {}
+ void rotate(float) {}
+ void translate(float, float) {}
+ void concatCTM(const AffineTransform&) {}
+ void beginTransparencyLayer() {}
+ void endTransparencyLayer() {}
+#endif
+
+#if PLATFORM(WIN)
+ // On Windows, we need to update the HDC for form controls to draw in the right place.
+ void save();
+ void restore();
+ void clip(const FloatRect&);
+ void clip(const Path&);
+ void scale(const FloatSize&);
+ void rotate(float);
+ void translate(float, float);
+ void concatCTM(const AffineTransform&);
+ void beginTransparencyLayer() { m_transparencyCount++; }
+ void endTransparencyLayer() { m_transparencyCount--; }
+
+ HDC m_hdc;
+ unsigned m_transparencyCount;
+#endif
+
+ CGContextRef m_cgContext;
+ bool m_userToDeviceTransformKnownToBeIdentity;
+};
+
+}
diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
new file mode 100644
index 0000000..502313b
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "Base64.h"
+#include "BitmapImage.h"
+#include "CString.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "PlatformString.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/Assertions.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/RetainPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize&)
+ : m_data(0)
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ success = false; // Make early return mean failure.
+ unsigned bytesPerRow;
+ if (size.width() < 0 || size.height() < 0)
+ return;
+ bytesPerRow = size.width();
+ if (!grayScale) {
+ // Protect against overflow
+ if (bytesPerRow > 0x3FFFFFFF)
+ return;
+ bytesPerRow *= 4;
+ }
+
+ m_data.m_data = tryFastCalloc(size.height(), bytesPerRow);
+ ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0);
+
+ CGColorSpaceRef colorSpace = grayScale ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
+ CGContextRef cgContext = CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow,
+ colorSpace, grayScale ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast);
+ CGColorSpaceRelease(colorSpace);
+ if (!cgContext)
+ return;
+
+ m_context.set(new GraphicsContext(cgContext));
+ m_context->scale(FloatSize(1, -1));
+ m_context->translate(0, -size.height());
+ CGContextRelease(cgContext);
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+ fastFree(m_data.m_data);
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+Image* ImageBuffer::image() const
+{
+ if (!m_image) {
+ // It's assumed that if image() is called, the actual rendering to the
+ // GraphicsContext must be done.
+ ASSERT(context());
+ CGImageRef cgImage = CGBitmapContextCreateImage(context()->platformContext());
+ // BitmapImage will release the passed in CGImage on destruction
+ m_image = BitmapImage::create(cgImage);
+ }
+ return m_image.get();
+}
+
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
+{
+ PassRefPtr<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());
+
+ 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;
+
+ unsigned srcBytesPerRow = 4 * m_size.width();
+ unsigned destBytesPerRow = 4 * rect.width();
+
+ // ::create ensures that all ImageBuffers have valid data, so we don't need to check it here.
+ unsigned char* srcRows = reinterpret_cast<unsigned char*>(m_data.m_data) + originy * srcBytesPerRow + originx * 4;
+ unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
+ for (int y = 0; y < numRows; ++y) {
+ for (int x = 0; x < numColumns; x++) {
+ int basex = x * 4;
+ if (unsigned char alpha = srcRows[basex + 3]) {
+ destRows[basex] = (srcRows[basex] * 255) / alpha;
+ destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha;
+ destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha;
+ destRows[basex + 3] = alpha;
+ } else
+ reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ }
+ srcRows += srcBytesPerRow;
+ destRows += 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;
+
+ unsigned srcBytesPerRow = 4 * source->width();
+ unsigned destBytesPerRow = 4 * m_size.width();
+
+ 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++) {
+ int basex = x * 4;
+ unsigned char alpha = srcRows[basex + 3];
+ if (alpha != 255) {
+ destRows[basex] = (srcRows[basex] * alpha + 254) / 255;
+ destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255;
+ destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255;
+ destRows[basex + 3] = alpha;
+ } else
+ reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0];
+ }
+ destRows += destBytesPerRow;
+ srcRows += srcBytesPerRow;
+ }
+}
+
+static RetainPtr<CFStringRef> utiFromMIMEType(const String& mimeType)
+{
+#if PLATFORM(MAC)
+ RetainPtr<CFStringRef> mimeTypeCFString(AdoptCF, mimeType.createCFString());
+ return RetainPtr<CFStringRef>(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeTypeCFString.get(), 0));
+#else
+ // FIXME: Add Windows support for all the supported UTIs when a way to convert from MIMEType to UTI reliably is found.
+ // For now, only support PNG, JPEG, and GIF. See <rdar://problem/6095286>.
+ static const CFStringRef kUTTypePNG = CFSTR("public.png");
+ static const CFStringRef kUTTypeJPEG = CFSTR("public.jpeg");
+ static const CFStringRef kUTTypeGIF = CFSTR("com.compuserve.gif");
+
+ if (equalIgnoringCase(mimeType, "image/png"))
+ return kUTTypePNG;
+ if (equalIgnoringCase(mimeType, "image/jpeg"))
+ return kUTTypeJPEG;
+ if (equalIgnoringCase(mimeType, "image/gif"))
+ return kUTTypeGIF;
+
+ ASSERT_NOT_REACHED();
+ return kUTTypePNG;
+#endif
+}
+
+String ImageBuffer::toDataURL(const String& mimeType) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context()->platformContext()));
+ if (!image)
+ return "data:,";
+
+ size_t width = CGImageGetWidth(image.get());
+ size_t height = CGImageGetHeight(image.get());
+
+ OwnArrayPtr<uint32_t> imageData(new uint32_t[width * height]);
+ if (!imageData)
+ return "data:,";
+
+ RetainPtr<CGImageRef> transformedImage(AdoptCF, CGBitmapContextCreateImage(context()->platformContext()));
+ if (!transformedImage)
+ return "data:,";
+
+ RetainPtr<CFMutableDataRef> transformedImageData(AdoptCF, CFDataCreateMutable(kCFAllocatorDefault, 0));
+ if (!transformedImageData)
+ return "data:,";
+
+ RetainPtr<CGImageDestinationRef> imageDestination(AdoptCF, CGImageDestinationCreateWithData(transformedImageData.get(),
+ utiFromMIMEType(mimeType).get(), 1, 0));
+ if (!imageDestination)
+ return "data:,";
+
+ CGImageDestinationAddImage(imageDestination.get(), transformedImage.get(), 0);
+ CGImageDestinationFinalize(imageDestination.get());
+
+ Vector<char> in;
+ in.append(CFDataGetBytePtr(transformedImageData.get()), CFDataGetLength(transformedImageData.get()));
+
+ Vector<char> out;
+ base64Encode(in, out);
+ out.append('\0');
+
+ return String::format("data:%s;base64,%s", mimeType.utf8().data(), out.data());
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/cg/ImageBufferData.h b/WebCore/platform/graphics/cg/ImageBufferData.h
new file mode 100644
index 0000000..5e6fc4c
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageBufferData.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ void* m_data;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp
new file mode 100644
index 0000000..8609c46
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "BitmapImage.h"
+
+#if PLATFORM(CG)
+
+#include "AffineTransform.h"
+#include "FloatConversion.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include "PDFDocumentImage.h"
+#include "PlatformString.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
+#include "WebCoreSystemInterface.h"
+#endif
+
+#if PLATFORM(WIN)
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+namespace WebCore {
+
+void FrameData::clear()
+{
+ 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.
+ }
+}
+
+// ================================================
+// Image Class
+// ================================================
+
+BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ CGFloat width = CGImageGetWidth(cgImage);
+ CGFloat height = CGImageGetHeight(cgImage);
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = cgImage;
+ m_frames[0].m_hasAlpha = true;
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+// Drawing Routines
+
+void BitmapImage::checkForSolidColor()
+{
+ if (frameCount() > 1)
+ m_isSolidColor = false;
+ else {
+ CGImageRef image = frameAtIndex(0);
+
+ // Currently we only check for solid color in the important special case of a 1x1 image.
+ if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
+ unsigned char pixel[4]; // RGBA
+ CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
+ CGContextRef bmap = CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), space,
+ kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
+ if (bmap) {
+ GraphicsContext(bmap).setCompositeOperation(CompositeCopy);
+ CGRect dst = { {0, 0}, {1, 1} };
+ CGContextDrawImage(bmap, dst, image);
+ if (pixel[3] == 0)
+ m_solidColor = Color(0, 0, 0, 0);
+ else
+ m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]);
+ m_isSolidColor = true;
+ CFRelease(bmap);
+ }
+ CFRelease(space);
+ }
+ }
+}
+
+CGImageRef BitmapImage::getCGImageRef()
+{
+ return frameAtIndex(0);
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp)
+{
+ startAnimation();
+
+ CGImageRef image = frameAtIndex(m_currentFrame);
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, destRect, solidColor(), compositeOp);
+ return;
+ }
+
+ float currHeight = CGImageGetHeight(image);
+ if (currHeight <= srcRect.y())
+ return;
+
+ CGContextRef context = ctxt->platformContext();
+ ctxt->save();
+
+ bool shouldUseSubimage = false;
+
+ // If the source rect is a subportion of the image, then we compute an inflated destination rect that will hold the entire image
+ // and then set a clip to the portion that we want to display.
+ FloatRect adjustedDestRect = destRect;
+ FloatSize selfSize = currentFrameSize();
+ if (srcRect.size() != selfSize) {
+ CGInterpolationQuality interpolationQuality = CGContextGetInterpolationQuality(context);
+ // When the image is scaled using high-quality interpolation, we create a temporary CGImage
+ // containing only the portion we want to display. We need to do this because high-quality
+ // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed
+ // into the destination rect. See <rdar://problem/6112909>.
+ shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && srcRect.size() != destRect.size();
+ if (shouldUseSubimage) {
+ image = CGImageCreateWithImageInRect(image, srcRect);
+ if (currHeight < srcRect.bottom()) {
+ ASSERT(CGImageGetHeight(image) == currHeight - CGRectIntegral(srcRect).origin.y);
+ adjustedDestRect.setHeight(destRect.height() / srcRect.height() * CGImageGetHeight(image));
+ }
+ } else {
+ float xScale = srcRect.width() / destRect.width();
+ float yScale = srcRect.height() / destRect.height();
+
+ adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale));
+ adjustedDestRect.setSize(FloatSize(selfSize.width() / xScale, selfSize.height() / yScale));
+
+ CGContextClipToRect(context, destRect);
+ }
+ }
+
+ // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly.
+ if (!shouldUseSubimage && currHeight < selfSize.height())
+ adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height());
+
+ // Flip the coords.
+ ctxt->setCompositeOperation(compositeOp);
+ CGContextTranslateCTM(context, adjustedDestRect.x(), adjustedDestRect.bottom());
+ CGContextScaleCTM(context, 1, -1);
+ adjustedDestRect.setLocation(FloatPoint());
+
+ // Draw the image.
+ CGContextDrawImage(context, adjustedDestRect, image);
+
+ if (shouldUseSubimage)
+ CGImageRelease(image);
+
+ ctxt->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void Image::drawPatternCallback(void* info, CGContextRef context)
+{
+ CGImageRef image = (CGImageRef)info;
+ CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect(0, 0, CGImageGetWidth(image), CGImageGetHeight(image))), image);
+}
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
+{
+ if (!nativeImageForCurrentFrame())
+ return;
+
+ ASSERT(patternTransform.isInvertible());
+ if (!patternTransform.isInvertible())
+ // Avoid a hang under CGContextDrawTiledImage on release builds.
+ return;
+
+ CGContextRef context = ctxt->platformContext();
+ ctxt->save();
+ CGContextClipToRect(context, destRect);
+ ctxt->setCompositeOperation(op);
+ CGContextTranslateCTM(context, destRect.x(), destRect.y() + destRect.height());
+ CGContextScaleCTM(context, 1, -1);
+
+ // Compute the scaled tile size.
+ float scaledTileHeight = tileRect.height() * narrowPrecisionToFloat(patternTransform.d());
+
+ // We have to adjust the phase to deal with the fact we're in Cartesian space now (with the bottom left corner of destRect being
+ // the origin).
+ float adjustedX = phase.x() - destRect.x() + tileRect.x() * narrowPrecisionToFloat(patternTransform.a()); // We translated the context so that destRect.x() is the origin, so subtract it out.
+ float adjustedY = destRect.height() - (phase.y() - destRect.y() + tileRect.y() * narrowPrecisionToFloat(patternTransform.d()) + scaledTileHeight);
+
+ CGImageRef tileImage = nativeImageForCurrentFrame();
+ float h = CGImageGetHeight(tileImage);
+
+ CGImageRef subImage;
+ if (tileRect.size() == size())
+ subImage = tileImage;
+ else {
+ // Copying a sub-image out of a partially-decoded image stops the decoding of the original image. It should never happen
+ // because sub-images are only used for border-image, which only renders when the image is fully decoded.
+ ASSERT(h == height());
+ subImage = CGImageCreateWithImageInRect(tileImage, tileRect);
+ }
+
+#ifndef BUILDING_ON_TIGER
+ // Leopard has an optimized call for the tiling of image patterns, but we can only use it if the image has been decoded enough that
+ // 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.
+ float scaledTileWidth = tileRect.width() * narrowPrecisionToFloat(patternTransform.a());
+ float w = CGImageGetWidth(tileImage);
+ if (w == size().width() && h == size().height())
+ CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage);
+ else {
+#endif
+
+ // On Leopard, this code now only runs for partially decoded images whose buffers do not yet match the overall size of the image.
+ // On Tiger this code runs all the time. This code is suboptimal because the pattern does not reference the image directly, and the
+ // pattern is destroyed before exiting the function. This means any decoding the pattern does doesn't end up cached anywhere, so we
+ // redecode every time we paint.
+ static const CGPatternCallbacks patternCallbacks = { 0, drawPatternCallback, NULL };
+ CGAffineTransform matrix = CGAffineTransformMake(narrowPrecisionToCGFloat(patternTransform.a()), 0, 0, narrowPrecisionToCGFloat(patternTransform.d()), adjustedX, adjustedY);
+ matrix = CGAffineTransformConcat(matrix, CGContextGetCTM(context));
+ // The top of a partially-decoded image is drawn at the bottom of the tile. Map it to the top.
+ matrix = CGAffineTransformTranslate(matrix, 0, size().height() - h);
+ CGPatternRef pattern = CGPatternCreate(subImage, CGRectMake(0, 0, tileRect.width(), tileRect.height()),
+ matrix, tileRect.width(), tileRect.height(),
+ kCGPatternTilingConstantSpacing, true, &patternCallbacks);
+ if (pattern == NULL) {
+ if (subImage != tileImage)
+ CGImageRelease(subImage);
+ ctxt->restore();
+ return;
+ }
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
+
+ CGFloat alpha = 1;
+ CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha);
+ CGContextSetFillColorSpace(context, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+ CGPatternRelease(pattern);
+
+ // FIXME: Really want a public API for this. It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy).
+ wkSetPatternBaseCTM(context, CGAffineTransformIdentity);
+ CGContextSetPatternPhase(context, CGSizeZero);
+
+ CGContextSetFillColorWithColor(context, color);
+ CGContextFillRect(context, CGContextGetClipBoundingBox(context));
+
+ CGColorRelease(color);
+
+#ifndef BUILDING_ON_TIGER
+ }
+#endif
+
+ if (subImage != tileImage)
+ CGImageRelease(subImage);
+ ctxt->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
new file mode 100644
index 0000000..73907c9
--- /dev/null
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 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 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 "ImageSource.h"
+
+#if PLATFORM(CG)
+
+#include "IntSize.h"
+#include "SharedBuffer.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
+
+ImageSource::ImageSource()
+ : m_decoder(0)
+{
+}
+
+ImageSource::~ImageSource()
+{
+ clear();
+}
+
+void ImageSource::clear()
+{
+ if (m_decoder) {
+ CFRelease(m_decoder);
+ m_decoder = 0;
+ }
+}
+
+CFDictionaryRef imageSourceOptions()
+{
+ static CFDictionaryRef options;
+
+ if (!options) {
+ const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
+ const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue };
+ options = CFDictionaryCreate(NULL, keys, values, 2,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+ return options;
+}
+
+bool ImageSource::initialized() const
+{
+ return m_decoder;
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (!m_decoder)
+ m_decoder = CGImageSourceCreateIncremental(NULL);
+#if PLATFORM(MAC)
+ // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability
+ // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.
+ CFDataRef cfData = data->createCFData();
+#else
+ // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the
+ // scenes. We use CFDataCreateWithBytesNoCopy in that case.
+ CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), kCFAllocatorNull);
+#endif
+ CGImageSourceUpdateData(m_decoder, cfData, allDataReceived);
+ CFRelease(cfData);
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ bool result = false;
+ CGImageSourceStatus imageSourceStatus = CGImageSourceGetStatus(m_decoder);
+
+ // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!
+ if (imageSourceStatus >= kCGImageStatusIncomplete) {
+ CFDictionaryRef image0Properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions());
+ if (image0Properties) {
+ CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelWidth);
+ CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelHeight);
+ result = widthNumber && heightNumber;
+ CFRelease(image0Properties);
+ }
+ }
+
+ return result;
+}
+
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
+{
+ IntSize result;
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
+ if (properties) {
+ int w = 0, h = 0;
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &w);
+ num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &h);
+ result = IntSize(w, h);
+ CFRelease(properties);
+ }
+ return result;
+}
+
+IntSize ImageSource::size() const
+{
+ return frameSizeAtIndex(0);
+}
+
+int ImageSource::repetitionCount()
+{
+ int result = cAnimationLoopOnce; // No property means loop once.
+ if (!initialized())
+ return result;
+
+ // A property with value 0 means loop forever.
+ CFDictionaryRef properties = CGImageSourceCopyProperties(m_decoder, imageSourceOptions());
+ if (properties) {
+ CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
+ if (gifProperties) {
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &result);
+ } else
+ result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate.
+
+ CFRelease(properties);
+ }
+
+ return result;
+}
+
+size_t ImageSource::frameCount() const
+{
+ return m_decoder ? CGImageSourceGetCount(m_decoder) : 0;
+}
+
+CGImageRef ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!initialized())
+ return 0;
+
+ CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions());
+ CFStringRef imageUTI = CGImageSourceGetType(m_decoder);
+ static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
+ if (!imageUTI || !CFEqual(imageUTI, xbmUTI))
+ return image;
+
+ // If it is an xbm image, mask out all the white areas to render them transparent.
+ const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255};
+ CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors);
+ if (!maskedImage)
+ return image;
+
+ CGImageRelease(image);
+ return maskedImage;
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete;
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ if (!initialized())
+ return 0;
+
+ float duration = 0;
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
+ if (properties) {
+ CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
+ if (typeProperties) {
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime);
+ if (num)
+ CFNumberGetValue(num, kCFNumberFloatType, &duration);
+ }
+ CFRelease(properties);
+ }
+
+ // 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.
+ if (duration < 0.051f)
+ return 0.100f;
+ return duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ // 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.
+ // FIXME: Could return false for JPEG and other non-transparent image formats.
+ // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary
+ // to determine whether or not a transparent color was defined.
+ return true;
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/IntPointCG.cpp b/WebCore/platform/graphics/cg/IntPointCG.cpp
new file mode 100644
index 0000000..95dbe5f
--- /dev/null
+++ b/WebCore/platform/graphics/cg/IntPointCG.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "IntPoint.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const CGPoint& p) : m_x(static_cast<int>(p.x)), m_y(static_cast<int>(p.y))
+{
+}
+
+IntPoint::operator CGPoint() const
+{
+ return CGPointMake(m_x, m_y);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/IntRectCG.cpp b/WebCore/platform/graphics/cg/IntRectCG.cpp
new file mode 100644
index 0000000..73fd63f
--- /dev/null
+++ b/WebCore/platform/graphics/cg/IntRectCG.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, 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 "IntRect.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+IntRect::operator CGRect() const
+{
+ return CGRectMake(x(), y(), width(), height());
+}
+
+IntRect enclosingIntRect(const CGRect& rect)
+{
+ int l = static_cast<int>(floorf(rect.origin.x));
+ int t = static_cast<int>(floorf(rect.origin.y));
+ int r = static_cast<int>(ceilf(CGRectGetMaxX(rect)));
+ int b = static_cast<int>(ceilf(CGRectGetMaxY(rect)));
+ return IntRect(l, t, r - l, b - t);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/IntSizeCG.cpp b/WebCore/platform/graphics/cg/IntSizeCG.cpp
new file mode 100644
index 0000000..d8e8c83
--- /dev/null
+++ b/WebCore/platform/graphics/cg/IntSizeCG.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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 "IntSize.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+IntSize::IntSize(const CGSize& s) : m_width(static_cast<int>(s.width)), m_height(static_cast<int>(s.height))
+{
+}
+
+IntSize::operator CGSize() const
+{
+ return CGSizeMake(m_width, m_height);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
new file mode 100644
index 0000000..2578f08
--- /dev/null
+++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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.
+ */
+
+#define _USE_MATH_DEFINES 1
+#include "config.h"
+#include "PDFDocumentImage.h"
+
+#if PLATFORM(CG)
+
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+PDFDocumentImage::PDFDocumentImage()
+ : Image(0) // PDFs don't animate
+ , m_document(0)
+ , m_rotation(0.0f)
+ , m_currentPage(-1)
+{
+}
+
+PDFDocumentImage::~PDFDocumentImage()
+{
+ CGPDFDocumentRelease(m_document);
+}
+
+IntSize PDFDocumentImage::size() const
+{
+ const float sina = sinf(-m_rotation);
+ const float cosa = cosf(-m_rotation);
+ const float width = m_mediaBox.size().width();
+ const float height = m_mediaBox.size().height();
+ const float rotWidth = width * cosa - height * sina;
+ const float rotHeight = width * sina + height * cosa;
+
+ return IntSize((int)(fabsf(rotWidth) + 0.5f), (int)(fabsf(rotHeight) + 0.5f));
+}
+
+bool PDFDocumentImage::dataChanged(bool allDataReceived)
+{
+ if (allDataReceived && !m_document) {
+#if PLATFORM(MAC)
+ // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability
+ // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.
+ CFDataRef data = m_data->createCFData();
+#else
+ // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the
+ // scenes. We use CFDataCreateWithBytesNoCopy in that case.
+ CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(m_data->data()), m_data->size(), kCFAllocatorNull);
+#endif
+ CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
+ CFRelease(data);
+ m_document = CGPDFDocumentCreateWithProvider(dataProvider);
+ CGDataProviderRelease(dataProvider);
+ setCurrentPage(0);
+ }
+ return m_document; // return true if size is available
+}
+
+void PDFDocumentImage::adjustCTM(GraphicsContext* context) const
+{
+ // rotate the crop box and calculate bounding box
+ float sina = sinf(-m_rotation);
+ float cosa = cosf(-m_rotation);
+ float width = m_cropBox.width();
+ float height = m_cropBox.height();
+
+ // calculate rotated x and y edges of the corp box. if they're negative, it means part of the image has
+ // been rotated outside of the bounds and we need to shift over the image so it lies inside the bounds again
+ CGPoint rx = CGPointMake(width * cosa, width * sina);
+ CGPoint ry = CGPointMake(-height * sina, height * cosa);
+
+ // adjust so we are at the crop box origin
+ const CGFloat zero = 0;
+ CGContextTranslateCTM(context->platformContext(), floorf(-min(zero, min(rx.x, ry.x))), floorf(-min(zero, min(rx.y, ry.y))));
+
+ // rotate -ve to remove rotation
+ CGContextRotateCTM(context->platformContext(), -m_rotation);
+
+ // shift so we are completely within media box
+ CGContextTranslateCTM(context->platformContext(), m_mediaBox.x() - m_cropBox.x(), m_mediaBox.y() - m_cropBox.y());
+}
+
+void PDFDocumentImage::setCurrentPage(int page)
+{
+ if (!m_document)
+ return;
+
+ if (page == m_currentPage)
+ return;
+
+ if (!(page >= 0 && page < pageCount()))
+ return;
+
+ m_currentPage = page;
+
+ CGPDFPageRef cgPage = CGPDFDocumentGetPage(m_document, page + 1);
+
+ // get media box (guaranteed)
+ m_mediaBox = CGPDFPageGetBoxRect(cgPage, kCGPDFMediaBox);
+
+ // get crop box (not always there). if not, use media box
+ CGRect r = CGPDFPageGetBoxRect(cgPage, kCGPDFCropBox);
+ if (!CGRectIsEmpty(r))
+ m_cropBox = r;
+ else
+ m_cropBox = m_mediaBox;
+
+ // get page rotation angle
+ m_rotation = CGPDFPageGetRotationAngle(cgPage) * piFloat / 180.0f; // to radians
+}
+
+int PDFDocumentImage::pageCount() const
+{
+ return m_document ? CGPDFDocumentGetNumberOfPages(m_document) : 0;
+}
+
+void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op)
+{
+ if (!m_document || m_currentPage == -1)
+ return;
+
+ context->save();
+
+ context->setCompositeOperation(op);
+
+ float hScale = dstRect.width() / srcRect.width();
+ float vScale = dstRect.height() / srcRect.height();
+
+ // Scale and translate so the document is rendered in the correct location,
+ // including accounting for the fact that a GraphicsContext is always flipped
+ // and doing appropriate flipping.
+ CGContextTranslateCTM(context->platformContext(), dstRect.x() - srcRect.x() * hScale, dstRect.y() - srcRect.y() * vScale);
+ CGContextScaleCTM(context->platformContext(), hScale, vScale);
+ CGContextScaleCTM(context->platformContext(), 1, -1);
+ CGContextTranslateCTM(context->platformContext(), 0, -srcRect.height());
+ CGContextClipToRect(context->platformContext(), CGRectIntegral(srcRect));
+
+ // Rotate translate image into position according to doc properties.
+ adjustCTM(context);
+
+ CGContextTranslateCTM(context->platformContext(), -m_mediaBox.x(), -m_mediaBox.y());
+ CGContextDrawPDFPage(context->platformContext(), CGPDFDocumentGetPage(m_document, m_currentPage + 1));
+
+ context->restore();
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h
new file mode 100644
index 0000000..5c9d4e1
--- /dev/null
+++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "Image.h"
+
+#include "FloatRect.h"
+#include "GraphicsTypes.h"
+
+#if PLATFORM(CG)
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+ class GraphicsContext;
+
+ class PDFDocumentImage : public Image {
+ public:
+ static PassRefPtr<PDFDocumentImage> create()
+ {
+ return adoptRef(new PDFDocumentImage);
+ }
+ ~PDFDocumentImage();
+
+ virtual bool hasSingleSecurityOrigin() const { return true; }
+
+ virtual bool dataChanged(bool allDataReceived);
+
+ // 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 unsigned decodedSize() const { return 0; }
+
+ virtual IntSize size() const;
+
+ private:
+ PDFDocumentImage();
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
+
+ void setCurrentPage(int);
+ int pageCount() const;
+ void adjustCTM(GraphicsContext*) const;
+
+ CGPDFDocumentRef m_document;
+ FloatRect m_mediaBox;
+ FloatRect m_cropBox;
+ float m_rotation;
+ int m_currentPage;
+ };
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp
new file mode 100644
index 0000000..1382589
--- /dev/null
+++ b/WebCore/platform/graphics/cg/PathCG.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * 2006, 2008 Rob Buis <buis@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#if PLATFORM(CG)
+
+#include "AffineTransform.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+Path::Path()
+ : m_path(CGPathCreateMutable())
+{
+}
+
+Path::~Path()
+{
+ CGPathRelease(m_path);
+}
+
+Path::Path(const Path& other)
+ : m_path(CGPathCreateMutableCopy(other.m_path))
+{
+}
+
+Path& Path::operator=(const Path& other)
+{
+ CGMutablePathRef path = CGPathCreateMutableCopy(other.m_path);
+ CGPathRelease(m_path);
+ m_path = path;
+ return *this;
+}
+
+
+static void copyClosingSubpathsApplierFunction(void* info, const CGPathElement* element)
+{
+ CGMutablePathRef path = static_cast<CGMutablePathRef>(info);
+ CGPoint* points = element->points;
+
+ switch (element->type) {
+ case kCGPathElementMoveToPoint:
+ if (!CGPathIsEmpty(path)) // to silence a warning when trying to close an empty path
+ CGPathCloseSubpath(path); // This is the only change from CGPathCreateMutableCopy
+ CGPathMoveToPoint(path, 0, points[0].x, points[0].y);
+ break;
+ case kCGPathElementAddLineToPoint:
+ CGPathAddLineToPoint(path, 0, points[0].x, points[0].y);
+ break;
+ case kCGPathElementAddQuadCurveToPoint:
+ CGPathAddQuadCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y);
+ break;
+ case kCGPathElementAddCurveToPoint:
+ CGPathAddCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y);
+ break;
+ case kCGPathElementCloseSubpath:
+ CGPathCloseSubpath(path);
+ break;
+ }
+}
+
+static CGMutablePathRef copyCGPathClosingSubpaths(CGPathRef originalPath)
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+ CGPathApply(originalPath, path, copyClosingSubpathsApplierFunction);
+ CGPathCloseSubpath(path);
+ return path;
+}
+
+bool Path::contains(const FloatPoint &point, WindRule rule) const
+{
+ if (!boundingRect().contains(point))
+ return false;
+
+ // CGPathContainsPoint returns false for non-closed paths, as a work-around, we copy and close the path first. Radar 4758998 asks for a better CG API to use
+ CGMutablePathRef path = copyCGPathClosingSubpaths(m_path);
+ bool ret = CGPathContainsPoint(path, 0, point, rule == RULE_EVENODD ? true : false);
+ CGPathRelease(path);
+ return ret;
+}
+
+void Path::translate(const FloatSize& size)
+{
+ CGAffineTransform translation = CGAffineTransformMake(1, 0, 0, 1, size.width(), size.height());
+ CGMutablePathRef newPath = CGPathCreateMutable();
+ CGPathAddPath(newPath, &translation, m_path);
+ CGPathRelease(m_path);
+ m_path = newPath;
+}
+
+FloatRect Path::boundingRect() const
+{
+ return CGPathGetBoundingBox(m_path);
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ CGPathMoveToPoint(m_path, 0, point.x(), point.y());
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ CGPathAddLineToPoint(m_path, 0, p.x(), p.y());
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ CGPathAddQuadCurveToPoint(m_path, 0, cp.x(), cp.y(), p.x(), p.y());
+}
+
+void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ CGPathAddCurveToPoint(m_path, 0, cp1.x(), cp1.y(), cp2.x(), cp2.y(), p.x(), p.y());
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ CGPathAddArcToPoint(m_path, 0, p1.x(), p1.y(), p2.x(), p2.y(), radius);
+}
+
+void Path::closeSubpath()
+{
+ if (!CGPathIsEmpty(m_path)) // to silence a warning when trying to close an empty path
+ CGPathCloseSubpath(m_path);
+}
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool clockwise)
+{
+ // Workaround for <rdar://problem/5189233> CGPathAddArc hangs or crashes when passed inf as start or end angle
+ if (isfinite(sa) && isfinite(ea))
+ CGPathAddArc(m_path, 0, p.x(), p.y(), r, sa, ea, clockwise);
+}
+
+void Path::addRect(const FloatRect& r)
+{
+ CGPathAddRect(m_path, 0, r);
+}
+
+void Path::addEllipse(const FloatRect& r)
+{
+ CGPathAddEllipseInRect(m_path, 0, r);
+}
+
+void Path::clear()
+{
+ CGPathRelease(m_path);
+ m_path = CGPathCreateMutable();
+}
+
+bool Path::isEmpty() const
+{
+ return CGPathIsEmpty(m_path);
+ }
+
+static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *element)
+{
+ CFMutableStringRef string = (CFMutableStringRef)info;
+ CFStringRef typeString = CFSTR("");
+ CGPoint* points = element->points;
+ switch (element->type) {
+ case kCGPathElementMoveToPoint:
+ CFStringAppendFormat(string, 0, CFSTR("M%.2f,%.2f "), points[0].x, points[0].y);
+ break;
+ case kCGPathElementAddLineToPoint:
+ CFStringAppendFormat(string, 0, CFSTR("L%.2f,%.2f "), points[0].x, points[0].y);
+ break;
+ case kCGPathElementAddQuadCurveToPoint:
+ CFStringAppendFormat(string, 0, CFSTR("Q%.2f,%.2f,%.2f,%.2f "),
+ points[0].x, points[0].y, points[1].x, points[1].y);
+ break;
+ case kCGPathElementAddCurveToPoint:
+ CFStringAppendFormat(string, 0, CFSTR("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f "),
+ points[0].x, points[0].y, points[1].x, points[1].y,
+ points[2].x, points[2].y);
+ break;
+ case kCGPathElementCloseSubpath:
+ typeString = CFSTR("X"); break;
+ }
+}
+
+static CFStringRef CFStringFromCGPath(CGPathRef path)
+{
+ if (!path)
+ return 0;
+
+ CFMutableStringRef string = CFStringCreateMutable(NULL, 0);
+ CGPathApply(path, string, CGPathToCFStringApplierFunction);
+ CFStringTrimWhitespace(string);
+
+
+ return string;
+}
+
+
+#pragma mark -
+#pragma mark Path Management
+
+String Path::debugString() const
+{
+ String result;
+ if (!isEmpty()) {
+ CFStringRef pathString = CFStringFromCGPath(m_path);
+ result = String(pathString);
+ CFRelease(pathString);
+ }
+ return result;
+}
+
+struct PathApplierInfo {
+ void* info;
+ PathApplierFunction function;
+};
+
+void CGPathApplierToPathApplier(void *info, const CGPathElement *element)
+{
+ PathApplierInfo* pinfo = (PathApplierInfo*)info;
+ FloatPoint points[3];
+ PathElement pelement;
+ pelement.type = (PathElementType)element->type;
+ pelement.points = points;
+ CGPoint* cgPoints = element->points;
+ switch (element->type) {
+ case kCGPathElementMoveToPoint:
+ case kCGPathElementAddLineToPoint:
+ points[0] = cgPoints[0];
+ break;
+ case kCGPathElementAddQuadCurveToPoint:
+ points[0] = cgPoints[0];
+ points[1] = cgPoints[1];
+ break;
+ case kCGPathElementAddCurveToPoint:
+ points[0] = cgPoints[0];
+ points[1] = cgPoints[1];
+ points[2] = cgPoints[2];
+ break;
+ case kCGPathElementCloseSubpath:
+ break;
+ }
+ pinfo->function(pinfo->info, &pelement);
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ PathApplierInfo pinfo;
+ pinfo.info = info;
+ pinfo.function = function;
+ CGPathApply(m_path, &pinfo, CGPathApplierToPathApplier);
+}
+
+void Path::transform(const AffineTransform& transform)
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+ CGAffineTransform transformCG = transform;
+ CGPathAddPath(path, &transformCG, m_path);
+ CGPathRelease(m_path);
+ m_path = path;
+}
+
+}
+
+#endif // PLATFORM(CG)
diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp
new file mode 100644
index 0000000..e1f7a69
--- /dev/null
+++ b/WebCore/platform/graphics/cg/PatternCG.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 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
+ * 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 "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+static void patternCallback(void* info, CGContextRef context)
+{
+ CGImageRef platformImage = static_cast<Image*>(info)->getCGImageRef();
+ if (!platformImage)
+ return;
+
+ CGRect rect = GraphicsContext(context).roundToDevicePixels(
+ FloatRect(0, 0, CGImageGetWidth(platformImage), CGImageGetHeight(platformImage)));
+ CGContextDrawImage(context, rect, platformImage);
+}
+
+static void patternReleaseCallback(void* info)
+{
+ static_cast<Image*>(info)->deref();
+}
+
+CGPatternRef Pattern::createPlatformPattern(const AffineTransform& transform) const
+{
+ IntRect tileRect = tileImage()->rect();
+
+ AffineTransform patternTransform = transform;
+ patternTransform.scale(1, -1);
+ patternTransform.translate(0, -tileRect.height());
+
+ // If FLT_MAX should also be used for xStep or yStep, nothing is rendered. Using fractions of FLT_MAX also
+ // result in nothing being rendered.
+ // INT_MAX is almost correct, but there seems to be some number wrapping occuring making the fill
+ // pattern is not filled correctly.
+ // So, just pick a really large number that works.
+ float xStep = m_repeatX ? tileRect.width() : (100000000.0f);
+ float yStep = m_repeatY ? tileRect.height() : (100000000.0f);
+
+ // The pattern will release the tile when it's done rendering in patternReleaseCallback
+ tileImage()->ref();
+
+ const CGPatternCallbacks patternCallbacks = { 0, patternCallback, patternReleaseCallback };
+ return CGPatternCreate(tileImage(), tileRect, patternTransform, xStep, yStep,
+ kCGPatternTilingConstantSpacing, TRUE, &patternCallbacks);
+}
+
+}
diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp
new file mode 100644
index 0000000..7210367
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEBlend.cpp
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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"
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FEBlend.h"
+
+namespace WebCore {
+
+FEBlend::FEBlend(FilterEffect* in, FilterEffect* in2, BlendModeType mode)
+ : FilterEffect()
+ , m_in(in)
+ , m_in2(in2)
+ , m_mode(mode)
+{
+}
+
+PassRefPtr<FEBlend> FEBlend::create(FilterEffect* in, FilterEffect* in2, BlendModeType mode)
+{
+ return adoptRef(new FEBlend(in, in2, mode));
+}
+
+FilterEffect* FEBlend::in2() const
+{
+ return m_in2.get();
+}
+
+void FEBlend::setIn2(FilterEffect* in2)
+{
+ m_in2 = in2;
+}
+
+BlendModeType FEBlend::blendMode() const
+{
+ return m_mode;
+}
+
+void FEBlend::setBlendMode(BlendModeType mode)
+{
+ m_mode = mode;
+}
+
+void FEBlend::apply()
+{
+}
+
+void FEBlend::dump()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h
new file mode 100644
index 0000000..b2835e8
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEBlend.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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 SVGFEBlend_h
+#define SVGFEBlend_h
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FilterEffect.h"
+
+namespace WebCore {
+
+ enum BlendModeType {
+ FEBLEND_MODE_UNKNOWN = 0,
+ FEBLEND_MODE_NORMAL = 1,
+ FEBLEND_MODE_MULTIPLY = 2,
+ FEBLEND_MODE_SCREEN = 3,
+ FEBLEND_MODE_DARKEN = 4,
+ FEBLEND_MODE_LIGHTEN = 5
+ };
+
+ class FEBlend : public FilterEffect {
+ public:
+ static PassRefPtr<FEBlend> create(FilterEffect*, FilterEffect*, BlendModeType);
+
+ FilterEffect* in2() const;
+ void setIn2(FilterEffect*);
+
+ BlendModeType blendMode() const;
+ void setBlendMode(BlendModeType);
+
+ virtual void apply();
+ virtual void dump();
+
+ private:
+ FEBlend(FilterEffect*, FilterEffect*, BlendModeType);
+
+ RefPtr<FilterEffect> m_in;
+ RefPtr<FilterEffect> m_in2;
+ BlendModeType m_mode;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
+
+#endif // SVGFEBlend_h
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
new file mode 100644
index 0000000..f783106
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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"
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FEColorMatrix.h"
+
+namespace WebCore {
+
+FEColorMatrix::FEColorMatrix(FilterEffect* in, ColorMatrixType type, const Vector<float>& values)
+ : FilterEffect()
+ , m_in(in)
+ , m_type(type)
+ , m_values(values)
+{
+}
+
+PassRefPtr<FEColorMatrix> FEColorMatrix::create(FilterEffect* in, ColorMatrixType type, const Vector<float>& values)
+{
+ return adoptRef(new FEColorMatrix(in, type, values));
+}
+
+ColorMatrixType FEColorMatrix::type() const
+{
+ return m_type;
+}
+
+void FEColorMatrix::setType(ColorMatrixType type)
+{
+ m_type = type;
+}
+
+const Vector<float>& FEColorMatrix::values() const
+{
+ return m_values;
+}
+
+void FEColorMatrix::setValues(const Vector<float> &values)
+{
+ m_values = values;
+}
+
+void FEColorMatrix::apply()
+{
+}
+
+void FEColorMatrix::dump()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.h b/WebCore/platform/graphics/filters/FEColorMatrix.h
new file mode 100644
index 0000000..d8193ed
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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 SVGFEColorMatrix_h
+#define SVGFEColorMatrix_h
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FilterEffect.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ enum ColorMatrixType {
+ FECOLORMATRIX_TYPE_UNKNOWN = 0,
+ FECOLORMATRIX_TYPE_MATRIX = 1,
+ FECOLORMATRIX_TYPE_SATURATE = 2,
+ FECOLORMATRIX_TYPE_HUEROTATE = 3,
+ FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4
+ };
+
+ class FEColorMatrix : public FilterEffect {
+ public:
+ static PassRefPtr<FEColorMatrix> create(FilterEffect*, ColorMatrixType, const Vector<float>&);
+
+ ColorMatrixType type() const;
+ void setType(ColorMatrixType);
+
+ const Vector<float>& values() const;
+ void setValues(const Vector<float>&);
+
+ virtual void apply();
+ virtual void dump();
+
+ private:
+ FEColorMatrix(FilterEffect*, ColorMatrixType, const Vector<float>&);
+
+ RefPtr<FilterEffect> m_in;
+ ColorMatrixType m_type;
+ Vector<float> m_values;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
+
+#endif // SVGFEColorMatrix_h
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
new file mode 100644
index 0000000..708ea3e
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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"
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FEComponentTransfer.h"
+
+namespace WebCore {
+
+FEComponentTransfer::FEComponentTransfer(FilterEffect* in, const ComponentTransferFunction& redFunc,
+ const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
+ : FilterEffect()
+ , m_in(in)
+ , m_redFunc(redFunc)
+ , m_greenFunc(greenFunc)
+ , m_blueFunc(blueFunc)
+ , m_alphaFunc(alphaFunc)
+{
+}
+
+PassRefPtr<FEComponentTransfer> FEComponentTransfer::create(FilterEffect* in, const ComponentTransferFunction& redFunc,
+ const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc)
+{
+ return adoptRef(new FEComponentTransfer(in, redFunc, greenFunc, blueFunc, alphaFunc));
+}
+
+ComponentTransferFunction FEComponentTransfer::redFunction() const
+{
+ return m_redFunc;
+}
+
+void FEComponentTransfer::setRedFunction(const ComponentTransferFunction& func)
+{
+ m_redFunc = func;
+}
+
+ComponentTransferFunction FEComponentTransfer::greenFunction() const
+{
+ return m_greenFunc;
+}
+
+void FEComponentTransfer::setGreenFunction(const ComponentTransferFunction& func)
+{
+ m_greenFunc = func;
+}
+
+ComponentTransferFunction FEComponentTransfer::blueFunction() const
+{
+ return m_blueFunc;
+}
+
+void FEComponentTransfer::setBlueFunction(const ComponentTransferFunction& func)
+{
+ m_blueFunc = func;
+}
+
+ComponentTransferFunction FEComponentTransfer::alphaFunction() const
+{
+ return m_alphaFunc;
+}
+
+void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func)
+{
+ m_alphaFunc = func;
+}
+
+void FEComponentTransfer::apply()
+{
+}
+
+void FEComponentTransfer::dump()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.h b/WebCore/platform/graphics/filters/FEComponentTransfer.h
new file mode 100644
index 0000000..20d70c0
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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 SVGFEComponentTransfer_h
+#define SVGFEComponentTransfer_h
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FilterEffect.h"
+#include "SVGFEDisplacementMap.h"
+
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ enum ComponentTransferType {
+ FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0,
+ FECOMPONENTTRANSFER_TYPE_IDENTITY = 1,
+ FECOMPONENTTRANSFER_TYPE_TABLE = 2,
+ FECOMPONENTTRANSFER_TYPE_DISCRETE = 3,
+ FECOMPONENTTRANSFER_TYPE_LINEAR = 4,
+ FECOMPONENTTRANSFER_TYPE_GAMMA = 5
+ };
+
+ struct ComponentTransferFunction {
+ ComponentTransferFunction()
+ : type(FECOMPONENTTRANSFER_TYPE_UNKNOWN)
+ , slope(0.0f)
+ , intercept(0.0f)
+ , amplitude(0.0f)
+ , exponent(0.0f)
+ , offset(0.0f)
+ {
+ }
+
+ ComponentTransferType type;
+
+ float slope;
+ float intercept;
+ float amplitude;
+ float exponent;
+ float offset;
+
+ Vector<float> tableValues;
+ };
+
+ class FEComponentTransfer : public FilterEffect {
+ public:
+ static PassRefPtr<FEComponentTransfer> create(FilterEffect*, const ComponentTransferFunction&,
+ const ComponentTransferFunction&, const ComponentTransferFunction&, const ComponentTransferFunction&);
+
+ ComponentTransferFunction redFunction() const;
+ void setRedFunction(const ComponentTransferFunction&);
+
+ ComponentTransferFunction greenFunction() const;
+ void setGreenFunction(const ComponentTransferFunction&);
+
+ ComponentTransferFunction blueFunction() const;
+ void setBlueFunction(const ComponentTransferFunction&);
+
+ ComponentTransferFunction alphaFunction() const;
+ void setAlphaFunction(const ComponentTransferFunction&);
+
+ virtual void apply();
+ virtual void dump();
+
+ private:
+ FEComponentTransfer(FilterEffect*,const ComponentTransferFunction&, const ComponentTransferFunction&,
+ const ComponentTransferFunction&, const ComponentTransferFunction&);
+
+ RefPtr<FilterEffect> m_in;
+ ComponentTransferFunction m_redFunc;
+ ComponentTransferFunction m_greenFunc;
+ ComponentTransferFunction m_blueFunc;
+ ComponentTransferFunction m_alphaFunc;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
+
+#endif // SVGFEComponentTransfer_h
diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp
new file mode 100644
index 0000000..0b5ce94
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEComposite.cpp
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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"
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FEComposite.h"
+
+namespace WebCore {
+
+FEComposite::FEComposite(FilterEffect* in, FilterEffect* in2, const CompositeOperationType& type,
+ const float& k1, const float& k2, const float& k3, const float& k4)
+ : FilterEffect()
+ , m_in(in)
+ , m_in2(in2)
+ , m_type(type)
+ , m_k1(k1)
+ , m_k2(k2)
+ , m_k3(k3)
+ , m_k4(k4)
+{
+}
+
+PassRefPtr<FEComposite> FEComposite::create(FilterEffect* in, FilterEffect* in2, const CompositeOperationType& type,
+ const float& k1, const float& k2, const float& k3, const float& k4)
+{
+ return adoptRef(new FEComposite(in, in2, type, k1, k2, k3, k4));
+}
+
+CompositeOperationType FEComposite::operation() const
+{
+ return m_type;
+}
+
+void FEComposite::setOperation(CompositeOperationType type)
+{
+ m_type = type;
+}
+
+float FEComposite::k1() const
+{
+ return m_k1;
+}
+
+void FEComposite::setK1(float k1)
+{
+ m_k1 = k1;
+}
+
+float FEComposite::k2() const
+{
+ return m_k2;
+}
+
+void FEComposite::setK2(float k2)
+{
+ m_k2 = k2;
+}
+
+float FEComposite::k3() const
+{
+ return m_k3;
+}
+
+void FEComposite::setK3(float k3)
+{
+ m_k3 = k3;
+}
+
+float FEComposite::k4() const
+{
+ return m_k4;
+}
+
+void FEComposite::setK4(float k4)
+{
+ m_k4 = k4;
+}
+
+void FEComposite::apply()
+{
+}
+
+void FEComposite::dump()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h
new file mode 100644
index 0000000..d205395
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEComposite.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@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
+ aint 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 SVGFEComposite_h
+#define SVGFEComposite_h
+
+#if ENABLE(SVG) && ENABLE(SVG_FILTERS)
+#include "FilterEffect.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+ enum CompositeOperationType {
+ FECOMPOSITE_OPERATOR_UNKNOWN = 0,
+ FECOMPOSITE_OPERATOR_OVER = 1,
+ FECOMPOSITE_OPERATOR_IN = 2,
+ FECOMPOSITE_OPERATOR_OUT = 3,
+ FECOMPOSITE_OPERATOR_ATOP = 4,
+ FECOMPOSITE_OPERATOR_XOR = 5,
+ FECOMPOSITE_OPERATOR_ARITHMETIC = 6
+ };
+
+ class FEComposite : public FilterEffect {
+ public:
+ static PassRefPtr<FEComposite> create(FilterEffect*, FilterEffect*, const CompositeOperationType&,
+ const float&, const float&, const float&, const float&);
+
+ CompositeOperationType operation() const;
+ void setOperation(CompositeOperationType);
+
+ float k1() const;
+ void setK1(float);
+
+ float k2() const;
+ void setK2(float);
+
+ float k3() const;
+ void setK3(float);
+
+ float k4() const;
+ void setK4(float);
+
+ virtual void apply();
+ virtual void dump();
+
+ private:
+ FEComposite(FilterEffect*, FilterEffect*, const CompositeOperationType&,
+ const float&, const float&, const float&, const float&);
+
+ RefPtr<FilterEffect> m_in;
+ RefPtr<FilterEffect> m_in2;
+ CompositeOperationType m_type;
+ float m_k1;
+ float m_k2;
+ float m_k3;
+ float m_k4;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG) && ENABLE(SVG_FILTERS)
+
+#endif // SVGFEComposite_h
diff --git a/WebCore/platform/graphics/gtk/ColorGtk.cpp b/WebCore/platform/graphics/gtk/ColorGtk.cpp
new file mode 100644
index 0000000..27f1b14
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/ColorGtk.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+Color::Color(const GdkColor& c)
+ : m_color(makeRGB(c.red >> 8, c.green >> 8, c.blue >> 8))
+ , m_valid(true)
+{
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp
new file mode 100644
index 0000000..d2b43cc
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCache.h"
+
+#include "Font.h"
+#include "SimpleFontData.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+ if (!FontPlatformData::init())
+ ASSERT_NOT_REACHED();
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+#if defined(USE_FREETYPE)
+ FcResult fresult;
+ FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->m_font);
+
+ if (!prim->m_fallbacks)
+ prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult);
+
+ FcFontSet* fs = prim->m_fallbacks;
+
+ for (int i = 0; i < fs->nfont; i++) {
+ FcPattern* fin = FcFontRenderPrepare(NULL, prim->m_pattern, fs->fonts[i]);
+ cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_pattern(fin);
+ FontPlatformData alternateFont(fontFace, font.fontDescription().computedPixelSize(), false, false);
+ cairo_font_face_destroy(fontFace);
+ alternateFont.m_pattern = fin;
+ SimpleFontData* sfd = getCachedFontData(&alternateFont);
+ if (sfd->containsCharacters(characters, length))
+ return sfd;
+ }
+#endif
+
+ return 0;
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ // 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");
+ return getCachedFontPlatformData(fontDescription, timesStr);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ return new FontPlatformData(fontDescription, family);
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..bb2e064
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+static void releaseData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ int error;
+
+ static FT_Library library = 0;
+ if (!library) {
+ error = FT_Init_FreeType(&library);
+ if (error) {
+ library = 0;
+ return 0;
+ }
+ }
+
+ FT_Face face;
+ error = FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer->data()), buffer->size(), 0, &face);
+ if (error)
+ return 0;
+
+ buffer->ref();
+ cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_ft_face(face, 0);
+
+ static cairo_user_data_key_t bufferKey;
+ cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData);
+
+ return new FontCustomPlatformData(fontFace);
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.h b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h
new file mode 100644
index 0000000..b36cc79
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.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 FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontRenderingMode.h"
+#include <wtf/Noncopyable.h>
+
+typedef struct _cairo_font_face cairo_font_face_t;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(cairo_font_face_t* fontFace)
+ : m_fontFace(fontFace)
+ {}
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
+
+ cairo_font_face_t* m_fontFace;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp
new file mode 100644
index 0000000..4f2f2bb
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+static void releaseData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ // FIXME: we need support in pango to read fonts from memory to implement this.y
+ return 0;
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp
new file mode 100644
index 0000000..288ba91
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontGtk.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (c) 2007 Hiroyuki Ikezoe
+ * Copyright (c) 2007 Kouhei Sutou
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Xan Lopez <xan@gnome.org>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * 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 "Font.h"
+
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+#include <cairo.h>
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+#if defined(USE_FREETYPE)
+#include <pango/pangofc-fontmap.h>
+#endif
+
+#if !defined(PANGO_VERSION_CHECK)
+// PANGO_VERSION_CHECK() and pango_layout_get_line_readonly() appeared in 1.5.2
+#define pango_layout_get_line_readonly pango_layout_get_line
+#define PANGO_VERSION_CHECK(major,minor,micro) 0
+#endif
+
+namespace WebCore {
+
+#define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
+#define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff)
+
+static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length)
+{
+ gboolean need_copy = FALSE;
+ int i;
+
+ for (i = 0; i < aLength; i++) {
+ if (!aText[i] || IS_LOW_SURROGATE(aText[i])) {
+ need_copy = TRUE;
+ break;
+ }
+ else if (IS_HIGH_SURROGATE(aText[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
+ i++;
+ else {
+ need_copy = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (need_copy) {
+
+ /* Pango doesn't correctly handle nuls. We convert them to 0xff. */
+ /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
+
+ UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0]));
+
+ /* don't need to reset i */
+ for (i = 0; i < aLength; i++) {
+ if (!p[i] || IS_LOW_SURROGATE(p[i]))
+ p[i] = 0xFFFD;
+ else if (IS_HIGH_SURROGATE(p[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
+ i++;
+ else
+ p[i] = 0xFFFD;
+ }
+ }
+
+ aText = p;
+ }
+
+ glong items_written;
+ text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL);
+ length = items_written;
+
+ if (need_copy)
+ g_free((gpointer)aText);
+
+}
+
+static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
+{
+ gchar* utf8 = 0;
+ gint new_length = 0;
+ utf16_to_utf8(characters, length, utf8, new_length);
+ if (!utf8)
+ return NULL;
+
+ if (from > 0) {
+ // discard the first 'from' characters
+ // FIXME: we should do this before the conversion probably
+ gchar* str_left = g_utf8_offset_to_pointer(utf8, from);
+ gchar* tmp = g_strdup(str_left);
+ g_free(utf8);
+ utf8 = tmp;
+ }
+
+ gchar* pos = utf8;
+ gint len = strlen(pos);
+ GString* ret = g_string_new_len(NULL, len);
+
+ // replace line break by space
+ while (len > 0) {
+ gint index, start;
+ pango_find_paragraph_boundary(pos, len, &index, &start);
+ g_string_append_len(ret, pos, index);
+ if (index == start)
+ break;
+ g_string_append_c(ret, ' ');
+ pos += start;
+ len -= start;
+ }
+ return g_string_free(ret, FALSE);
+}
+
+static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout)
+{
+#if defined(USE_FREETYPE)
+ if (font->primaryFont()->m_font.m_pattern) {
+ PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->m_font.m_pattern, FALSE);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+ }
+#elif defined(USE_PANGO)
+ if (font->primaryFont()->m_font.m_font) {
+ PangoFontDescription* desc = pango_font_describe(font->primaryFont()->m_font.m_font);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+ }
+#endif
+
+ pango_layout_set_auto_dir(layout, FALSE);
+
+ PangoContext* pangoContext = pango_layout_get_context(layout);
+ PangoDirection direction = run.rtl() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
+ pango_context_set_base_dir(pangoContext, direction);
+ PangoAttrList* list = pango_attr_list_new();
+ PangoAttribute* attr;
+
+ attr = pango_attr_size_new_absolute(font->pixelSize() * PANGO_SCALE);
+ attr->end_index = G_MAXUINT;
+ pango_attr_list_insert_before(list, attr);
+
+ if (!run.spacingDisabled()) {
+ attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE);
+ attr->end_index = G_MAXUINT;
+ pango_attr_list_insert_before(list, attr);
+ }
+
+ // Pango does not yet support synthesising small caps
+ // See http://bugs.webkit.org/show_bug.cgi?id=15610
+
+ pango_layout_set_attributes(layout, list);
+ pango_attr_list_unref(list);
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+ cairo_translate(cr, point.x(), point.y());
+
+ PangoLayout* layout = pango_cairo_create_layout(cr);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ // Our layouts are single line
+ PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
+
+ GdkRegion* partialRegion = NULL;
+ if (to - from != run.length()) {
+ // Clip the region of the run to be rendered
+ char* start = g_utf8_offset_to_pointer(utf8, from);
+ char* end = g_utf8_offset_to_pointer(start, to - from);
+ int ranges[] = {start - utf8, end - utf8};
+ partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1);
+ gdk_region_shrink(partialRegion, 0, -pixelSize());
+ }
+
+ Color fillColor = context->fillColor();
+ float red, green, blue, alpha;
+
+ // Text shadow, inspired by FontMac
+ IntSize shadowSize;
+ int shadowBlur = 0;
+ Color shadowColor;
+ bool hasShadow = context->textDrawingMode() == cTextFill &&
+ context->getShadow(shadowSize, shadowBlur, shadowColor);
+
+ // TODO: Blur support
+ if (hasShadow) {
+ // Disable graphics context shadows (not yet implemented) and paint them manually
+ context->clearShadow();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ cairo_save(cr);
+
+ shadowFillColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+
+ cairo_translate(cr, shadowSize.width(), shadowSize.height());
+
+ if (partialRegion) {
+ gdk_cairo_region(cr, partialRegion);
+ cairo_clip(cr);
+ }
+
+ pango_cairo_show_layout_line(cr, layoutLine);
+
+ cairo_restore(cr);
+ }
+
+ fillColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+
+ if (partialRegion) {
+ gdk_cairo_region(cr, partialRegion);
+ cairo_clip(cr);
+ }
+
+ pango_cairo_show_layout_line(cr, layoutLine);
+
+ if (context->textDrawingMode() & cTextStroke) {
+ Color strokeColor = context->strokeColor();
+ strokeColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+ pango_cairo_layout_line_path(cr, layoutLine);
+ cairo_set_line_width(cr, context->strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ // Re-enable the platform shadow we disabled earlier
+ if (hasShadow)
+ context->setShadow(shadowSize, shadowBlur, shadowColor);
+
+ // Pango sometimes leaves behind paths we don't want
+ cairo_new_path(cr);
+
+ if (partialRegion)
+ gdk_region_destroy(partialRegion);
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ cairo_restore(cr);
+}
+
+// We should create the layout with our actual context but we can't access it from here.
+static PangoLayout* getDefaultPangoLayout(const TextRun& run)
+{
+ static PangoFontMap* map = pango_cairo_font_map_get_default();
+#if PANGO_VERSION_CHECK(1,21,5)
+ static PangoContext* pangoContext = pango_font_map_create_context(map);
+#else
+ // Deprecated in Pango 1.21.
+ static PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
+#endif
+ PangoLayout* layout = pango_layout_new(pangoContext);
+
+ return layout;
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ if (run.length() == 0)
+ return 0.0f;
+
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ int width;
+ pango_layout_get_pixel_size(layout, &width, 0);
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return width;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ int index, trailing;
+ pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing);
+ glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index);
+ if (includePartialGlyphs)
+ offset += trailing;
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return offset;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
+{
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ char* start = g_utf8_offset_to_pointer(utf8, from);
+ char* end = g_utf8_offset_to_pointer(start, to - from);
+
+ if (run.ltr()) {
+ from = start - utf8;
+ to = end - utf8;
+ } else {
+ from = end - utf8;
+ to = start - utf8;
+ }
+
+ PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
+ int x_pos;
+
+ x_pos = 0;
+ if (from < layoutLine->length)
+ pango_layout_line_index_to_x(layoutLine, from, FALSE, &x_pos);
+ float beforeWidth = PANGO_PIXELS_FLOOR(x_pos);
+
+ x_pos = 0;
+ if (run.ltr() || to < layoutLine->length)
+ pango_layout_line_index_to_x(layoutLine, to, FALSE, &x_pos);
+ float afterWidth = PANGO_PIXELS(x_pos);
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return FloatRect(point.x() + beforeWidth, point.y(), afterWidth - beforeWidth, h);
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h
new file mode 100644
index 0000000..efa5dd5
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontPlatformData.h
@@ -0,0 +1,132 @@
+/*
+ * 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 Apple Computer, Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include "GlyphBuffer.h"
+#include "FontDescription.h"
+#include <cairo.h>
+#if defined(USE_FREETYPE)
+#include <cairo-ft.h>
+#include <fontconfig/fcfreetype.h>
+#elif defined(USE_PANGO)
+#include <pango/pangocairo.h>
+#else
+#error "Must defined a font backend"
+#endif
+
+namespace WebCore {
+
+class FontPlatformData {
+public:
+ FontPlatformData(WTF::HashTableDeletedValueType)
+#if defined(USE_FREETYPE)
+ : m_pattern(hashTableDeletedFontValue())
+ , m_fallbacks(0)
+#elif defined(USE_PANGO)
+ : m_context(0)
+ , m_font(hashTableDeletedFontValue())
+#else
+#error "Must defined a font backend"
+#endif
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData()
+#if defined(USE_FREETYPE)
+ : m_pattern(0)
+ , m_fallbacks(0)
+#elif defined(USE_PANGO)
+ : m_context(0)
+ , m_font(0)
+#else
+#error "Must defined a font backend"
+#endif
+ , m_scaledFont(0)
+ { }
+
+ FontPlatformData(const FontDescription&, const AtomicString& family);
+
+ FontPlatformData(float size, bool bold, bool italic);
+ FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic);
+
+ ~FontPlatformData();
+
+ static bool init();
+
+ bool isFixedPitch();
+ float size() const { return m_size; }
+
+ void setFont(cairo_t*) const;
+
+ unsigned hash() const
+ {
+#if defined(USE_FREETYPE)
+ if (m_pattern)
+ return FcPatternHash(m_pattern);
+#endif
+ uintptr_t hashCodes[1] = { reinterpret_cast<uintptr_t>(m_scaledFont) };
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+ }
+
+ bool operator==(const FontPlatformData&) const;
+ bool isHashTableDeletedValue() const {
+#if defined(USE_FREETYPE)
+ return m_pattern == hashTableDeletedFontValue();
+#elif defined(USE_PANGO)
+ return m_font == hashTableDeletedFontValue();
+#endif
+ };
+
+#if defined(USE_FREETYPE)
+ FcPattern* m_pattern;
+ FcFontSet* m_fallbacks;
+#elif defined(USE_PANGO)
+ static PangoFontMap* m_fontMap;
+ static GHashTable* m_hashTable;
+
+ PangoContext* m_context;
+ PangoFont* m_font;
+#else
+#error "Must defined a font backend"
+#endif
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ cairo_scaled_font_t* m_scaledFont;
+private:
+#if defined(USE_FREETYPE)
+ static FcPattern *hashTableDeletedFontValue() { return reinterpret_cast<FcPattern*>(-1); }
+#elif defined(USE_PANGO)
+ static PangoFont *hashTableDeletedFontValue() { return reinterpret_cast<PangoFont*>(-1); }
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
new file mode 100644
index 0000000..17d789b
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * 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 "FontPlatformData.h"
+
+#include "CString.h"
+#include "PlatformString.h"
+#include "FontDescription.h"
+
+#include <cairo-ft.h>
+#include <cairo.h>
+#include <fontconfig/fcfreetype.h>
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
+ : m_pattern(0)
+ , m_fallbacks(0)
+ , m_size(fontDescription.computedPixelSize())
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+{
+ FontPlatformData::init();
+
+ CString familyNameString = familyName.string().utf8();
+ const char* fcfamily = familyNameString.data();
+ int fcslant = FC_SLANT_ROMAN;
+ // FIXME: Map all FontWeight values to fontconfig weights.
+ int fcweight = FC_WEIGHT_NORMAL;
+ double fcsize = fontDescription.computedPixelSize();
+ if (fontDescription.italic())
+ fcslant = FC_SLANT_ITALIC;
+ if (fontDescription.weight() >= FontWeight600)
+ fcweight = FC_WEIGHT_BOLD;
+
+ int type = fontDescription.genericFamily();
+
+ FcPattern* pattern = FcPatternCreate();
+ cairo_font_face_t* fontFace;
+ static const cairo_font_options_t* defaultOptions = cairo_font_options_create();
+ const cairo_font_options_t* options = NULL;
+ cairo_matrix_t fontMatrix;
+
+ if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily)))
+ goto freePattern;
+
+ switch (type) {
+ case FontDescription::SerifFamily:
+ fcfamily = "serif";
+ break;
+ case FontDescription::SansSerifFamily:
+ fcfamily = "sans-serif";
+ break;
+ case FontDescription::MonospaceFamily:
+ fcfamily = "monospace";
+ break;
+ case FontDescription::StandardFamily:
+ fcfamily = "sans-serif";
+ break;
+ case FontDescription::NoFamily:
+ default:
+ fcfamily = NULL;
+ break;
+ }
+
+ if (fcfamily && !FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily)))
+ goto freePattern;
+ if (!FcPatternAddInteger(pattern, FC_WEIGHT, fcweight))
+ goto freePattern;
+ if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant))
+ goto freePattern;
+ if (!FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fcsize))
+ goto freePattern;
+
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ FcResult fcresult;
+ m_pattern = FcFontMatch(NULL, pattern, &fcresult);
+ // FIXME: should we set some default font?
+ if (!m_pattern)
+ goto freePattern;
+ fontFace = cairo_ft_font_face_create_for_pattern(m_pattern);
+ cairo_matrix_t ctm;
+ cairo_matrix_init_scale(&fontMatrix, fontDescription.computedPixelSize(), fontDescription.computedPixelSize());
+ cairo_matrix_init_identity(&ctm);
+
+#if GTK_CHECK_VERSION(2,10,0)
+ if (GdkScreen* screen = gdk_screen_get_default())
+ options = gdk_screen_get_font_options(screen);
+#endif
+ // gdk_screen_get_font_options() returns NULL if no default options are
+ // set, so we always have to check.
+ if (!options)
+ options = defaultOptions;
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+ cairo_font_face_destroy(fontFace);
+
+freePattern:
+ FcPatternDestroy(pattern);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
+ : m_pattern(0)
+ , m_fallbacks(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_scaledFont(0)
+{
+}
+
+FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic)
+ : m_pattern(0)
+ , m_fallbacks(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_scaledFont(0)
+{
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ static const cairo_font_options_t* defaultOptions = cairo_font_options_create();
+ const cairo_font_options_t* options = NULL;
+
+#if GTK_CHECK_VERSION(2,10,0)
+ if (GdkScreen* screen = gdk_screen_get_default())
+ options = gdk_screen_get_font_options(screen);
+#endif
+ // gdk_screen_get_font_options() returns NULL if no default options are
+ // set, so we always have to check.
+ if (!options)
+ options = defaultOptions;
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+}
+
+bool FontPlatformData::init()
+{
+ static bool initialized = false;
+ if (initialized)
+ return true;
+ if (!FcInit()) {
+ fprintf(stderr, "Can't init font config library\n");
+ return false;
+ }
+ initialized = true;
+ return true;
+}
+
+FontPlatformData::~FontPlatformData()
+{
+}
+
+bool FontPlatformData::isFixedPitch()
+{
+ // TODO: Support isFixedPitch() for custom fonts.
+ if (!m_pattern)
+ return false;
+
+ int spacing;
+ if (FcPatternGetInteger(m_pattern, FC_SPACING, 0, &spacing) == FcResultMatch)
+ return spacing == FC_MONO;
+ return false;
+}
+
+void FontPlatformData::setFont(cairo_t* cr) const
+{
+ ASSERT(m_scaledFont);
+
+ cairo_set_scaled_font(cr, m_scaledFont);
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ if (m_pattern == other.m_pattern)
+ return true;
+ if (m_pattern == 0 || m_pattern == reinterpret_cast<FcPattern*>(-1)
+ || other.m_pattern == 0 || other.m_pattern == reinterpret_cast<FcPattern*>(-1))
+ return false;
+ return FcPatternEqual(m_pattern, other.m_pattern);
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
new file mode 100644
index 0000000..be3fd43
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, 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 "FontPlatformData.h"
+
+#include "CString.h"
+#include "PlatformString.h"
+#include "FontDescription.h"
+#include <cairo.h>
+#include <assert.h>
+
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+#if !defined(PANGO_VERSION_CHECK)
+#define PANGO_VERSION_CHECK(major,minor,micro) 0
+#endif
+
+// Use cairo-ft i a recent enough Pango version isn't available
+#if !PANGO_VERSION_CHECK(1,18,0)
+#include <cairo-ft.h>
+#include <pango/pangofc-fontmap.h>
+#endif
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+ PangoFontMap* FontPlatformData::m_fontMap = 0;
+ GHashTable* FontPlatformData::m_hashTable = 0;
+
+FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
+ : m_context(0)
+ , m_font(0)
+ , m_size(fontDescription.computedSize())
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_scaledFont(0)
+{
+ FontPlatformData::init();
+
+ CString stored_family = familyName.string().utf8();
+ char const* families[] = {
+ stored_family.data(),
+ NULL
+ };
+
+ switch (fontDescription.genericFamily()) {
+ case FontDescription::SerifFamily:
+ families[1] = "serif";
+ break;
+ case FontDescription::SansSerifFamily:
+ families[1] = "sans";
+ break;
+ case FontDescription::MonospaceFamily:
+ families[1] = "monospace";
+ break;
+ case FontDescription::NoFamily:
+ case FontDescription::StandardFamily:
+ default:
+ families[1] = "sans";
+ break;
+ }
+
+ PangoFontDescription* description = pango_font_description_new();
+ pango_font_description_set_absolute_size(description, fontDescription.computedSize() * PANGO_SCALE);
+
+ // FIXME: Map all FontWeight values to Pango font weights.
+ if (fontDescription.weight() >= FontWeight600)
+ pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD);
+ if (fontDescription.italic())
+ pango_font_description_set_style(description, PANGO_STYLE_ITALIC);
+
+#if PANGO_VERSION_CHECK(1,21,5) // deprecated in 1.21
+ m_context = pango_font_map_create_context(m_fontMap);
+#else
+ m_context = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(m_fontMap));
+#endif
+ for (unsigned int i = 0; !m_font && i < G_N_ELEMENTS(families); i++) {
+ pango_font_description_set_family(description, families[i]);
+ pango_context_set_font_description(m_context, description);
+ m_font = pango_font_map_load_font(m_fontMap, m_context, description);
+ }
+
+#if PANGO_VERSION_CHECK(1,18,0)
+ if (m_font)
+ m_scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(m_font)));
+#else
+ // This compatibility code for older versions of Pango is not well-tested.
+ if (m_font) {
+ PangoFcFont* fcfont = PANGO_FC_FONT(m_font);
+ cairo_font_face_t* face = cairo_ft_font_face_create_for_pattern(fcfont->font_pattern);
+ double size;
+ if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
+ size = 12.0;
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_font_options_t* fontOptions;
+ if (pango_cairo_context_get_font_options(m_context))
+ fontOptions = cairo_font_options_copy(pango_cairo_context_get_font_options(m_context));
+ else
+ fontOptions = cairo_font_options_create();
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ m_scaledFont = cairo_scaled_font_create(face, &fontMatrix, &ctm, fontOptions);
+ cairo_font_options_destroy(fontOptions);
+ cairo_font_face_destroy(face);
+ }
+#endif
+ pango_font_description_free(description);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
+ : m_context(0)
+ , m_font(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_scaledFont(0)
+{
+}
+
+FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic)
+ : m_context(0)
+ , m_font(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
+ , m_scaledFont(0)
+{
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_font_options_t* options = cairo_font_options_create();
+
+ // We force antialiasing and disable hinting to provide consistent
+ // typographic qualities for custom fonts on all platforms.
+ cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+ cairo_font_options_destroy(options);
+}
+
+bool FontPlatformData::init()
+{
+ static bool initialized = false;
+ if (initialized)
+ return true;
+ initialized = true;
+
+ if (!m_fontMap)
+ m_fontMap = pango_cairo_font_map_get_default();
+ if (!m_hashTable) {
+ PangoFontFamily** families = 0;
+ int n_families = 0;
+
+ m_hashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ pango_font_map_list_families(m_fontMap, &families, &n_families);
+
+ for (int family = 0; family < n_families; family++)
+ g_hash_table_insert(m_hashTable,
+ g_strdup(pango_font_family_get_name(families[family])),
+ g_object_ref(families[family]));
+
+ g_free(families);
+ }
+
+ return true;
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ // Destroy takes place in FontData::platformDestroy().
+}
+
+bool FontPlatformData::isFixedPitch()
+{
+ PangoFontDescription* description = pango_font_describe_with_absolute_size(m_font);
+ PangoFontFamily* family = reinterpret_cast<PangoFontFamily*>(g_hash_table_lookup(m_hashTable, pango_font_description_get_family(description)));
+ pango_font_description_free(description);
+ return pango_font_family_is_monospace(family);
+}
+
+void FontPlatformData::setFont(cairo_t* cr) const
+{
+ ASSERT(m_scaledFont);
+
+ cairo_set_scaled_font(cr, m_scaledFont);
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ if (m_font == other.m_font)
+ return true;
+ if (m_font == 0 || m_font == reinterpret_cast<PangoFont*>(-1)
+ || other.m_font == 0 || other.m_font == reinterpret_cast<PangoFont*>(-1))
+ return false;
+ PangoFontDescription* thisDesc = pango_font_describe(m_font);
+ PangoFontDescription* otherDesc = pango_font_describe(other.m_font);
+ bool result = pango_font_description_equal(thisDesc, otherDesc);
+ pango_font_description_free(otherDesc);
+ pango_font_description_free(thisDesc);
+ return result;
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp
new file mode 100644
index 0000000..24ad864
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ *
+ * 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 "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters.
+ // We won't support this for now.
+ if (bufferLength > GlyphPage::size)
+ return false;
+
+ FT_Face face = cairo_ft_scaled_font_lock_face(fontData->m_font.m_scaledFont);
+ if (!face)
+ return false;
+
+ bool haveGlyphs = false;
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = FcFreeTypeCharIndex(face, buffer[i]);
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+
+ cairo_ft_scaled_font_unlock_face(fontData->m_font.m_scaledFont);
+
+ return haveGlyphs;
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp
new file mode 100644
index 0000000..8fada5c
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk>
+ * Copyright (C) 2007 Pioneer Research Center USA, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <pango/pango-font.h>
+
+namespace WebCore {
+
+static PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc)
+{
+ PangoGlyph result = 0;
+ gchar buffer[7];
+
+ gint length = g_unichar_to_utf8(wc, buffer);
+ g_return_val_if_fail(length, 0);
+
+ GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL);
+
+ if (g_list_length(items) == 1) {
+ PangoItem* item = reinterpret_cast<PangoItem*>(items->data);
+ PangoFont* tmpFont = item->analysis.font;
+ item->analysis.font = font;
+
+ PangoGlyphString* glyphs = pango_glyph_string_new();
+ pango_shape(buffer, length, &item->analysis, glyphs);
+
+ item->analysis.font = tmpFont;
+
+ if (glyphs->num_glyphs == 1)
+ result = glyphs->glyphs[0].glyph;
+ else
+ g_warning("didn't get 1 glyph but %d", glyphs->num_glyphs);
+
+ pango_glyph_string_free(glyphs);
+ }
+
+ g_list_foreach(items, (GFunc)pango_item_free, NULL);
+ g_list_free(items);
+
+ return result;
+}
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters.
+ // We won't support this for now.
+ if (bufferLength > GlyphPage::size)
+ return false;
+
+ if (!fontData->m_font.m_font || fontData->m_font.m_font == reinterpret_cast<PangoFont*>(-1))
+ return false;
+
+ bool haveGlyphs = false;
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = pango_font_get_glyph(fontData->m_font.m_font, fontData->m_font.m_context, buffer[i]);
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+
+ return haveGlyphs;
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp
new file mode 100644
index 0000000..d8b38a0
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/IconGtk.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 "Icon.h"
+
+#include "CString.h"
+#include "GraphicsContext.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "PassRefPtr.h"
+
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+Icon::Icon()
+ : m_icon(0)
+{
+}
+
+Icon::~Icon()
+{
+ if (m_icon)
+ g_object_unref(m_icon);
+}
+
+static String lookupIconName(String MIMEType)
+{
+ /*
+ Lookup an appropriate icon according to either the Icon Naming Spec
+ or conventional Gnome icon names respectively.
+
+ See http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
+
+ The icon theme is probed for the following names:
+ 1. media-subtype
+ 2. gnome-mime-media-subtype
+ 3. media-x-generic
+ 4. gnome-mime-media
+
+ In the worst case it falls back to the stock file icon.
+ */
+ int pos = MIMEType.find('/');
+ if(pos >= 0) {
+ String media = MIMEType.substring(0, pos);
+ String subtype = MIMEType.substring(pos + 1);
+ GtkIconTheme* iconTheme = gtk_icon_theme_get_default();
+ String iconName = media + "-" + subtype;
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ iconName = "gnome-mime-" + media + "-" + subtype;
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ iconName = media + "-x-generic";
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ iconName = media + "gnome-mime-" + media;
+ if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data()))
+ return iconName;
+ }
+ return GTK_STOCK_FILE;
+}
+
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
+{
+ if (!g_path_skip_root(filename.utf8().data()))
+ return 0;
+
+ String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename);
+ String iconName = lookupIconName(MIMEType);
+
+ RefPtr<Icon> icon = adoptRef(new Icon);
+ icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
+ if (!icon->m_icon)
+ return 0;
+ return icon.release();
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ //FIXME: Implement this
+ return 0;
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ // TODO: Scale/clip the image if necessary.
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+ gdk_cairo_set_source_pixbuf(cr, m_icon, rect.x(), rect.y());
+ cairo_paint(cr);
+ cairo_restore(cr);
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp
new file mode 100644
index 0000000..b745209
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "BitmapImage.h"
+
+// This function loads resources from WebKit
+Vector<char> loadResourceIntoArray(const char*);
+
+namespace WebCore {
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ Vector<char> arr = loadResourceIntoArray(name);
+ RefPtr<BitmapImage> img = BitmapImage::create();
+ RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size());
+ img->setData(buffer, true);
+ return img.release();
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/IntPointGtk.cpp b/WebCore/platform/graphics/gtk/IntPointGtk.cpp
new file mode 100644
index 0000000..c402158
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/IntPointGtk.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const GdkPoint& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator GdkPoint() const
+{
+ GdkPoint p = { x(), y() };
+ return p;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/gtk/IntRectGtk.cpp b/WebCore/platform/graphics/gtk/IntRectGtk.cpp
new file mode 100644
index 0000000..aaa1944
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/IntRectGtk.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const GdkRectangle& r)
+ : m_location(IntPoint(r.x, r.y))
+ , m_size(r.width, r.height)
+{
+}
+
+IntRect::operator GdkRectangle() const
+{
+ GdkRectangle r = { x(), y(), width(), height() };
+ return r;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
new file mode 100644
index 0000000..1f0cac6
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.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
+ * aint 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"
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayerPrivateGStreamer.h"
+#include "VideoSinkGStreamer.h"
+
+#include "CString.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "KURL.h"
+#include "MIMETypeRegistry.h"
+#include "MediaPlayer.h"
+#include "NotImplemented.h"
+#include "ScrollView.h"
+#include "Widget.h"
+#include <wtf/GOwnPtr.h>
+
+#include <gdk/gdkx.h>
+#include <gst/base/gstbasesrc.h>
+#include <gst/gst.h>
+#include <gst/interfaces/mixer.h>
+#include <gst/interfaces/xoverlay.h>
+#include <gst/video/video.h>
+#include <limits>
+#include <math.h>
+
+using namespace std;
+
+namespace WebCore {
+
+gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data)
+{
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR)
+ {
+ GOwnPtr<GError> err;
+ GOwnPtr<gchar> debug;
+
+ gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
+ if (err->code == 3) {
+ LOG_VERBOSE(Media, "File not found");
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ if (mp)
+ mp->loadingFailed();
+ } else
+ LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message);
+ }
+ return true;
+}
+
+gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data)
+{
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS)
+ {
+ LOG_VERBOSE(Media, "End of Stream");
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ mp->didEnd();
+ }
+ return true;
+}
+
+gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data)
+{
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED)
+ {
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ mp->updateStates();
+ }
+ return true;
+}
+
+gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data)
+{
+ if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING)
+ {
+ gint percent = 0;
+ gst_message_parse_buffering(message, &percent);
+ LOG_VERBOSE(Media, "Buffering %d", percent);
+ }
+ return true;
+}
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_playBin(0)
+ , m_videoSink(0)
+ , m_source(0)
+ , m_rate(1.0f)
+ , m_endTime(numeric_limits<float>::infinity())
+ , m_isEndReached(false)
+ , m_volume(0.5f)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::DataUnavailable)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_rect(IntRect())
+ , m_visible(true)
+{
+
+ static bool gstInitialized = false;
+ // FIXME: We should pass the arguments from the command line
+ if (!gstInitialized) {
+ gst_init(0, NULL);
+ gstInitialized = true;
+ }
+
+ // FIXME: The size shouldn't be fixed here, this is just a quick hack.
+ m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480);
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+ if (m_surface)
+ cairo_surface_destroy(m_surface);
+
+ if (m_playBin) {
+ gst_element_set_state(m_playBin, GST_STATE_NULL);
+ gst_object_unref(GST_OBJECT(m_playBin));
+ }
+}
+
+void MediaPlayerPrivate::load(String url)
+{
+ LOG_VERBOSE(Media, "Load %s", url.utf8().data());
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::DataUnavailable) {
+ m_readyState = MediaPlayer::DataUnavailable;
+ m_player->readyStateChanged();
+ }
+
+ createGSTPlayBin(url);
+ pause();
+}
+
+void MediaPlayerPrivate::play()
+{
+ LOG_VERBOSE(Media, "Play");
+ // When end reached, rewind for Test video-seek-past-end-playing
+ if (m_isEndReached)
+ seek(0);
+ m_isEndReached = false;
+
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ m_startedPlaying = true;
+}
+
+void MediaPlayerPrivate::pause()
+{
+ LOG_VERBOSE(Media, "Pause");
+ gst_element_set_state(m_playBin, GST_STATE_PAUSED);
+ m_startedPlaying = false;
+}
+
+float MediaPlayerPrivate::duration()
+{
+ if (!m_playBin)
+ return 0.0;
+
+ GstFormat fmt = GST_FORMAT_TIME;
+ gint64 len = 0;
+
+ if (gst_element_query_duration(m_playBin, &fmt, &len))
+ LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len));
+ else
+ LOG_VERBOSE(Media, "Duration query failed ");
+
+ if ((GstClockTime)len == GST_CLOCK_TIME_NONE) {
+ m_isStreaming = true;
+ return numeric_limits<float>::infinity();
+ }
+ return (float) (len / 1000000000.0);
+ // FIXME: handle 3.14.9.5 properly
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ if (!m_playBin)
+ return 0;
+ // Necessary as sometimes, gstreamer return 0:00 at the EOS
+ if (m_isEndReached)
+ return m_endTime;
+
+ float ret;
+
+ GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
+ if (gst_element_query(m_playBin, query)) {
+ gint64 position;
+ gst_query_parse_position(query, NULL, &position);
+ ret = (float) (position / 1000000000.0);
+ LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position));
+ } else {
+ LOG_VERBOSE(Media, "Position query failed...");
+ ret = 0.0;
+ }
+ gst_query_unref(query);
+
+ return ret;
+}
+
+void MediaPlayerPrivate::seek(float time)
+{
+ GstClockTime sec = (GstClockTime)(time * GST_SECOND);
+
+ if (!m_playBin)
+ return;
+
+ if (m_isStreaming)
+ return;
+
+ LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
+ // FIXME: What happens when the seeked position is not available?
+ if (!gst_element_seek( m_playBin, m_rate,
+ GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
+ GST_SEEK_TYPE_SET, sec,
+ GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+ LOG_VERBOSE(Media, "Seek to %f failed", time);
+}
+
+void MediaPlayerPrivate::setEndTime(float time)
+{
+ if (!m_playBin)
+ return;
+ if (m_isStreaming)
+ return;
+ if (m_endTime != time) {
+ m_endTime = time;
+ GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND);
+ GstClockTime end = (GstClockTime)(time * GST_SECOND);
+ LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end));
+ // FIXME: What happens when the seeked position is not available?
+ if (!gst_element_seek(m_playBin, m_rate,
+ GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
+ GST_SEEK_TYPE_SET, start,
+ GST_SEEK_TYPE_SET, end ))
+ LOG_VERBOSE(Media, "Seek to %f failed", time);
+ }
+}
+
+void MediaPlayerPrivate::startEndPointTimerIfNeeded()
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivate::cancelSeek()
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ notImplemented();
+}
+
+bool MediaPlayerPrivate::paused() const
+{
+ return !m_startedPlaying;
+}
+
+bool MediaPlayerPrivate::seeking() const
+{
+ return false;
+}
+
+// Returns the size of the video
+IntSize MediaPlayerPrivate::naturalSize()
+{
+ if (!hasVideo())
+ return IntSize();
+
+ int x = 0, y = 0;
+ if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) {
+ gst_video_get_size(GST_PAD(pad), &x, &y);
+ gst_object_unref(GST_OBJECT(pad));
+ }
+
+ return IntSize(x, y);
+}
+
+bool MediaPlayerPrivate::hasVideo()
+{
+ gint currentVideo = -1;
+ if (m_playBin)
+ g_object_get(G_OBJECT(m_playBin), "current-video", &currentVideo, NULL);
+ return currentVideo > -1;
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ m_volume = volume;
+ LOG_VERBOSE(Media, "Volume to %f", volume);
+ setMuted(false);
+}
+
+void MediaPlayerPrivate::setMuted(bool b)
+{
+ if (!m_playBin)
+ return;
+
+ if (b) {
+ g_object_get(G_OBJECT(m_playBin), "volume", &m_volume, NULL);
+ g_object_set(G_OBJECT(m_playBin), "volume", (double)0.0, NULL);
+ } else {
+ g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL);
+ }
+}
+
+void MediaPlayerPrivate::setRate(float rate)
+{
+ if (rate == 0.0) {
+ gst_element_set_state(m_playBin, GST_STATE_PAUSED);
+ return;
+ }
+ if (m_isStreaming)
+ return;
+
+ m_rate = rate;
+ LOG_VERBOSE(Media, "Set Rate to %f", rate);
+ if (!gst_element_seek(m_playBin, rate,
+ GST_FORMAT_TIME,
+ (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
+ GST_SEEK_TYPE_SET, (GstClockTime) (currentTime() * GST_SECOND),
+ GST_SEEK_TYPE_SET, (GstClockTime) (m_endTime * GST_SECOND)))
+ LOG_VERBOSE(Media, "Set Rate to %f failed", rate);
+}
+
+int MediaPlayerPrivate::dataRate() const
+{
+ notImplemented();
+ return 1;
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivate::networkState()
+{
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivate::readyState()
+{
+ return m_readyState;
+}
+
+float MediaPlayerPrivate::maxTimeBuffered()
+{
+ notImplemented();
+ LOG_VERBOSE(Media, "maxTimeBuffered");
+ // rtsp streams are not buffered
+ return m_isStreaming ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeSeekable()
+{
+ // TODO
+ LOG_VERBOSE(Media, "maxTimeSeekable");
+ if (m_isStreaming)
+ return numeric_limits<float>::infinity();
+ // infinite duration means live stream
+ return maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeLoaded()
+{
+ // TODO
+ LOG_VERBOSE(Media, "maxTimeLoaded");
+ notImplemented();
+ return duration();
+}
+
+unsigned MediaPlayerPrivate::bytesLoaded()
+{
+ notImplemented();
+ LOG_VERBOSE(Media, "bytesLoaded");
+ /*if (!m_playBin)
+ return 0;
+ float dur = duration();
+ float maxTime = maxTimeLoaded();
+ if (!dur)
+ return 0;*/
+ return 1;//totalBytes() * maxTime / dur;
+}
+
+bool MediaPlayerPrivate::totalBytesKnown()
+{
+ notImplemented();
+ LOG_VERBOSE(Media, "totalBytesKnown");
+ return totalBytes() > 0;
+}
+
+unsigned MediaPlayerPrivate::totalBytes()
+{
+ notImplemented();
+ LOG_VERBOSE(Media, "totalBytes");
+ if (!m_playBin)
+ return 0;
+
+ if (!m_source)
+ return 0;
+
+ // Do something with m_source to get the total bytes of the media
+
+ return 100;
+}
+
+void MediaPlayerPrivate::cancelLoad()
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivate::updateStates()
+{
+ // There is no (known) way to get such level of information about
+ // the state of GStreamer, therefore, when in PAUSED state,
+ // we are sure we can display the first frame and go to play
+
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+ GstState state;
+ GstState pending;
+
+ if (!m_playBin)
+ return;
+
+ GstStateChangeReturn ret = gst_element_get_state (m_playBin,
+ &state, &pending, 250 * GST_NSECOND);
+
+ switch(ret) {
+ case GST_STATE_CHANGE_SUCCESS:
+ LOG_VERBOSE(Media, "State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
+
+ if (state == GST_STATE_READY) {
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (state == GST_STATE_PAUSED) {
+ m_readyState = MediaPlayer::CanPlayThrough;
+ }
+ if (m_networkState < MediaPlayer::Loaded)
+ m_networkState = MediaPlayer::Loaded;
+
+ g_object_get(m_playBin, "source", &m_source, NULL);
+ if (!m_source)
+ LOG_VERBOSE(Media, "m_source is NULL");
+ break;
+ case GST_STATE_CHANGE_ASYNC:
+ LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
+ // Change in progress
+ return;
+ break;
+ case GST_STATE_CHANGE_NO_PREROLL:
+ LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s",
+ gst_element_state_get_name(state),
+ gst_element_state_get_name(pending));
+ if (state == GST_STATE_READY) {
+ m_readyState = MediaPlayer::CanPlay;
+ } else if (state == GST_STATE_PAUSED) {
+ m_readyState = MediaPlayer::CanPlay;
+ }
+ if (m_networkState < MediaPlayer::LoadedMetaData)
+ m_networkState = MediaPlayer::LoadedMetaData;
+ break;
+ default:
+ LOG_VERBOSE(Media, "Else : %d", ret);
+ break;
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::DataUnavailable;
+
+ if (m_networkState != oldNetworkState) {
+ LOG_VERBOSE(Media, "Network State Changed from %u to %u",
+ oldNetworkState, m_networkState);
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != oldReadyState) {
+ LOG_VERBOSE(Media, "Ready State Changed from %u to %u",
+ oldReadyState, m_readyState);
+ m_player->readyStateChanged();
+ }
+}
+
+void MediaPlayerPrivate::loadStateChanged()
+{
+ updateStates();
+}
+
+void MediaPlayerPrivate::rateChanged()
+{
+ updateStates();
+}
+
+void MediaPlayerPrivate::sizeChanged()
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivate::timeChanged()
+{
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::volumeChanged()
+{
+ m_player->volumeChanged();
+}
+
+void MediaPlayerPrivate::didEnd()
+{
+ m_isEndReached = true;
+ pause();
+ timeChanged();
+}
+
+void MediaPlayerPrivate::loadingFailed()
+{
+ if (m_networkState != MediaPlayer::LoadFailed) {
+ m_networkState = MediaPlayer::LoadFailed;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::DataUnavailable) {
+ m_readyState = MediaPlayer::DataUnavailable;
+ m_player->readyStateChanged();
+ }
+}
+
+void MediaPlayerPrivate::setRect(const IntRect& rect)
+{
+ m_rect = rect;
+}
+
+void MediaPlayerPrivate::setVisible(bool visible)
+{
+ m_visible = visible;
+}
+
+void MediaPlayerPrivate::repaint()
+{
+ m_player->repaint();
+}
+
+void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ if (!m_visible)
+ return;
+
+ //TODO: m_rect vs rect?
+ cairo_t* cr = context->platformContext();
+
+ cairo_save(cr);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_translate(cr, rect.x(), rect.y());
+ cairo_rectangle(cr, 0, 0, rect.width(), rect.height());
+ cairo_set_source_surface(cr, m_surface, 0, 0);
+ cairo_fill(cr);
+ cairo_restore(cr);
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ // FIXME: do the real thing
+ notImplemented();
+ types.add(String("video/x-theora+ogg"));
+}
+
+void MediaPlayerPrivate::createGSTPlayBin(String url)
+{
+ ASSERT(!m_playBin);
+ m_playBin = gst_element_factory_make("playbin", "play");
+
+ GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
+ gst_bus_add_signal_watch(bus);
+ g_signal_connect(bus, "message::error", G_CALLBACK(mediaPlayerPrivateErrorCallback), this);
+ g_signal_connect(bus, "message::eos", G_CALLBACK(mediaPlayerPrivateEOSCallback), this);
+ g_signal_connect(bus, "message::state-changed", G_CALLBACK(mediaPlayerPrivateStateCallback), this);
+ g_signal_connect(bus, "message::buffering", G_CALLBACK(mediaPlayerPrivateBufferingCallback), this);
+ gst_object_unref(bus);
+
+ g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL);
+
+ GstElement* audioSink = gst_element_factory_make("gconfaudiosink", NULL);
+ m_videoSink = webkit_video_sink_new(m_surface);
+
+ g_object_set(m_playBin, "audio-sink", audioSink, NULL);
+ g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
+
+ setVolume(m_volume);
+}
+
+}
+
+#endif
+
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
new file mode 100644
index 0000000..3f08bc0
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.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
+ * aint 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 MediaPlayerPrivateGStreamer_h
+#define MediaPlayerPrivateGStreamer_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+#include "Timer.h"
+
+#include <gtk/gtk.h>
+
+typedef struct _GstElement GstElement;
+typedef struct _GstMessage GstMessage;
+typedef struct _GstBus GstBus;
+
+namespace WebCore {
+
+ class GraphicsContext;
+ class IntSize;
+ class IntRect;
+ class String;
+
+ gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
+ gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
+ gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
+
+ class MediaPlayerPrivate : Noncopyable
+ {
+ friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
+ friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
+ friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
+
+ public:
+ MediaPlayerPrivate(MediaPlayer*);
+ ~MediaPlayerPrivate();
+
+ IntSize naturalSize();
+ bool hasVideo();
+
+ void load(String url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration();
+ float currentTime() const;
+ void seek(float);
+ void setEndTime(float);
+
+ void setRate(float);
+ void setVolume(float);
+ void setMuted(bool);
+
+ int dataRate() const;
+
+ MediaPlayer::NetworkState networkState();
+ MediaPlayer::ReadyState readyState();
+
+ float maxTimeBuffered();
+ float maxTimeSeekable();
+ unsigned bytesLoaded();
+ bool totalBytesKnown();
+ unsigned totalBytes();
+
+ 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; }
+
+ private:
+
+ void updateStates();
+ void cancelSeek();
+ void endPointTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded();
+ void startEndPointTimerIfNeeded();
+
+ void createGSTPlayBin(String url);
+
+ private:
+ MediaPlayer* m_player;
+ GstElement* m_playBin;
+ GstElement* m_videoSink;
+ GstElement* m_source;
+ float m_rate;
+ float m_endTime;
+ bool m_isEndReached;
+ double m_volume;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ IntRect m_rect;
+ bool m_visible;
+ cairo_surface_t* m_surface;
+ };
+}
+
+#endif
+#endif
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
new file mode 100644
index 0000000..1ca3e95
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * 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 "SimpleFontData.h"
+
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include "GlyphBuffer.h"
+#include <cairo.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ cairo_font_extents_t font_extents;
+ cairo_text_extents_t text_extents;
+ cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents);
+ m_ascent = static_cast<int>(font_extents.ascent);
+ m_descent = static_cast<int>(font_extents.descent);
+ m_lineSpacing = static_cast<int>(font_extents.height);
+ cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents);
+ m_xHeight = text_extents.height;
+ cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents);
+ m_spaceWidth = static_cast<int>(text_extents.x_advance);
+ m_lineGap = m_lineSpacing - m_ascent - m_descent;
+}
+
+void SimpleFontData::platformDestroy()
+{
+ delete m_smallCapsFontData;
+
+ if (isCustomFont())
+ return;
+
+ if (m_font.m_pattern && ((FcPattern*)-1 != m_font.m_pattern)) {
+ FcPatternDestroy(m_font.m_pattern);
+ m_font.m_pattern = 0;
+ }
+
+ if (m_font.m_fallbacks) {
+ FcFontSetDestroy(m_font.m_fallbacks);
+ m_font.m_fallbacks = 0;
+ }
+
+ if (m_font.m_scaledFont) {
+ cairo_scaled_font_destroy(m_font.m_scaledFont);
+ m_font.m_scaledFont = 0;
+ }
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ FontDescription desc = FontDescription(fontDescription);
+ desc.setSpecifiedSize(0.70f*fontDescription.computedSize());
+ const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family());
+ m_smallCapsFontData = new SimpleFontData(*pdata);
+ }
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ FT_Face face = cairo_ft_scaled_font_lock_face(m_font.m_scaledFont);
+
+ if (!face)
+ return false;
+
+ for (unsigned i = 0; i < length; i++) {
+ if (FcFreeTypeCharIndex(face, characters[i]) == 0) {
+ cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont);
+ return false;
+ }
+ }
+
+ cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont);
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = m_font.isFixedPitch();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ ASSERT(m_font.m_scaledFont);
+
+ cairo_glyph_t cglyph = { glyph, 0, 0 };
+ cairo_text_extents_t extents;
+ cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents);
+
+ float w = (float)m_spaceWidth;
+ if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0)
+ w = (float)extents.x_advance;
+ return w;
+}
+
+void SimpleFontData::setFont(cairo_t* cr) const
+{
+ ASSERT(cr);
+ m_font.setFont(cr);
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
new file mode 100644
index 0000000..8621865
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Pioneer Research Center USA, 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 "SimpleFontData.h"
+
+#include "FloatRect.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include "GlyphBuffer.h"
+#include <cairo.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ cairo_font_extents_t font_extents;
+ cairo_text_extents_t text_extents;
+ cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents);
+ m_ascent = static_cast<int>(font_extents.ascent);
+ m_descent = static_cast<int>(font_extents.descent);
+ m_lineSpacing = static_cast<int>(font_extents.height);
+ cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents);
+ m_xHeight = text_extents.height;
+ cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents);
+ m_spaceWidth = static_cast<int>(text_extents.x_advance);
+ m_lineGap = m_lineSpacing - m_ascent - m_descent;
+}
+
+void SimpleFontData::platformDestroy()
+{
+ if (!isCustomFont()) {
+
+ if (m_font.m_font && m_font.m_font != reinterpret_cast<PangoFont*>(-1)) {
+ g_object_unref(m_font.m_font);
+ m_font.m_font = 0;
+ }
+
+ if (m_font.m_context) {
+ g_object_unref (m_font.m_context);
+ m_font.m_context = 0;
+ }
+
+ if (m_font.m_scaledFont) {
+ cairo_scaled_font_destroy(m_font.m_scaledFont);
+ m_font.m_scaledFont = 0;
+ }
+ }
+
+ delete m_smallCapsFontData;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ FontDescription desc = FontDescription(fontDescription);
+ desc.setSpecifiedSize(0.70f*fontDescription.computedSize());
+ const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family());
+ m_smallCapsFontData = new SimpleFontData(*pdata);
+ }
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ 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);
+
+ for (int i = 0; i < length; i++) {
+ if (PANGO_COVERAGE_NONE == pango_coverage_get(requested, i)) {
+ result = false;
+ break;
+ }
+ }
+
+ pango_coverage_unref(requested);
+ pango_coverage_unref(available);
+
+ return result;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = m_font.isFixedPitch();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ ASSERT(m_font.m_scaledFont);
+
+ cairo_glyph_t cglyph = { glyph, 0, 0 };
+ cairo_text_extents_t extents;
+ cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents);
+
+ float w = (float)m_spaceWidth;
+ if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0)
+ w = (float)extents.x_advance;
+ return w;
+}
+
+void SimpleFontData::setFont(cairo_t* cr) const
+{
+ ASSERT(cr);
+ m_font.setFont(cr);
+}
+
+}
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
new file mode 100644
index 0000000..04df7ac
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2007 OpenedHand
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:webkit-video-sink
+ * @short_description: GStreamer video sink
+ *
+ * #WebKitVideoSink is a GStreamer sink element that sends
+ * data to a #cairo_surface_t.
+ */
+
+#include "config.h"
+#include "VideoSinkGStreamer.h"
+
+#include <glib.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink",
+ GST_PAD_SINK, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS(GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx));
+
+GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug);
+#define GST_CAT_DEFAULT webkit_video_sink_debug
+
+static GstElementDetails webkit_video_sink_details =
+ GST_ELEMENT_DETAILS((gchar*) "WebKit video sink",
+ (gchar*) "Sink/Video",
+ (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface",
+ (gchar*) "Alp Toker <alp@atoker.com>");
+
+enum {
+ PROP_0,
+ PROP_SURFACE
+};
+
+struct _WebKitVideoSinkPrivate {
+ cairo_surface_t* surface;
+ GAsyncQueue* async_queue;
+ gboolean rgb_ordering;
+ int width;
+ int height;
+ int fps_n;
+ int fps_d;
+ int par_n;
+ int par_d;
+};
+
+#define _do_init(bla) \
+ GST_DEBUG_CATEGORY_INIT (webkit_video_sink_debug, \
+ "webkitsink", \
+ 0, \
+ "webkit video sink")
+
+GST_BOILERPLATE_FULL(WebKitVideoSink,
+ webkit_video_sink,
+ GstBaseSink,
+ GST_TYPE_BASE_SINK,
+ _do_init);
+
+static void
+webkit_video_sink_base_init(gpointer g_class)
+{
+ GstElementClass* element_class = GST_ELEMENT_CLASS(g_class);
+
+ gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate));
+ gst_element_class_set_details(element_class, &webkit_video_sink_details);
+}
+
+static void
+webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass)
+{
+ WebKitVideoSinkPrivate* priv;
+
+ sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
+ priv->async_queue = g_async_queue_new();
+}
+
+static gboolean
+webkit_video_sink_idle_func(gpointer data)
+{
+ WebKitVideoSinkPrivate* priv;
+ GstBuffer* buffer;
+
+ priv = (WebKitVideoSinkPrivate*)data;
+
+ if (!priv->async_queue)
+ return FALSE;
+
+ buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue);
+ if (buffer == NULL || G_UNLIKELY(!GST_IS_BUFFER(buffer)))
+ return FALSE;
+
+ // TODO: consider priv->rgb_ordering?
+ cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~ 3);
+
+ // TODO: We copy the data twice right now. This could be easily improved.
+ cairo_t* cr = cairo_create(priv->surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface(cr, src, 0, 0);
+ cairo_surface_destroy(src);
+ cairo_rectangle(cr, 0, 0, priv->width, priv->height);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ gst_buffer_unref(buffer);
+
+ return FALSE;
+}
+
+static GstFlowReturn
+webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+
+ g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer));
+ g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, priv, NULL);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+ GstStructure* structure;
+ gboolean ret;
+ const GValue* fps;
+ const GValue* par;
+ gint width, height;
+ int red_mask;
+
+ GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps);
+
+ if (gst_caps_is_empty(intersection))
+ return FALSE;
+
+ gst_caps_unref(intersection);
+
+ structure = gst_caps_get_structure(caps, 0);
+
+ ret = gst_structure_get_int(structure, "width", &width);
+ ret &= gst_structure_get_int(structure, "height", &height);
+ fps = gst_structure_get_value(structure, "framerate");
+ ret &= (fps != NULL);
+
+ par = gst_structure_get_value(structure, "pixel-aspect-ratio");
+
+ if (!ret)
+ return FALSE;
+
+ priv->width = width;
+ priv->height = height;
+
+ /* We dont yet use fps or pixel aspect into but handy to have */
+ priv->fps_n = gst_value_get_fraction_numerator(fps);
+ priv->fps_d = gst_value_get_fraction_denominator(fps);
+
+ if (par) {
+ priv->par_n = gst_value_get_fraction_numerator(par);
+ priv->par_d = gst_value_get_fraction_denominator(par);
+ } else
+ priv->par_n = priv->par_d = 1;
+
+ gst_structure_get_int(structure, "red_mask", &red_mask);
+ priv->rgb_ordering = (red_mask == static_cast<int>(0xff000000));
+
+ return TRUE;
+}
+
+static void
+webkit_video_sink_dispose(GObject* object)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+
+ if (priv->surface) {
+ cairo_surface_destroy(priv->surface);
+ priv->surface = NULL;
+ }
+
+ if (priv->async_queue) {
+ g_async_queue_unref(priv->async_queue);
+ priv->async_queue = NULL;
+ }
+
+ G_OBJECT_CLASS(parent_class)->dispose(object);
+}
+
+static void
+webkit_video_sink_finalize(GObject* object)
+{
+ G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+static void
+webkit_video_sink_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+ WebKitVideoSinkPrivate* priv = sink->priv;
+
+ switch (prop_id) {
+ case PROP_SURFACE:
+ if (priv->surface)
+ cairo_surface_destroy(priv->surface);
+ priv->surface = cairo_surface_reference((cairo_surface_t*)g_value_get_pointer(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+webkit_video_sink_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
+{
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+
+ switch (prop_id) {
+ case PROP_SURFACE:
+ g_value_set_pointer(value, sink->priv->surface);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+webkit_video_sink_stop(GstBaseSink* base_sink)
+{
+ WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv;
+
+ g_async_queue_lock(priv->async_queue);
+
+ /* Remove all remaining objects from the queue */
+ while(GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue))
+ gst_buffer_unref(buffer);
+
+ g_async_queue_unlock(priv->async_queue);
+
+ return TRUE;
+}
+
+static void
+webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
+{
+ GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
+ GstBaseSinkClass* gstbase_sink_class = GST_BASE_SINK_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate));
+
+ gobject_class->set_property = webkit_video_sink_set_property;
+ gobject_class->get_property = webkit_video_sink_get_property;
+
+ gobject_class->dispose = webkit_video_sink_dispose;
+ gobject_class->finalize = webkit_video_sink_finalize;
+
+ gstbase_sink_class->render = webkit_video_sink_render;
+ gstbase_sink_class->preroll = webkit_video_sink_render;
+ gstbase_sink_class->stop = webkit_video_sink_stop;
+ gstbase_sink_class->set_caps = webkit_video_sink_set_caps;
+
+ g_object_class_install_property(
+ gobject_class, PROP_SURFACE,
+ g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*",
+ (GParamFlags)(G_PARAM_READWRITE)));
+}
+
+/**
+ * webkit_video_sink_new:
+ * @surface: a #cairo_surface_t
+ *
+ * Creates a new GStreamer video sink which uses @surface as the target
+ * for sinking a video stream from GStreamer.
+ *
+ * Return value: a #GstElement for the newly created video sink
+ */
+GstElement*
+webkit_video_sink_new(cairo_surface_t* surface)
+{
+ return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, NULL);
+}
+
+void
+webkit_video_sink_set_surface(WebKitVideoSink* sink, cairo_surface_t* surface)
+{
+ WebKitVideoSinkPrivate* priv;
+
+ sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
+ if (priv->surface)
+ cairo_surface_destroy(priv->surface);
+ priv->surface = cairo_surface_reference(surface);
+}
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
new file mode 100644
index 0000000..2a706fb
--- /dev/null
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 OpenedHand
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _HAVE_WEBKIT_VIDEO_SINK_H
+#define _HAVE_WEBKIT_VIDEO_SINK_H
+
+#include <cairo.h>
+#include <glib-object.h>
+#include <gst/base/gstbasesink.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_VIDEO_SINK webkit_video_sink_get_type()
+
+#define WEBKIT_VIDEO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSink))
+
+#define WEBKIT_VIDEO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
+
+#define WEBKIT_IS_VIDEO_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ WEBKIT_TYPE_VIDEO_SINK))
+
+#define WEBKIT_IS_VIDEO_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ WEBKIT_TYPE_VIDEO_SINK))
+
+#define WEBKIT_VIDEO_SINK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass))
+
+typedef struct _WebKitVideoSink WebKitVideoSink;
+typedef struct _WebKitVideoSinkClass WebKitVideoSinkClass;
+typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate;
+
+struct _WebKitVideoSink
+{
+ /*< private >*/
+ GstBaseSink parent;
+ WebKitVideoSinkPrivate *priv;
+};
+
+struct _WebKitVideoSinkClass
+{
+ /*< private >*/
+ GstBaseSinkClass parent_class;
+
+ /* Future padding */
+ void (* _webkit_reserved1) (void);
+ void (* _webkit_reserved2) (void);
+ void (* _webkit_reserved3) (void);
+ void (* _webkit_reserved4) (void);
+ void (* _webkit_reserved5) (void);
+ void (* _webkit_reserved6) (void);
+};
+
+GType webkit_video_sink_get_type (void) G_GNUC_CONST;
+GstElement *webkit_video_sink_new (cairo_surface_t *surface);
+
+void webkit_video_sink_set_surface (WebKitVideoSink *sink, cairo_surface_t *surface);
+
+G_END_DECLS
+
+#endif
diff --git a/WebCore/platform/graphics/mac/ColorMac.h b/WebCore/platform/graphics/mac/ColorMac.h
new file mode 100644
index 0000000..3be9094
--- /dev/null
+++ b/WebCore/platform/graphics/mac/ColorMac.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ColorMac_h
+#define ColorMac_h
+
+#include "Color.h"
+
+#ifdef __OBJC__
+@class NSColor;
+#else
+class NSColor;
+#endif
+
+namespace WebCore {
+
+ Color colorFromNSColor(NSColor *);
+ NSColor* nsColor(const Color&);
+
+ bool usesTestModeFocusRingColor();
+ void setUsesTestModeFocusRingColor(bool);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm
new file mode 100644
index 0000000..96fdc39
--- /dev/null
+++ b/WebCore/platform/graphics/mac/ColorMac.mm
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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.
+ */
+
+#import "config.h"
+#import "Color.h"
+#import "ColorMac.h"
+
+#import <wtf/Assertions.h>
+#import <wtf/RetainPtr.h>
+
+@interface WebCoreControlTintObserver : NSObject
++ (void)controlTintDidChange;
+@end
+
+namespace WebCore {
+
+// NSColor calls don't throw, so no need to block Cocoa exceptions in this file
+
+static RGBA32 oldAquaFocusRingColor = 0xFF7DADD9;
+static RGBA32 systemFocusRingColor;
+static bool useOldAquaFocusRingColor;
+
+
+static RGBA32 makeRGBAFromNSColor(NSColor *c)
+{
+ return makeRGBA((int)(255 * [c redComponent]), (int)(255 * [c greenComponent]), (int)(255 * [c blueComponent]), (int)(255 * [c alphaComponent]));
+}
+
+Color colorFromNSColor(NSColor *c)
+{
+ return Color(makeRGBAFromNSColor(c));
+}
+
+NSColor* nsColor(const Color& color)
+{
+ unsigned c = color.rgb();
+ switch (c) {
+ case 0: {
+ // Need this to avoid returning nil because cachedRGBAValues will default to 0.
+ static RetainPtr<NSColor> clearColor = [NSColor clearColor];
+ return clearColor.get();
+ }
+ case Color::black: {
+ static RetainPtr<NSColor> blackColor = [NSColor blackColor];
+ return blackColor.get();
+ }
+ case Color::white: {
+ static RetainPtr<NSColor> whiteColor = [NSColor whiteColor];
+ return whiteColor.get();
+ }
+ default: {
+ const int cacheSize = 32;
+ static unsigned cachedRGBAValues[cacheSize];
+ static RetainPtr<NSColor> cachedColors[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;
+ cachedColors[cursor] = result;
+ if (++cursor == cacheSize)
+ cursor = 0;
+ return result;
+ }
+ }
+}
+
+static CGColorRef CGColorFromNSColor(NSColor* color)
+{
+ // This needs to always use device colorspace so it can de-calibrate the color for
+ // CGColor to possibly recalibrate it.
+ NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+ CGFloat red = [deviceColor redComponent];
+ CGFloat green = [deviceColor greenComponent];
+ CGFloat blue = [deviceColor blueComponent];
+ CGFloat alpha = [deviceColor alphaComponent];
+ const CGFloat components[4] = { red, green, blue, alpha };
+ static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB();
+ CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components);
+ return cgColor;
+}
+
+CGColorRef cgColor(const Color& c)
+{
+ // We could directly create a CGColor here, but that would
+ // skip any RGB caching the nsColor method does. A direct
+ // creation could be investigated for a possible performance win.
+ return CGColorFromNSColor(nsColor(c));
+}
+
+Color focusRingColor()
+{
+ static bool tintIsKnown = false;
+ if (!tintIsKnown) {
+ [[NSNotificationCenter defaultCenter] addObserver:[WebCoreControlTintObserver class]
+ selector:@selector(controlTintDidChange)
+ name:NSControlTintDidChangeNotification
+ object:NSApp];
+ [WebCoreControlTintObserver controlTintDidChange];
+ tintIsKnown = true;
+ }
+
+ if (usesTestModeFocusRingColor())
+ return oldAquaFocusRingColor;
+
+ return systemFocusRingColor;
+}
+
+bool usesTestModeFocusRingColor()
+{
+ return useOldAquaFocusRingColor;
+}
+
+void setUsesTestModeFocusRingColor(bool newValue)
+{
+ useOldAquaFocusRingColor = newValue;
+}
+
+}
+
+@implementation WebCoreControlTintObserver
+
++ (void)controlTintDidChange
+{
+#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
new file mode 100644
index 0000000..171a7ec
--- /dev/null
+++ b/WebCore/platform/graphics/mac/CoreTextController.cpp
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2007, 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 "CoreTextController.h"
+
+#if USE(CORE_TEXT)
+
+#include "CharacterNames.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "SimpleFontData.h"
+#include "TextBreakIterator.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+static inline CGFloat roundCGFloat(CGFloat f)
+{
+ if (sizeof(CGFloat) == sizeof(float))
+ return roundf(static_cast<float>(f));
+ return static_cast<CGFloat>(round(f));
+}
+
+static inline CGFloat ceilCGFloat(CGFloat f)
+{
+ if (sizeof(CGFloat) == sizeof(float))
+ return ceilf(static_cast<float>(f));
+ return static_cast<CGFloat>(ceil(f));
+}
+
+CoreTextController::CoreTextRun::CoreTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength)
+ : m_CTRun(ctRun)
+ , m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+{
+ m_glyphCount = CTRunGetGlyphCount(ctRun);
+ m_indices = CTRunGetStringIndicesPtr(ctRun);
+ if (!m_indices) {
+ m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
+ CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex));
+ m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get()));
+ CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices));
+ }
+}
+
+// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on
+// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path.
+CoreTextController::CoreTextRun::CoreTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
+ : m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+{
+ Vector<CFIndex, 16> indices;
+ unsigned r = 0;
+ while (r < stringLength) {
+ indices.append(r);
+ if (U_IS_SURROGATE(characters[r])) {
+ ASSERT(r + 1 < stringLength);
+ ASSERT(U_IS_SURROGATE_LEAD(characters[r]));
+ ASSERT(U_IS_TRAIL(characters[r + 1]));
+ r += 2;
+ } else
+ r++;
+ }
+ m_glyphCount = indices.size();
+ if (!ltr) {
+ for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
+ std::swap(indices[r], indices[end]);
+ }
+ m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
+ CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex));
+ m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get()));
+}
+
+CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection)
+ : m_font(*font)
+ , m_run(run)
+ , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
+ , m_currentCharacter(0)
+ , m_end(run.length())
+ , m_totalWidth(0)
+ , m_runWidthSoFar(0)
+ , m_numGlyphsSoFar(0)
+ , m_currentRun(0)
+ , m_glyphInCurrentRun(0)
+ , m_finalRoundingWidth(0)
+ , m_lastRoundingGlyph(0)
+{
+ m_padding = m_run.padding();
+ if (!m_padding)
+ m_padPerSpace = 0;
+ else {
+ float numSpaces = 0;
+ for (int s = 0; s < m_run.length(); s++)
+ if (Font::treatAsSpace(m_run[s]))
+ numSpaces++;
+
+ if (numSpaces == 0)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = ceilf(m_run.padding() / numSpaces);
+ }
+
+ collectCoreTextRuns();
+ adjustGlyphsAndAdvances();
+}
+
+int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs)
+{
+ // FIXME: For positions occurring within a ligature, we should return the closest "ligature caret" or
+ // approximate it by dividing the width of the ligature by the number of characters it encompasses.
+ // However, Core Text does not expose a low-level API for directly finding
+ // out how many characters a ligature encompasses (the "attachment count").
+ if (h >= m_totalWidth)
+ return m_run.ltr() ? m_end : 0;
+ if (h < 0)
+ return m_run.ltr() ? 0 : m_end;
+
+ CGFloat x = h;
+
+ size_t runCount = m_coreTextRuns.size();
+ size_t offsetIntoAdjustedGlyphs = 0;
+
+ for (size_t r = 0; r < runCount; ++r) {
+ const CoreTextRun& coreTextRun = m_coreTextRuns[r];
+ for (unsigned j = 0; j < coreTextRun.glyphCount(); ++j) {
+ CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width;
+ if (x <= adjustedAdvance) {
+ CFIndex hitIndex = coreTextRun.indexAt(j);
+ int stringLength = coreTextRun.stringLength();
+ TextBreakIterator* characterIterator = characterBreakIterator(coreTextRun.characters(), stringLength);
+ int clusterStart;
+ if (isTextBreak(characterIterator, hitIndex))
+ clusterStart = hitIndex;
+ else {
+ clusterStart = textBreakPreceding(characterIterator, hitIndex);
+ if (clusterStart == TextBreakDone)
+ clusterStart = 0;
+ }
+
+ if (!includePartialGlyphs)
+ return coreTextRun.stringLocation() + clusterStart;
+
+ int clusterEnd = textBreakFollowing(characterIterator, hitIndex);
+ if (clusterEnd == TextBreakDone)
+ clusterEnd = stringLength;
+
+ CGFloat clusterWidth = adjustedAdvance;
+ // FIXME: The search stops at the boundaries of coreTextRun. In theory, it should go on into neighboring CoreTextRuns
+ // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
+ // reordering and on font fallback should occur within a CTLine.
+ if (clusterEnd - clusterStart > 1) {
+ int firstGlyphBeforeCluster = j - 1;
+ while (firstGlyphBeforeCluster && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
+ CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
+ clusterWidth += width;
+ x += width;
+ firstGlyphBeforeCluster--;
+ }
+ unsigned firstGlyphAfterCluster = j + 1;
+ while (firstGlyphAfterCluster < coreTextRun.glyphCount() && coreTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
+ clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
+ firstGlyphAfterCluster++;
+ }
+ }
+ if (x <= clusterWidth / 2)
+ return coreTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
+ else
+ return coreTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
+ }
+ x -= adjustedAdvance;
+ }
+ offsetIntoAdjustedGlyphs += coreTextRun.glyphCount();
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void CoreTextController::collectCoreTextRuns()
+{
+ if (!m_end)
+ return;
+
+ // We break up glyph run generation for the string by FontData and (if needed) the use of small caps.
+ const UChar* cp = m_run.characters();
+ bool hasTrailingSoftHyphen = m_run[m_end - 1] == softHyphen;
+
+ if (m_font.isSmallCaps() || hasTrailingSoftHyphen)
+ m_smallCapsBuffer.resize(m_end);
+
+ unsigned indexOfFontTransition = m_run.rtl() ? m_end - 1 : 0;
+ const UChar* curr = m_run.rtl() ? cp + m_end - 1 : cp;
+ const UChar* end = m_run.rtl() ? cp - 1 : cp + m_end;
+
+ // FIXME: Using HYPHEN-MINUS rather than HYPHEN because Times has a HYPHEN-MINUS glyph that looks like its
+ // SOFT-HYPHEN glyph, and has no HYPHEN glyph.
+ static const UChar hyphen = '-';
+
+ if (hasTrailingSoftHyphen && m_run.rtl()) {
+ collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);
+ indexOfFontTransition--;
+ curr--;
+ }
+
+ GlyphData glyphData;
+ GlyphData nextGlyphData;
+
+ bool isSurrogate = U16_IS_SURROGATE(*curr);
+ if (isSurrogate) {
+ if (m_run.ltr()) {
+ if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
+ } else {
+ if (!U16_IS_TRAIL(curr[0]) || curr -1 == end || !U16_IS_SURROGATE_LEAD(curr[-1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false);
+ }
+ } else
+ nextGlyphData = m_font.glyphDataForCharacter(*curr, false);
+
+ UChar newC = 0;
+
+ bool isSmallCaps;
+ bool nextIsSmallCaps = !isSurrogate && m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr;
+
+ if (nextIsSmallCaps)
+ m_smallCapsBuffer[curr - cp] = newC;
+
+ while (true) {
+ curr = m_run.rtl() ? curr - (isSurrogate ? 2 : 1) : curr + (isSurrogate ? 2 : 1);
+ if (curr == end)
+ break;
+
+ glyphData = nextGlyphData;
+ isSmallCaps = nextIsSmallCaps;
+ int index = curr - cp;
+ isSurrogate = U16_IS_SURROGATE(*curr);
+ UChar c = *curr;
+ bool forceSmallCaps = !isSurrogate && isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK);
+ if (isSurrogate) {
+ if (m_run.ltr()) {
+ if (!U16_IS_SURROGATE_LEAD(curr[0]) || curr + 1 == end || !U16_IS_TRAIL(curr[1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[0], curr[1]), false);
+ } else {
+ if (!U16_IS_TRAIL(curr[0]) || curr -1 == end || !U16_IS_SURROGATE_LEAD(curr[-1]))
+ return;
+ nextGlyphData = m_font.glyphDataForCharacter(U16_GET_SUPPLEMENTARY(curr[-1], curr[0]), false);
+ }
+ } else
+ nextGlyphData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps);
+
+ if (!isSurrogate && m_font.isSmallCaps()) {
+ nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
+ if (nextIsSmallCaps)
+ m_smallCapsBuffer[index] = forceSmallCaps ? c : newC;
+ }
+
+ if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) {
+ int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition;
+ int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition;
+ collectCoreTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0);
+ indexOfFontTransition = index;
+ }
+ }
+
+ int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition - (hasTrailingSoftHyphen ? 1 : 0);
+ if (itemLength) {
+ int itemStart = m_run.rtl() ? 0 : indexOfFontTransition;
+ collectCoreTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0);
+ }
+
+ if (hasTrailingSoftHyphen && m_run.ltr())
+ collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);
+}
+
+void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
+{
+ // FIXME: For offsets falling inside a ligature, we should advance only as far as the appropriate "ligature caret"
+ // or divide the width of the ligature by the number of offsets it encompasses and make an advance proportional
+ // to the offsets into the ligature. However, Core Text does not expose a low-level API for
+ // directly finding out how many characters a ligature encompasses (the "attachment count").
+ if (static_cast<int>(offset) > m_end)
+ offset = m_end;
+
+ if (offset <= m_currentCharacter)
+ return;
+
+ m_currentCharacter = offset;
+
+ size_t runCount = m_coreTextRuns.size();
+
+ bool ltr = m_run.ltr();
+
+ unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar;
+ while (m_currentRun < runCount) {
+ const CoreTextRun& coreTextRun = m_coreTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun];
+ size_t glyphCount = coreTextRun.glyphCount();
+ unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
+ while (m_glyphInCurrentRun < glyphCount) {
+ if (coreTextRun.indexAt(g) + coreTextRun.stringLocation() >= m_currentCharacter)
+ return;
+ CGSize adjustedAdvance = m_adjustedAdvances[k];
+ if (glyphBuffer)
+ glyphBuffer->add(m_adjustedGlyphs[k], coreTextRun.fontData(), adjustedAdvance);
+ m_runWidthSoFar += adjustedAdvance.width;
+ m_numGlyphsSoFar++;
+ m_glyphInCurrentRun++;
+ if (ltr) {
+ g++;
+ k++;
+ } else {
+ g--;
+ k--;
+ }
+ }
+ m_currentRun++;
+ m_glyphInCurrentRun = 0;
+ }
+ if (!ltr && m_numGlyphsSoFar == m_adjustedAdvances.size())
+ m_runWidthSoFar += m_finalRoundingWidth;
+}
+
+void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+{
+ if (!fontData) {
+ // Create a run of missing glyphs from the primary font.
+ m_coreTextRuns.append(CoreTextRun(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
+ return;
+ }
+
+ RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull));
+
+ RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes()));
+
+ RetainPtr<CTTypesetterRef> typesetter;
+
+ if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) {
+ 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()));
+ } else
+ typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get()));
+
+ RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
+
+ CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
+
+ CFIndex runCount = CFArrayGetCount(runArray);
+
+ for (CFIndex r = 0; r < runCount; r++) {
+ CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
+ ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
+ m_coreTextRuns.append(CoreTextRun(ctRun, fontData, cp, stringLocation, length));
+ }
+}
+
+void CoreTextController::adjustGlyphsAndAdvances()
+{
+ size_t runCount = m_coreTextRuns.size();
+ for (size_t r = 0; r < runCount; ++r) {
+ const CoreTextRun& coreTextRun = m_coreTextRuns[r];
+ unsigned glyphCount = coreTextRun.glyphCount();
+ const SimpleFontData* fontData = coreTextRun.fontData();
+
+ Vector<CGGlyph, 256> glyphsVector;
+ const CGGlyph* glyphs;
+
+ Vector<CGSize, 256> advancesVector;
+ const CGSize* advances;
+
+ if (coreTextRun.ctRun()) {
+ glyphs = CTRunGetGlyphsPtr(coreTextRun.ctRun());
+ if (!glyphs) {
+ glyphsVector.grow(glyphCount);
+ CTRunGetGlyphs(coreTextRun.ctRun(), CFRangeMake(0, 0), glyphsVector.data());
+ glyphs = glyphsVector.data();
+ }
+
+ advances = CTRunGetAdvancesPtr(coreTextRun.ctRun());
+ if (!advances) {
+ advancesVector.grow(glyphCount);
+ CTRunGetAdvances(coreTextRun.ctRun(), CFRangeMake(0, 0), advancesVector.data());
+ advances = advancesVector.data();
+ }
+ } else {
+ // Synthesize a run of missing glyphs.
+ glyphsVector.fill(0, glyphCount);
+ glyphs = glyphsVector.data();
+ advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), glyphCount);
+ advances = advancesVector.data();
+ }
+
+ bool lastRun = r + 1 == runCount;
+ const UChar* cp = coreTextRun.characters();
+ CGFloat roundedSpaceWidth = roundCGFloat(fontData->m_spaceWidth);
+ bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances();
+ bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled();
+
+
+ for (unsigned i = 0; i < glyphCount; i++) {
+ CFIndex characterIndex = coreTextRun.indexAt(i);
+ UChar ch = *(cp + characterIndex);
+ bool lastGlyph = lastRun && i + 1 == glyphCount;
+ UChar nextCh;
+ if (lastGlyph)
+ nextCh = ' ';
+ else if (i + 1 < glyphCount)
+ nextCh = *(cp + coreTextRun.indexAt(i + 1));
+ else
+ nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0));
+
+ bool treatAsSpace = Font::treatAsSpace(ch);
+ CGGlyph glyph = treatAsSpace ? fontData->m_spaceGlyph : glyphs[i];
+ CGSize advance = treatAsSpace ? CGSizeMake(fontData->m_spaceWidth, advances[i].height) : advances[i];
+
+ if (ch == '\t' && m_run.allowTabs()) {
+ float tabWidth = m_font.tabWidth();
+ advance.width = tabWidth - fmodf(m_run.xPos() + m_totalWidth, tabWidth);
+ } else if (ch == zeroWidthSpace || Font::treatAsZeroWidthSpace(ch) && !treatAsSpace) {
+ advance.width = 0;
+ glyph = fontData->m_spaceGlyph;
+ }
+
+ float roundedAdvanceWidth = roundf(advance.width);
+ if (roundsAdvances)
+ advance.width = roundedAdvanceWidth;
+
+ advance.width += fontData->m_syntheticBoldOffset;
+
+ // We special case spaces in two ways when applying word rounding.
+ // First, we round spaces to an adjusted width in all fonts.
+ // Second, in fixed-pitch fonts we ensure that all glyphs that
+ // match the width of the space glyph have the same width as the space glyph.
+ if (roundedAdvanceWidth == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding())
+ advance.width = fontData->m_adjustedSpaceWidth;
+
+ if (hasExtraSpacing) {
+ // If we're a glyph with an advance, go ahead and add in letter-spacing.
+ // That way we weed out zero width lurkers. This behavior matches the fast text code path.
+ if (advance.width && m_font.letterSpacing())
+ advance.width += m_font.letterSpacing();
+
+ // Handle justification and word-spacing.
+ if (glyph == fontData->m_spaceGlyph) {
+ // Account for padding. WebCore uses space padding to justify text.
+ // We distribute the specified padding over the available spaces in the run.
+ if (m_padding) {
+ // Use leftover padding if not evenly divisible by number of spaces.
+ if (m_padding < m_padPerSpace) {
+ advance.width += m_padding;
+ m_padding = 0;
+ } else {
+ advance.width += m_padPerSpace;
+ m_padding -= m_padPerSpace;
+ }
+ }
+
+ // Account for word-spacing.
+ if (treatAsSpace && characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing())
+ advance.width += m_font.wordSpacing();
+ }
+ }
+
+ // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters
+ // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
+ // We adjust the width of the last character of a "word" to ensure an integer width.
+ // Force characters that are used to determine word boundaries for the rounding hack
+ // to be integer width, so the following words will start on an integer boundary.
+ if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(ch))
+ advance.width = ceilCGFloat(advance.width);
+
+ // Check to see if the next character is a "rounding hack character", if so, adjust the
+ // width so that the total run width will be on an integer boundary.
+ if (m_run.applyWordRounding() && !lastGlyph && Font::isRoundingHackCharacter(nextCh) || m_run.applyRunRounding() && lastGlyph) {
+ CGFloat totalWidth = m_totalWidth + advance.width;
+ CGFloat extraWidth = ceilCGFloat(totalWidth) - totalWidth;
+ if (m_run.ltr())
+ advance.width += extraWidth;
+ else {
+ m_totalWidth += extraWidth;
+ if (m_lastRoundingGlyph)
+ m_adjustedAdvances[m_lastRoundingGlyph - 1].width += extraWidth;
+ else
+ m_finalRoundingWidth = extraWidth;
+ m_lastRoundingGlyph = m_adjustedAdvances.size() + 1;
+ }
+ }
+
+ m_totalWidth += advance.width;
+ advance.height *= -1;
+ m_adjustedAdvances.append(advance);
+ m_adjustedGlyphs.append(glyph);
+ }
+ }
+}
+
+} // namespace WebCore
+
+#endif // USE(CORE_TEXT)
diff --git a/WebCore/platform/graphics/mac/CoreTextController.h b/WebCore/platform/graphics/mac/CoreTextController.h
new file mode 100644
index 0000000..8dbb7fb
--- /dev/null
+++ b/WebCore/platform/graphics/mac/CoreTextController.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007, 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 CoreTextController_h
+#define CoreTextController_h
+
+#if USE(CORE_TEXT)
+
+#include "Font.h"
+#include "GlyphBuffer.h"
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class CoreTextController {
+public:
+ CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false);
+
+ // Advance and emit glyphs up to the specified character.
+ void advance(unsigned to, GlyphBuffer* = 0);
+
+ // Compute the character offset for a given x coordinate.
+ int offsetForPosition(int x, bool includePartialGlyphs);
+
+ // Returns the width of everything we've consumed so far.
+ float runWidthSoFar() const { return m_runWidthSoFar; }
+
+ float totalWidth() const { return m_totalWidth; }
+
+ // Extra width to the left of the leftmost glyph.
+ float finalRoundingWidth() const { return m_finalRoundingWidth; }
+
+private:
+ class CoreTextRun {
+ public:
+ CoreTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength);
+ CoreTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr);
+
+ CTRunRef ctRun() const { return m_CTRun.get(); }
+ unsigned glyphCount() const { return m_glyphCount; }
+ const SimpleFontData* fontData() const { return m_fontData; }
+ const UChar* characters() const { return m_characters; }
+ unsigned stringLocation() const { return m_stringLocation; }
+ size_t stringLength() const { return m_stringLength; }
+ CFIndex indexAt(size_t i) const { return m_indices[i]; }
+
+ private:
+ RetainPtr<CTRunRef> m_CTRun;
+ unsigned m_glyphCount;
+ const SimpleFontData* m_fontData;
+ const UChar* m_characters;
+ unsigned m_stringLocation;
+ size_t m_stringLength;
+ const CFIndex* m_indices;
+ // Used only if CTRunGet*Ptr fails or if this is a missing glyphs run.
+ RetainPtr<CFMutableDataRef> m_indicesData;
+ };
+
+ void collectCoreTextRuns();
+ void collectCoreTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
+ void adjustGlyphsAndAdvances();
+
+ const Font& m_font;
+ const TextRun& m_run;
+ bool m_mayUseNaturalWritingDirection;
+
+ Vector<UChar, 256> m_smallCapsBuffer;
+
+ Vector<CoreTextRun, 16> m_coreTextRuns;
+ Vector<CGSize, 256> m_adjustedAdvances;
+ Vector<CGGlyph, 256> m_adjustedGlyphs;
+
+ unsigned m_currentCharacter;
+ int m_end;
+
+ CGFloat m_totalWidth;
+
+ float m_runWidthSoFar;
+ unsigned m_numGlyphsSoFar;
+ size_t m_currentRun;
+ unsigned m_glyphInCurrentRun;
+ float m_finalRoundingWidth;
+ float m_padding;
+ float m_padPerSpace;
+
+ unsigned m_lastRoundingGlyph;
+};
+
+} // namespace WebCore
+#endif // USE(CORE_TEXT)
+#endif // CoreTextController_h
diff --git a/WebCore/platform/graphics/mac/FloatPointMac.mm b/WebCore/platform/graphics/mac/FloatPointMac.mm
new file mode 100644
index 0000000..2f73314
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FloatPointMac.mm
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatPoint.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+FloatPoint::FloatPoint(const NSPoint& p) : m_x(p.x), m_y(p.y)
+{
+}
+
+FloatPoint::operator NSPoint() const
+{
+ return NSMakePoint(m_x, m_y);
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/graphics/mac/FloatRectMac.mm b/WebCore/platform/graphics/mac/FloatRectMac.mm
new file mode 100644
index 0000000..1d6b045
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FloatRectMac.mm
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatRect.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+FloatRect::FloatRect(const NSRect& r) : m_location(r.origin), m_size(r.size)
+{
+}
+
+FloatRect::operator NSRect() const
+{
+ return NSMakeRect(x(), y(), width(), height());
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/graphics/mac/FloatSizeMac.mm b/WebCore/platform/graphics/mac/FloatSizeMac.mm
new file mode 100644
index 0000000..01efbe9
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FloatSizeMac.mm
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005 Nokia. 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 "FloatSize.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+FloatSize::FloatSize(const NSSize& s) : m_width(s.width), m_height(s.height)
+{
+}
+
+FloatSize::operator NSSize() const
+{
+ return NSMakeSize(m_width, m_height);
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm
new file mode 100644
index 0000000..e7cda66
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontCacheMac.mm
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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.
+ */
+
+#import "config.h"
+#import "FontCache.h"
+
+#import "Font.h"
+#import "SimpleFontData.h"
+#import "FontPlatformData.h"
+#import "WebCoreSystemInterface.h"
+#import "WebFontCache.h"
+
+#ifdef BUILDING_ON_TIGER
+typedef int NSInteger;
+#endif
+
+namespace WebCore {
+
+static void fontCacheATSNotificationCallback(ATSFontNotificationInfoRef, void*)
+{
+ FontCache::invalidate();
+}
+
+void FontCache::platformInit()
+{
+ wkSetUpFontCache();
+ // FIXME: Passing kATSFontNotifyOptionReceiveWhileSuspended may be an overkill and does not seem to work anyway.
+ ATSFontNotificationSubscribe(fontCacheATSNotificationCallback, kATSFontNotifyOptionReceiveWhileSuspended, 0, 0);
+}
+
+static int toAppKitFontWeight(FontWeight fontWeight)
+{
+ static int appKitFontWeights[] = {
+ 2, // FontWeight100
+ 3, // FontWeight200
+ 4, // FontWeight300
+ 5, // FontWeight400
+ 6, // FontWeight500
+ 8, // FontWeight600
+ 9, // FontWeight700
+ 10, // FontWeight800
+ 12, // FontWeight900
+ };
+ return appKitFontWeights[fontWeight];
+}
+
+static inline bool isAppKitFontWeightBold(NSInteger appKitFontWeight)
+{
+ return appKitFontWeight >= 7;
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ const FontPlatformData& platformData = font.fontDataAt(0)->fontDataForCharacter(characters[0])->platformData();
+ NSFont *nsFont = platformData.font();
+
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(characters) length:length freeWhenDone:NO];
+ NSFont *substituteFont = wkGetFontInLanguageForRange(nsFont, string, NSMakeRange(0, length));
+ [string release];
+
+ if (!substituteFont && length == 1)
+ substituteFont = wkGetFontInLanguageForCharacter(nsFont, characters[0]);
+ if (!substituteFont)
+ return 0;
+
+ // Use the family name from the AppKit-supplied substitute font, requesting the
+ // traits, weight, and size we want. One way this does better than the original
+ // AppKit request is that it takes synthetic bold and oblique into account.
+ // But it does create the possibility that we could end up with a font that
+ // doesn't actually cover the characters we need.
+
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+
+ NSFontTraitMask traits;
+ NSInteger weight;
+ CGFloat size;
+
+ if (nsFont) {
+ traits = [fontManager traitsOfFont:nsFont];
+ if (platformData.m_syntheticBold)
+ traits |= NSBoldFontMask;
+ if (platformData.m_syntheticOblique)
+ traits |= NSFontItalicTrait;
+ weight = [fontManager weightOfFont:nsFont];
+ size = [nsFont pointSize];
+ } else {
+ // For custom fonts nsFont is nil.
+ traits = font.italic() ? NSFontItalicTrait : 0;
+ weight = toAppKitFontWeight(font.weight());
+ size = font.pixelSize();
+ }
+
+ if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont familyName] traits:traits weight:weight size:size])
+ substituteFont = bestVariation;
+
+ substituteFont = font.fontDescription().usePrinterFont() ? [substituteFont printerFont] : [substituteFont screenFont];
+
+ NSFontTraitMask substituteFontTraits = [fontManager traitsOfFont:substituteFont];
+ NSInteger substituteFontWeight = [fontManager weightOfFont:substituteFont];
+
+ FontPlatformData alternateFont(substituteFont,
+ !font.isPlatformFont() && isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(substituteFontWeight),
+ !font.isPlatformFont() && (traits & NSFontItalicTrait) && !(substituteFontTraits & NSFontItalicTrait));
+ return getCachedFontData(&alternateFont);
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ // Attempt to find an appropriate font using a match based on
+ // the presence of keywords in the the requested names. For example, we'll
+ // match any name that contains "Arabic" to Geeza Pro.
+ FontPlatformData* platformData = 0;
+ 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");
+ for (int j = 0; j < 3 && !platformData; ++j)
+ if (currFamily->family().contains(matchWords[j], false))
+ platformData = getCachedFontPlatformData(font.fontDescription(), geezaStr);
+ }
+ currFamily = currFamily->next();
+ }
+
+ return platformData;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ static AtomicString timesStr("Times");
+ static 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.
+ FontPlatformData* platformFont = getCachedFontPlatformData(fontDescription, timesStr);
+ if (!platformFont)
+ // The Times fallback will almost always work, but in the highly unusual case where
+ // the user doesn't have it, we fall back on Lucida Grande because that's
+ // guaranteed to be there, according to Nathan Taylor. This is good enough
+ // to avoid a crash at least.
+ platformFont = getCachedFontPlatformData(fontDescription, lucidaGrandeStr);
+
+ return platformFont;
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ [WebFontCache getTraits:traitsMasks inFamily:familyName];
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ NSFontTraitMask traits = fontDescription.italic() ? NSFontItalicTrait : 0;
+ NSInteger weight = toAppKitFontWeight(fontDescription.weight());
+ float size = fontDescription.computedPixelSize();
+
+ NSFont *nsFont = [WebFontCache fontWithFamily:family traits:traits weight:weight size:size];
+ if (!nsFont)
+ return 0;
+
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSFontTraitMask actualTraits = 0;
+ if (fontDescription.italic())
+ actualTraits = [fontManager traitsOfFont:nsFont];
+ NSInteger actualWeight = [fontManager weightOfFont:nsFont];
+
+ FontPlatformData* result = new FontPlatformData;
+
+ // Use the correct font for print vs. screen.
+ result->setFont(fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont]);
+ result->m_syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight);
+ result->m_syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait);
+ return result;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..1fb144c
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault);
+ CGFontRelease(m_cgFont);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
+{
+ return FontPlatformData(m_cgFont, (ATSUFontID)m_atsFont, size, bold, italic);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ // Use ATS to activate the font.
+ ATSFontContainerRef containerRef = 0;
+
+ // The value "3" means that the font is private and can't be seen by anyone else.
+ ATSFontActivateFromMemory((void*)buffer->data(), buffer->size(), 3, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &containerRef);
+ if (!containerRef)
+ return 0;
+ ItemCount fontCount;
+ ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 0, NULL, &fontCount);
+
+ // We just support the first font in the list.
+ if (fontCount == 0) {
+ ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ return 0;
+ }
+
+ ATSFontRef fontRef = 0;
+ ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, &fontRef, NULL);
+ if (!fontRef) {
+ ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ return 0;
+ }
+
+ CGFontRef cgFontRef = CGFontCreateWithPlatformFont(&fontRef);
+#ifndef BUILDING_ON_TIGER
+ // Workaround for <rdar://problem/5675504>.
+ if (!CGFontGetNumberOfGlyphs(cgFontRef)) {
+ CFRelease(cgFontRef);
+ cgFontRef = 0;
+ }
+#endif
+ if (!cgFontRef) {
+ ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
+ return 0;
+ }
+
+ return new FontCustomPlatformData(containerRef, fontRef, cgFontRef);
+}
+
+}
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
new file mode 100644
index 0000000..1e73ae0
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontRenderingMode.h"
+#include <wtf/Noncopyable.h>
+
+typedef struct CGFont* CGFontRef;
+typedef UInt32 ATSFontContainerRef;
+typedef UInt32 ATSFontRef;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(ATSFontContainerRef container, ATSFontRef atsFont, CGFontRef cgFont)
+ : m_atsContainer(container), m_atsFont(atsFont), m_cgFont(cgFont)
+ {}
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
+
+ ATSFontContainerRef m_atsContainer;
+ ATSFontRef m_atsFont;
+ CGFontRef m_cgFont;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm
new file mode 100644
index 0000000..bef18d0
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontMac.mm
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#import "config.h"
+#import "Font.h"
+
+#import "GlyphBuffer.h"
+#import "GraphicsContext.h"
+#import "Logging.h"
+#import "SimpleFontData.h"
+#import "WebCoreSystemInterface.h"
+#import "WebCoreTextRenderer.h"
+
+#define SYNTHETIC_OBLIQUE_ANGLE 14
+
+#ifdef __LP64__
+#define URefCon void*
+#else
+#define URefCon UInt32
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
+{
+ CGContextRef cgContext = context->platformContext();
+
+ bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext);
+ bool newShouldUseFontSmoothing = WebCoreShouldUseFontSmoothing();
+
+ if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing)
+ CGContextSetShouldSmoothFonts(cgContext, newShouldUseFontSmoothing);
+
+ const FontPlatformData& platformData = font->platformData();
+ NSFont* drawFont;
+ if (!isPrinterFont()) {
+ drawFont = [platformData.font() screenFont];
+ if (drawFont != platformData.font())
+ // We are getting this in too many places (3406411); use ERROR so it only prints on debug versions for now. (We should debug this also, eventually).
+ LOG_ERROR("Attempting to set non-screen font (%@) when drawing to screen. Using screen font anyway, may result in incorrect metrics.",
+ [[[platformData.font() fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
+ } else {
+ drawFont = [platformData.font() printerFont];
+ if (drawFont != platformData.font())
+ NSLog(@"Attempting to set non-printer font (%@) when printing. Using printer font anyway, may result in incorrect metrics.",
+ [[[platformData.font() fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
+ }
+
+ CGContextSetFont(cgContext, platformData.cgFont());
+
+ CGAffineTransform matrix = CGAffineTransformIdentity;
+ if (drawFont)
+ memcpy(&matrix, [drawFont matrix], sizeof(matrix));
+ matrix.b = -matrix.b;
+ matrix.d = -matrix.d;
+ if (platformData.m_syntheticOblique)
+ matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0));
+ CGContextSetTextMatrix(cgContext, matrix);
+
+ if (drawFont) {
+ wkSetCGFontRenderingMode(cgContext, drawFont);
+ CGContextSetFontSize(cgContext, 1.0f);
+ } else
+ CGContextSetFontSize(cgContext, platformData.m_size);
+
+ IntSize shadowSize;
+ int shadowBlur;
+ Color shadowColor;
+ context->getShadow(shadowSize, shadowBlur, shadowColor);
+
+ bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur;
+ if (hasSimpleShadow) {
+ // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
+ context->clearShadow();
+ Color fillColor = context->fillColor();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ context->setFillColor(shadowFillColor);
+ CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->m_syntheticBoldOffset) {
+ CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + shadowSize.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+ context->setFillColor(fillColor);
+ }
+
+ CGContextSetTextPosition(cgContext, point.x(), point.y());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->m_syntheticBoldOffset) {
+ CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+
+ if (hasSimpleShadow)
+ context->setShadow(shadowSize, shadowBlur, shadowColor);
+
+ if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing)
+ CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing);
+}
+
+}
diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm
new file mode 100644
index 0000000..9a45c5a
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm
@@ -0,0 +1,623 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#import "config.h"
+#import "Font.h"
+
+#if USE(ATSUI)
+
+#import "CharacterNames.h"
+#import "GraphicsContext.h"
+#import "Logging.h"
+#import "ShapeArabic.h"
+#import "SimpleFontData.h"
+#import <wtf/OwnArrayPtr.h>
+
+#define SYNTHETIC_OBLIQUE_ANGLE 14
+
+#ifdef __LP64__
+#define URefCon void*
+#else
+#define URefCon UInt32
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+struct ATSULayoutParameters : Noncopyable
+{
+ ATSULayoutParameters(const TextRun& run)
+ : m_run(run)
+ , m_font(0)
+ , m_hasSyntheticBold(false)
+ , m_syntheticBoldPass(false)
+ , m_padPerSpace(0)
+ {}
+
+ ~ATSULayoutParameters()
+ {
+ ATSUDisposeTextLayout(m_layout);
+ }
+
+ void initialize(const Font*, const GraphicsContext* = 0);
+
+ const TextRun& m_run;
+
+ const Font* m_font;
+
+ ATSUTextLayout m_layout;
+ OwnArrayPtr<const SimpleFontData*> m_fonts;
+
+ OwnArrayPtr<UChar> m_charBuffer;
+ bool m_hasSyntheticBold;
+ bool m_syntheticBoldPass;
+ float m_padPerSpace;
+};
+
+static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride)
+{
+ if (!run.directionalOverride())
+ return run;
+
+ charactersWithOverride.set(new UChar[run.length() + 2]);
+ charactersWithOverride[0] = run.rtl() ? rightToLeftOverride : leftToRightOverride;
+ memcpy(&charactersWithOverride[1], run.data(0), sizeof(UChar) * run.length());
+ charactersWithOverride[run.length() + 1] = popDirectionalFormatting;
+
+ TextRun result = run;
+ result.setText(charactersWithOverride.get(), run.length() + 2);
+ return result;
+}
+
+static bool fontHasMirroringInfo(ATSUFontID fontID)
+{
+ ByteCount propTableSize;
+ OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);
+ if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info
+ return true;
+ else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error
+ LOG_ERROR("ATSFontGetTable failed (%d)", status);
+
+ return false;
+}
+
+static void disableLigatures(const SimpleFontData* fontData)
+{
+ // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are
+ // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.
+ // See bugzilla 5166.
+ if (fontData->platformData().allowsLigatures())
+ return;
+
+ ATSUFontFeatureType featureTypes[] = { kLigaturesType };
+ ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
+ OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status);
+}
+
+static void initializeATSUStyle(const SimpleFontData* fontData)
+{
+ if (fontData->m_ATSUStyleInitialized)
+ return;
+
+ ATSUFontID fontID = fontData->platformData().m_atsuFontID;
+ if (!fontID) {
+ LOG_ERROR("unable to get ATSUFontID for %@", fontData->m_font.font());
+ return;
+ }
+
+ OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle);
+ if (status != noErr)
+ // Who knows how many ATSU functions will crash when passed a NULL style...
+ LOG_ERROR("ATSUCreateStyle failed (%d)", status);
+
+ CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
+ if (fontData->m_font.m_syntheticOblique)
+ transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0));
+ Fixed fontSize = FloatToFixed(fontData->platformData().m_size);
+ ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) };
+ // Turn off automatic kerning until it is supported in the CG code path (bug 6136)
+ Fract kerningInhibitFactor = FloatToFract(1.0);
+
+ ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
+ ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor };
+ status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetAttributes failed (%d)", status);
+
+ fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID);
+
+ // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bug 6135 is fixed.
+ disableLigatures(fontData);
+
+ fontData->m_ATSUStyleInitialized = true;
+}
+
+static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector iCurrentOperation, ATSULineRef iLineRef, URefCon iRefCon,
+ void *iOperationCallbackParameterPtr, ATSULayoutOperationCallbackStatus *oCallbackStatus)
+{
+ ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon);
+ OSStatus status;
+ ItemCount count;
+ ATSLayoutRecord *layoutRecords;
+
+ if (params->m_run.applyWordRounding()) {
+ status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, (void **)&layoutRecords, &count);
+ if (status != noErr) {
+ *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;
+ return status;
+ }
+
+ Fixed lastNativePos = 0;
+ float lastAdjustedPos = 0;
+ const UChar* characters = params->m_charBuffer ? params->m_charBuffer.get() : params->m_run.characters();
+ const SimpleFontData** renderers = params->m_fonts.get();
+ const SimpleFontData* renderer;
+ const SimpleFontData* lastRenderer = 0;
+ ByteCount offset = layoutRecords[0].originalOffset;
+ UChar nextCh = *(UChar *)(((char *)characters)+offset);
+ bool shouldRound = false;
+ bool syntheticBoldPass = params->m_syntheticBoldPass;
+ Fixed syntheticBoldOffset = 0;
+ ATSGlyphRef spaceGlyph = 0;
+ bool hasExtraSpacing = (params->m_font->letterSpacing() || params->m_font->wordSpacing() || params->m_run.padding()) && !params->m_run.spacingDisabled();
+ float padding = params->m_run.padding();
+ // In the CoreGraphics code path, the rounding hack is applied in logical order.
+ // Here it is applied in visual left-to-right order, which may be better.
+ ItemCount lastRoundingChar = 0;
+ ItemCount i;
+ for (i = 1; i < count; i++) {
+ bool isLastChar = i == count - 1;
+ renderer = renderers[offset / 2];
+ if (renderer != lastRenderer) {
+ lastRenderer = renderer;
+ spaceGlyph = renderer->m_spaceGlyph;
+ // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems
+ // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI
+ // does in any of its device-metrics modes.
+ shouldRound = renderer->platformData().roundsGlyphAdvances();
+ if (syntheticBoldPass)
+ syntheticBoldOffset = FloatToFixed(renderer->m_syntheticBoldOffset);
+ }
+ float width;
+ if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) {
+ width = 0;
+ layoutRecords[i-1].glyphID = spaceGlyph;
+ } else {
+ width = FixedToFloat(layoutRecords[i].realPos - lastNativePos);
+ if (shouldRound)
+ width = roundf(width);
+ width += renderer->m_syntheticBoldOffset;
+ if (renderer->m_treatAsFixedPitch ? width == renderer->m_spaceWidth : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace))
+ width = renderer->m_adjustedSpaceWidth;
+ }
+ lastNativePos = layoutRecords[i].realPos;
+
+ if (hasExtraSpacing) {
+ if (width && params->m_font->letterSpacing())
+ width +=params->m_font->letterSpacing();
+ if (Font::treatAsSpace(nextCh)) {
+ if (params->m_run.padding()) {
+ if (padding < params->m_padPerSpace) {
+ width += padding;
+ padding = 0;
+ } else {
+ width += params->m_padPerSpace;
+ padding -= params->m_padPerSpace;
+ }
+ }
+ if (offset != 0 && !Font::treatAsSpace(*((UChar *)(((char *)characters)+offset) - 1)) && params->m_font->wordSpacing())
+ width += params->m_font->wordSpacing();
+ }
+ }
+
+ UChar ch = nextCh;
+ offset = layoutRecords[i].originalOffset;
+ // Use space for nextCh at the end of the loop so that we get inside the rounding hack code.
+ // We won't actually round unless the other conditions are satisfied.
+ nextCh = isLastChar ? ' ' : *(UChar *)(((char *)characters)+offset);
+
+ if (Font::isRoundingHackCharacter(ch))
+ width = ceilf(width);
+ lastAdjustedPos = lastAdjustedPos + width;
+ if (Font::isRoundingHackCharacter(nextCh) && (!isLastChar || params->m_run.applyRunRounding())){
+ if (params->m_run.ltr())
+ lastAdjustedPos = ceilf(lastAdjustedPos);
+ else {
+ float roundingWidth = ceilf(lastAdjustedPos) - lastAdjustedPos;
+ Fixed rw = FloatToFixed(roundingWidth);
+ ItemCount j;
+ for (j = lastRoundingChar; j < i; j++)
+ layoutRecords[j].realPos += rw;
+ lastRoundingChar = i;
+ lastAdjustedPos += roundingWidth;
+ }
+ }
+ if (syntheticBoldPass) {
+ if (syntheticBoldOffset)
+ layoutRecords[i-1].realPos += syntheticBoldOffset;
+ else
+ layoutRecords[i-1].glyphID = spaceGlyph;
+ }
+ layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos);
+ }
+
+ status = ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords);
+ }
+ *oCallbackStatus = kATSULayoutOperationCallbackStatusHandled;
+ return noErr;
+}
+
+static inline bool isArabicLamWithAlefLigature(UChar c)
+{
+ return c >= 0xfef5 && c <= 0xfefc;
+}
+
+static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength, unsigned shapingStart)
+{
+ while (shapingStart < totalLength) {
+ unsigned shapingEnd;
+ // We do not want to pass a Lam with Alef ligature followed by a space to the shaper,
+ // since we want to be able to identify this sequence as the result of shaping a Lam
+ // followed by an Alef and padding with a space.
+ bool foundLigatureSpace = false;
+ for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd)
+ foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' ';
+ shapingEnd++;
+
+ UErrorCode shapingError = U_ZERO_ERROR;
+ unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError);
+
+ if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) {
+ for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) {
+ if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ')
+ dest[++j] = zeroWidthSpace;
+ }
+ if (foundLigatureSpace) {
+ dest[shapingEnd] = ' ';
+ shapingEnd++;
+ } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) {
+ // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef,
+ // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR.
+ ASSERT(dest[shapingStart] == ' ');
+ dest[shapingStart] = zeroWidthSpace;
+ }
+ } else {
+ // Something went wrong. Abandon shaping and just copy the rest of the buffer.
+ LOG_ERROR("u_shapeArabic failed(%d)", shapingError);
+ shapingEnd = totalLength;
+ memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar));
+ }
+ shapingStart = shapingEnd;
+ }
+}
+
+void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* graphicsContext)
+{
+ m_font = font;
+
+ const SimpleFontData* fontData = font->primaryFont();
+ m_fonts.set(new const SimpleFontData*[m_run.length()]);
+ if (font->isSmallCaps())
+ m_charBuffer.set(new UChar[m_run.length()]);
+
+ ATSUTextLayout layout;
+ OSStatus status;
+ ATSULayoutOperationOverrideSpecifier overrideSpecifier;
+
+ initializeATSUStyle(fontData);
+
+ // FIXME: This is currently missing the following required features that the CoreGraphics code path has:
+ // - \n, \t, and nonbreaking space render as a space.
+
+ UniCharCount runLength = m_run.length();
+
+ if (m_charBuffer)
+ memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar));
+
+ status = ATSUCreateTextLayoutWithTextPtr(
+ (m_charBuffer ? m_charBuffer.get() : m_run.characters()),
+ 0, // offset
+ runLength, // length
+ runLength, // total length
+ 1, // styleRunCount
+ &runLength, // length of style run
+ &fontData->m_ATSUStyle,
+ &layout);
+ if (status != noErr)
+ LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed(%d)", status);
+ m_layout = layout;
+ ATSUSetTextLayoutRefCon(m_layout, (URefCon)this);
+
+ // FIXME: There are certain times when this method is called, when we don't have access to a GraphicsContext
+ // measuring text runs with floatWidthForComplexText is one example.
+ // ATSUI requires that we pass a valid CGContextRef to it when specifying kATSUCGContextTag (crashes when passed 0)
+ // ATSUI disables sub-pixel rendering if kATSUCGContextTag is not specified! So we're in a bind.
+ // Sometimes [[NSGraphicsContext currentContext] graphicsPort] may return the wrong (or no!) context. Nothing we can do about it (yet).
+ CGContextRef cgContext = graphicsContext ? graphicsContext->platformContext() : (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+
+ ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
+ Boolean rtl = m_run.rtl();
+ overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
+ overrideSpecifier.overrideUPP = overrideLayoutOperation;
+ ATSUAttributeTag tags[] = { kATSUCGContextTag, kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag };
+ ByteCount sizes[] = { sizeof(CGContextRef), sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) };
+ ATSUAttributeValuePtr values[] = { &cgContext, &lineLayoutOptions, &rtl, &overrideSpecifier };
+
+ status = ATSUSetLayoutControls(layout, (m_run.applyWordRounding() ? 4 : 3), tags, sizes, values);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetLayoutControls failed(%d)", status);
+
+ status = ATSUSetTransientFontMatching(layout, YES);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetTransientFontMatching failed(%d)", status);
+
+ m_hasSyntheticBold = false;
+ ATSUFontID ATSUSubstituteFont;
+ UniCharArrayOffset substituteOffset = 0;
+ UniCharCount substituteLength;
+ UniCharArrayOffset lastOffset;
+ const SimpleFontData* substituteFontData = 0;
+
+ while (substituteOffset < runLength) {
+ // FIXME: Using ATSUMatchFontsToText() here results in several problems: the CSS font family list is not necessarily followed for the 2nd
+ // and onwards unmatched characters; segmented fonts do not work correctly; behavior does not match the simple text and Uniscribe code
+ // paths. Change this function to use Font::glyphDataForCharacter() for each character instead.
+ lastOffset = substituteOffset;
+ status = ATSUMatchFontsToText(layout, substituteOffset, kATSUToTextEnd, &ATSUSubstituteFont, &substituteOffset, &substituteLength);
+ if (status == kATSUFontsMatched || status == kATSUFontsNotMatched) {
+ const FontData* fallbackFontData = m_font->fontDataForCharacters(m_run.characters() + substituteOffset, substituteLength);
+ substituteFontData = fallbackFontData ? fallbackFontData->fontDataForCharacter(m_run[0]) : 0;
+ if (substituteFontData) {
+ initializeATSUStyle(substituteFontData);
+ if (substituteFontData->m_ATSUStyle)
+ ATSUSetRunStyle(layout, substituteFontData->m_ATSUStyle, substituteOffset, substituteLength);
+ } else
+ substituteFontData = fontData;
+ } else {
+ substituteOffset = runLength;
+ substituteLength = 0;
+ }
+
+ bool shapedArabic = false;
+ bool isSmallCap = false;
+ UniCharArrayOffset firstSmallCap = 0;
+ const SimpleFontData *r = fontData;
+ UniCharArrayOffset i;
+ for (i = lastOffset; ; i++) {
+ if (i == substituteOffset || i == substituteOffset + substituteLength) {
+ if (isSmallCap) {
+ isSmallCap = false;
+ initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription()));
+ ATSUSetRunStyle(layout, r->smallCapsFontData(m_font->fontDescription())->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
+ }
+ if (i == substituteOffset && substituteLength > 0)
+ r = substituteFontData;
+ else
+ break;
+ }
+ if (!shapedArabic && WTF::Unicode::isArabicChar(m_run[i]) && !r->shapesArabic()) {
+ shapedArabic = true;
+ if (!m_charBuffer) {
+ m_charBuffer.set(new UChar[runLength]);
+ memcpy(m_charBuffer.get(), m_run.characters(), i * sizeof(UChar));
+ ATSUTextMoved(layout, m_charBuffer.get());
+ }
+ shapeArabic(m_run.characters(), m_charBuffer.get(), runLength, i);
+ }
+ if (m_run.rtl() && !r->m_ATSUMirrors) {
+ UChar mirroredChar = u_charMirror(m_run[i]);
+ if (mirroredChar != m_run[i]) {
+ if (!m_charBuffer) {
+ m_charBuffer.set(new UChar[runLength]);
+ memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar));
+ ATSUTextMoved(layout, m_charBuffer.get());
+ }
+ m_charBuffer[i] = mirroredChar;
+ }
+ }
+ if (m_font->isSmallCaps()) {
+ const SimpleFontData* smallCapsData = r->smallCapsFontData(m_font->fontDescription());
+ UChar c = m_charBuffer[i];
+ UChar newC;
+ if (U_GET_GC_MASK(c) & U_GC_M_MASK)
+ m_fonts[i] = isSmallCap ? smallCapsData : r;
+ else if (!u_isUUppercase(c) && (newC = u_toupper(c)) != c) {
+ m_charBuffer[i] = newC;
+ if (!isSmallCap) {
+ isSmallCap = true;
+ firstSmallCap = i;
+ }
+ m_fonts[i] = smallCapsData;
+ } else {
+ if (isSmallCap) {
+ isSmallCap = false;
+ initializeATSUStyle(smallCapsData);
+ ATSUSetRunStyle(layout, smallCapsData->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
+ }
+ m_fonts[i] = r;
+ }
+ } else
+ m_fonts[i] = r;
+ if (m_fonts[i]->m_syntheticBoldOffset)
+ m_hasSyntheticBold = true;
+ }
+ substituteOffset += substituteLength;
+ }
+ if (m_run.padding()) {
+ float numSpaces = 0;
+ unsigned k;
+ for (k = 0; k < runLength; k++)
+ if (Font::treatAsSpace(m_run[k]))
+ numSpaces++;
+
+ if (numSpaces == 0)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = ceilf(m_run.padding() / numSpaces);
+ } else
+ m_padPerSpace = 0;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
+{
+ OwnArrayPtr<UChar> charactersWithOverride;
+ TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride);
+ if (run.directionalOverride()) {
+ from++;
+ to++;
+ }
+
+ ATSULayoutParameters params(adjustedRun);
+ params.initialize(this);
+
+ ATSTrapezoid firstGlyphBounds;
+ ItemCount actualNumBounds;
+
+ OSStatus status = ATSUGetGlyphBounds(params.m_layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);
+ if (status != noErr || actualNumBounds != 1) {
+ static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
+ firstGlyphBounds = zeroTrapezoid;
+ }
+
+ float beforeWidth = MIN(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x));
+ float afterWidth = MAX(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x));
+
+ FloatRect rect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+
+ return rect;
+}
+
+void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ OSStatus status;
+
+ int drawPortionLength = to - from;
+ OwnArrayPtr<UChar> charactersWithOverride;
+ TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride);
+ if (run.directionalOverride())
+ from++;
+
+ ATSULayoutParameters params(adjustedRun);
+ params.initialize(this, graphicsContext);
+
+ // ATSUI can't draw beyond -32768 to +32767 so we translate the CTM and tell ATSUI to draw at (0, 0).
+ CGContextRef context = graphicsContext->platformContext();
+ CGContextTranslateCTM(context, point.x(), point.y());
+
+ IntSize shadowSize;
+ int shadowBlur;
+ Color shadowColor;
+ graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor);
+
+ bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur;
+ if (hasSimpleShadow) {
+ // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
+ graphicsContext->clearShadow();
+ Color fillColor = graphicsContext->fillColor();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ graphicsContext->setFillColor(shadowFillColor);
+ CGContextTranslateCTM(context, shadowSize.width(), shadowSize.height());
+ status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
+ if (status == noErr && params.m_hasSyntheticBold) {
+ // Force relayout for the bold pass
+ ATSUClearLayoutCache(params.m_layout, 0);
+ params.m_syntheticBoldPass = true;
+ status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
+ // Force relayout for the next pass
+ ATSUClearLayoutCache(params.m_layout, 0);
+ params.m_syntheticBoldPass = false;
+ }
+ CGContextTranslateCTM(context, -shadowSize.width(), -shadowSize.height());
+ graphicsContext->setFillColor(fillColor);
+ }
+
+ status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
+ if (status == noErr && params.m_hasSyntheticBold) {
+ // Force relayout for the bold pass
+ ATSUClearLayoutCache(params.m_layout, 0);
+ params.m_syntheticBoldPass = true;
+ status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
+ }
+ CGContextTranslateCTM(context, -point.x(), -point.y());
+
+ if (status != noErr)
+ // Nothing to do but report the error (dev build only).
+ LOG_ERROR("ATSUDrawText() failed(%d)", status);
+
+ if (hasSimpleShadow)
+ graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor);
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ if (run.length() == 0)
+ return 0;
+
+ ATSULayoutParameters params(run);
+ params.initialize(this);
+
+ OSStatus status;
+
+ ATSTrapezoid firstGlyphBounds;
+ ItemCount actualNumBounds;
+ status = ATSUGetGlyphBounds(params.m_layout, 0, 0, 0, run.length(), kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);
+ if (status != noErr)
+ LOG_ERROR("ATSUGetGlyphBounds() failed(%d)", status);
+ if (actualNumBounds != 1)
+ LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds);
+
+ return MAX(FixedToFloat(firstGlyphBounds.upperRight.x), FixedToFloat(firstGlyphBounds.lowerRight.x)) -
+ MIN(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x));
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ OwnArrayPtr<UChar> charactersWithOverride;
+ TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride);
+
+ ATSULayoutParameters params(adjustedRun);
+ params.initialize(this);
+
+ UniCharArrayOffset primaryOffset = 0;
+
+ // FIXME: No idea how to avoid including partial glyphs.
+ // Not even sure if that's the behavior this yields now.
+ Boolean isLeading;
+ UniCharArrayOffset secondaryOffset = 0;
+ OSStatus status = ATSUPositionToOffset(params.m_layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset);
+ unsigned offset;
+ if (status == noErr) {
+ offset = (unsigned)primaryOffset;
+ if (run.directionalOverride() && offset > 0)
+ offset--;
+ } else
+ // Failed to find offset! Return 0 offset.
+ offset = 0;
+
+ return offset;
+}
+
+}
+#endif // USE(ATSUI)
diff --git a/WebCore/platform/graphics/mac/FontMacCoreText.cpp b/WebCore/platform/graphics/mac/FontMacCoreText.cpp
new file mode 100644
index 0000000..5fb9d5d
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontMacCoreText.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2006, 2007, 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#if USE(CORE_TEXT)
+
+#include "CoreTextController.h"
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "SimpleFontData.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h,
+ int from, int to) const
+{
+ CoreTextController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to);
+ float afterWidth = controller.runWidthSoFar();
+
+ // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
+ if (run.rtl()) {
+ float totalWidth = controller.totalWidth();
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+ }
+
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+}
+
+void Font::drawComplexText(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();
+ CoreTextController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to, &glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ float afterWidth = controller.runWidthSoFar();
+
+ if (run.rtl()) {
+ startX += controller.totalWidth() + controller.finalRoundingWidth() - afterWidth;
+ for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
+ glyphBuffer.swap(i, end);
+ } else
+ startX += beforeWidth;
+
+ // Draw the glyph buffer now at the starting point returned in startX.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, run, startPoint);
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ CoreTextController controller(this, run, true);
+ return controller.totalWidth();
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ CoreTextController controller(this, run);
+ return controller.offsetForPosition(x, includePartialGlyphs);
+}
+
+}
+#endif // USE(CORE_TEXT)
diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h
new file mode 100644
index 0000000..40a2dbd
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontPlatformData.h
@@ -0,0 +1,126 @@
+/*
+ * This file is part of the internal font implementation.
+ * It should not be included by source files outside it.
+ *
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include "StringImpl.h"
+
+#ifdef __OBJC__
+@class NSFont;
+#else
+class NSFont;
+#endif
+
+typedef struct CGFont* CGFontRef;
+typedef UInt32 ATSUFontID;
+#ifndef BUILDING_ON_TIGER
+typedef const struct __CTFont* CTFontRef;
+#endif
+
+#include <CoreFoundation/CFBase.h>
+#include <objc/objc-auto.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+#ifndef BUILDING_ON_TIGER
+inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); }
+#endif
+
+struct FontPlatformData {
+ FontPlatformData(float size, bool syntheticBold, bool syntheticOblique)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
+ , m_atsuFontID(0)
+ , m_size(size)
+ , m_font(0)
+#ifdef BUILDING_ON_TIGER
+ , m_cgFont(0)
+#endif
+ {
+ }
+
+ FontPlatformData(NSFont * = 0, bool syntheticBold = false, bool syntheticOblique = false);
+
+ FontPlatformData(CGFontRef f, ATSUFontID fontID, float s, bool b , bool o)
+ : m_syntheticBold(b), m_syntheticOblique(o), m_atsuFontID(fontID), m_size(s), m_font(0), m_cgFont(f)
+ {
+ }
+
+ FontPlatformData(const FontPlatformData&);
+
+ ~FontPlatformData();
+
+ FontPlatformData(WTF::HashTableDeletedValueType) : m_font(hashTableDeletedFontValue()) { }
+ bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); }
+
+ float size() const { return m_size; }
+
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+
+ ATSUFontID m_atsuFontID;
+ float m_size;
+
+ unsigned hash() const
+ {
+ ASSERT(m_font != 0 || m_cgFont == 0);
+ uintptr_t hashCodes[2] = { (uintptr_t)m_font, m_syntheticBold << 1 | m_syntheticOblique };
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+ }
+
+ const FontPlatformData& operator=(const FontPlatformData& f);
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font && m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique &&
+ m_cgFont == other.m_cgFont && m_size == other.m_size && m_atsuFontID == other.m_atsuFontID;
+ }
+
+ NSFont *font() const { return m_font; }
+ void setFont(NSFont *font);
+
+ bool roundsGlyphAdvances() const;
+ bool allowsLigatures() const;
+
+#ifndef BUILDING_ON_TIGER
+ CGFontRef cgFont() const { return m_cgFont.get(); }
+#else
+ CGFontRef cgFont() const { return m_cgFont; }
+#endif
+
+private:
+ static NSFont *hashTableDeletedFontValue() { return reinterpret_cast<NSFont *>(-1); }
+
+ NSFont *m_font;
+#ifndef BUILDING_ON_TIGER
+ RetainPtr<CGFontRef> m_cgFont;
+#else
+ CGFontRef m_cgFont; // It is not necessary to refcount this, since either an NSFont owns it or some CachedFont has it referenced.
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
new file mode 100644
index 0000000..15e573d
--- /dev/null
+++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
@@ -0,0 +1,107 @@
+/*
+ * This file is part of the internal font implementation.
+ *
+ * Copyright (C) 2006-7 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#import "config.h"
+#import "FontPlatformData.h"
+
+#import "WebCoreSystemInterface.h"
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(NSFont *f, bool b , bool o)
+: m_syntheticBold(b), m_syntheticOblique(o), m_font(f)
+{
+ if (f)
+ CFRetain(f);
+ m_size = f ? [f pointSize] : 0.0f;
+#ifndef BUILDING_ON_TIGER
+ m_cgFont = CTFontCopyGraphicsFont(toCTFontRef(f), 0);
+ m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(f), 0);
+#else
+ m_cgFont = wkGetCGFontFromNSFont(f);
+ m_atsuFontID = wkGetNSFontATSUFontId(f);
+#endif
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& f)
+{
+ m_font = f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1) ? static_cast<const NSFont *>(CFRetain(f.m_font)) : f.m_font;
+ m_syntheticBold = f.m_syntheticBold;
+ m_syntheticOblique = f.m_syntheticOblique;
+ m_size = f.m_size;
+ m_cgFont = f.m_cgFont;
+ m_atsuFontID = f.m_atsuFontID;
+}
+
+FontPlatformData:: ~FontPlatformData()
+{
+ if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
+ CFRelease(m_font);
+}
+
+const FontPlatformData& FontPlatformData::operator=(const FontPlatformData& f)
+{
+ m_syntheticBold = f.m_syntheticBold;
+ m_syntheticOblique = f.m_syntheticOblique;
+ m_size = f.m_size;
+ m_cgFont = f.m_cgFont;
+ m_atsuFontID = f.m_atsuFontID;
+ if (m_font == f.m_font)
+ return *this;
+ if (f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1))
+ CFRetain(f.m_font);
+ if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
+ CFRelease(m_font);
+ m_font = f.m_font;
+ return *this;
+}
+
+void FontPlatformData::setFont(NSFont *font)
+{
+ if (m_font == font)
+ return;
+ if (font)
+ CFRetain(font);
+ if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
+ CFRelease(m_font);
+ m_font = font;
+ m_size = font ? [font pointSize] : 0.0f;
+#ifndef BUILDING_ON_TIGER
+ m_cgFont = CTFontCopyGraphicsFont(toCTFontRef(font), 0);
+ m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(font), 0);
+#else
+ m_cgFont = wkGetCGFontFromNSFont(font);
+ m_atsuFontID = wkGetNSFontATSUFontId(font);
+#endif
+}
+
+bool FontPlatformData::roundsGlyphAdvances() const
+{
+ return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
+}
+
+bool FontPlatformData::allowsLigatures() const
+{
+ return ![[m_font coveredCharacterSet] characterIsMember:'a'];
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp b/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp
new file mode 100644
index 0000000..143e665
--- /dev/null
+++ b/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include "WebCoreSystemInterface.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ bool haveGlyphs = false;
+
+#ifndef BUILDING_ON_TIGER
+ Vector<CGGlyph, 512> glyphs(bufferLength);
+ wkGetGlyphsForCharacters(fontData->platformData().cgFont(), buffer, glyphs.data(), bufferLength);
+
+ for (unsigned i = 0; i < length; ++i) {
+ if (!glyphs[i])
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyphs[i], fontData);
+ haveGlyphs = true;
+ }
+ }
+#else
+ // Use an array of long so we get good enough alignment.
+ long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)];
+
+ OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector);
+ if (status != noErr)
+ // This should never happen, perhaps indicates a bad font! If it does the
+ // font substitution code will find an alternate font.
+ return false;
+
+ wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector);
+
+ unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
+ if (numGlyphs != length) {
+ // This should never happen, perhaps indicates a bad font?
+ // If it does happen, the font substitution code will find an alternate font.
+ wkClearGlyphVector(&glyphVector);
+ return false;
+ }
+
+ ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector);
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = glyphRecord->glyphID;
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
+ }
+ wkClearGlyphVector(&glyphVector);
+#endif
+
+ return haveGlyphs;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
new file mode 100644
index 0000000..3f9176c
--- /dev/null
+++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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.
+ */
+
+#import "config.h"
+#import "GraphicsContext.h"
+
+#import "../cg/GraphicsContextPlatformPrivateCG.h"
+
+#import "WebCoreSystemInterface.h"
+
+// FIXME: More of this should use CoreGraphics instead of AppKit.
+// FIXME: More of this should move into GraphicsContextCG.cpp.
+
+namespace WebCore {
+
+// NSColor, NSBezierPath, and NSGraphicsContext
+// calls in this file are all exception-safe, so we don't block
+// exceptions for those.
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ int radius = (focusRingWidth() - 1) / 2;
+ int offset = radius + focusRingOffset();
+ CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
+
+ CGMutablePathRef focusRingPath = CGPathCreateMutable();
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+ for (unsigned i = 0; i < rectCount; i++)
+ CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset));
+
+ CGContextRef context = platformContext();
+#ifdef BUILDING_ON_TIGER
+ CGContextBeginTransparencyLayer(context, NULL);
+#endif
+ CGContextBeginPath(context);
+ CGContextAddPath(context, focusRingPath);
+ wkDrawFocusRing(context, colorRef, radius);
+#ifdef BUILDING_ON_TIGER
+ CGContextEndTransparencyLayer(context);
+#endif
+ CGColorRelease(colorRef);
+
+ CGPathRelease(focusRingPath);
+}
+
+#ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp.
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ [[NSGraphicsContext graphicsContextWithGraphicsPort:platformContext() flipped:YES]
+ setCompositingOperation:(NSCompositingOperation)op];
+ [pool drain];
+}
+#endif
+
+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) {
+ usingDot = usingDotForGrammar;
+ patternColor = grammarPatternColor.get();
+ } else {
+ usingDot = usingDotForSpelling;
+ patternColor = spellingPatternColor.get();
+ }
+
+ // Make sure to draw only complete dots.
+ // NOTE: Code here used to shift the underline to the left and increase the width
+ // to make sure everything gets underlined, but that results in drawing out of
+ // bounds (e.g. when at the edge of a view) and could make it appear that the
+ // space between adjacent misspelled words was underlined.
+ if (usingDot) {
+ // allow slightly more considering that the pattern ends with a transparent pixel
+ int widthMod = width % patternWidth;
+ if (patternWidth - widthMod > cMisspellingLinePatternGapWidth)
+ width -= widthMod;
+ }
+
+ // FIXME: This code should not use NSGraphicsContext currentContext
+ // In order to remove this requirement we will need to use CGPattern instead of NSColor
+ // FIXME: This code should not be using wkSetPatternPhaseInUserSpace, as this approach is wrong
+ // for transforms.
+
+ // Draw underline
+ NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
+ CGContextRef context = (CGContextRef)[currentContext graphicsPort];
+ CGContextSaveGState(context);
+
+ [patternColor set];
+
+ wkSetPatternPhaseInUserSpace(context, point);
+
+ NSRectFillUsingOperation(NSMakeRect(point.x(), point.y(), width, patternHeight), NSCompositeSourceOver);
+
+ CGContextRestoreGState(context);
+}
+
+}
diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm
new file mode 100644
index 0000000..63abe59
--- /dev/null
+++ b/WebCore/platform/graphics/mac/IconMac.mm
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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.
+ *
+ */
+
+#import "config.h"
+#import "Icon.h"
+
+#import "GraphicsContext.h"
+#import "LocalCurrentGraphicsContext.h"
+#import "PlatformString.h"
+#import <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+Icon::Icon(NSImage *image)
+ : m_nsImage(image)
+{
+ // Need this because WebCore uses AppKit's flipped coordinate system exclusively.
+ [image setFlipped:YES];
+}
+
+Icon::~Icon()
+{
+}
+
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
+{
+ // Don't pass relative filenames -- we don't want a result that depends on the current directory.
+ // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[]
+ if (filename.isEmpty() || filename[0U] != '/')
+ return 0;
+
+ NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filename];
+ if (!image)
+ return 0;
+
+ return adoptRef(new Icon(image));
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ if (filenames.isEmpty())
+ return 0;
+#ifdef BUILDING_ON_TIGER
+ // FIXME: find a better image to use on Tiger.
+ return createIconForFile(filenames[0]);
+#else
+ NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments];
+ if (!image)
+ return 0;
+
+ return adoptRef(new Icon(image));
+#endif
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (context->paintingDisabled())
+ return;
+
+ LocalCurrentGraphicsContext localCurrentGC(context);
+
+ [m_nsImage.get() drawInRect:rect
+ fromRect:NSMakeRect(0, 0, [m_nsImage.get() size].width, [m_nsImage.get() size].height)
+ operation:NSCompositeSourceOver fraction:1.0f];
+}
+
+}
diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm
new file mode 100644
index 0000000..a0d257b
--- /dev/null
+++ b/WebCore/platform/graphics/mac/ImageMac.mm
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 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 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.
+ */
+
+#import "config.h"
+#import "BitmapImage.h"
+
+#import "FloatRect.h"
+#import "FoundationExtras.h"
+#import "GraphicsContext.h"
+#import "PlatformString.h"
+
+@interface WebCoreBundleFinder : NSObject
+@end
+
+@implementation WebCoreBundleFinder
+@end
+
+namespace WebCore {
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+ if (m_frames.size() != 1)
+ return;
+
+ m_nsImage = 0;
+ m_tiffRep = 0;
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ NSBundle *bundle = [NSBundle bundleForClass:[WebCoreBundleFinder class]];
+ NSString *imagePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"tiff"];
+ NSData *namedImageData = [NSData dataWithContentsOfFile:imagePath];
+ if (namedImageData) {
+ RefPtr<Image> image = BitmapImage::create();
+ image->setData(SharedBuffer::wrapNSData(namedImageData), true);
+ return image.release();
+ }
+
+ // We have reports indicating resource loads are failing, but we don't yet know the root cause(s).
+ // Two theories are bad installs (image files are missing), and too-many-open-files.
+ // See rdar://5607381
+ ASSERT_NOT_REACHED();
+ return Image::nullImage();
+}
+
+CFDataRef BitmapImage::getTIFFRepresentation()
+{
+ if (m_tiffRep)
+ return m_tiffRep.get();
+
+ unsigned numFrames = frameCount();
+
+ // If numFrames is zero, we know for certain this image doesn't have valid data
+ // Even though the call to CGImageDestinationCreateWithData will fail and we'll handle it gracefully,
+ // in certain circumstances that call will spam the console with an error message
+ if (!numFrames)
+ return 0;
+
+ Vector<CGImageRef> images;
+ for (unsigned i = 0; i < numFrames; ++i ) {
+ CGImageRef cgImage = frameAtIndex(i);
+ if (cgImage)
+ images.append(cgImage);
+ }
+
+ unsigned numValidFrames = images.size();
+
+ RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, 0));
+ // FIXME: Use type kCGImageTypeIdentifierTIFF constant once is becomes available in the API
+ CGImageDestinationRef destination = CGImageDestinationCreateWithData(data.get(), CFSTR("public.tiff"), numValidFrames, 0);
+
+ if (!destination)
+ return 0;
+
+ for (unsigned i = 0; i < numValidFrames; ++i)
+ CGImageDestinationAddImage(destination, images[i], 0);
+
+ CGImageDestinationFinalize(destination);
+ CFRelease(destination);
+
+ m_tiffRep = data;
+ return m_tiffRep.get();
+}
+
+NSImage* BitmapImage::getNSImage()
+{
+ if (m_nsImage)
+ return m_nsImage.get();
+
+ CFDataRef data = getTIFFRepresentation();
+ if (!data)
+ return 0;
+
+ m_nsImage.adoptNS([[NSImage alloc] initWithData:(NSData*)data]);
+ return m_nsImage.get();
+}
+
+}
diff --git a/WebCore/platform/graphics/mac/IntPointMac.mm b/WebCore/platform/graphics/mac/IntPointMac.mm
new file mode 100644
index 0000000..7a2e730
--- /dev/null
+++ b/WebCore/platform/graphics/mac/IntPointMac.mm
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "IntPoint.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+IntPoint::IntPoint(const NSPoint& p) : m_x(static_cast<int>(p.x)), m_y(static_cast<int>(p.y))
+{
+}
+
+IntPoint::operator NSPoint() const
+{
+ return NSMakePoint(m_x, m_y);
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/graphics/mac/IntRectMac.mm b/WebCore/platform/graphics/mac/IntRectMac.mm
new file mode 100644
index 0000000..738618a
--- /dev/null
+++ b/WebCore/platform/graphics/mac/IntRectMac.mm
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, 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 "IntRect.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+IntRect::operator NSRect() const
+{
+ return NSMakeRect(x(), y(), width(), height());
+}
+
+IntRect enclosingIntRect(const NSRect& rect)
+{
+ int l = static_cast<int>(floorf(rect.origin.x));
+ int t = static_cast<int>(floorf(rect.origin.y));
+ int r = static_cast<int>(ceilf(NSMaxX(rect)));
+ int b = static_cast<int>(ceilf(NSMaxY(rect)));
+ return IntRect(l, t, r - l, b - t);
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/graphics/mac/IntSizeMac.mm b/WebCore/platform/graphics/mac/IntSizeMac.mm
new file mode 100644
index 0000000..c7dcd88
--- /dev/null
+++ b/WebCore/platform/graphics/mac/IntSizeMac.mm
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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 "IntSize.h"
+
+namespace WebCore {
+
+#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
+
+IntSize::IntSize(const NSSize& s) : m_width(static_cast<int>(s.width)), m_height(static_cast<int>(s.height))
+{
+}
+
+IntSize::operator NSSize() const
+{
+ return NSMakeSize(m_width, m_height);
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
new file mode 100644
index 0000000..3f18ab4
--- /dev/null
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayerPrivateQTKit_h
+#define MediaPlayerPrivateQTKit_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+#include "Timer.h"
+#include <wtf/RetainPtr.h>
+
+#ifdef __OBJC__
+#import <QTKit/QTTime.h>
+@class QTMovie;
+@class QTMovieView;
+@class QTVideoRendererWebKitOnly;
+@class WebCoreMovieObserver;
+#else
+class QTMovie;
+class QTMovieView;
+class QTTime;
+class QTVideoRendererWebKitOnly;
+class WebCoreMovieObserver;
+#endif
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+namespace WebCore {
+
+class MediaPlayerPrivate : 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 time);
+
+ void setRate(float);
+ void setVolume(float);
+
+ int dataRate() const;
+
+ MediaPlayer::NetworkState networkState() const { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ float maxTimeBuffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ bool totalBytesKnown() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setRect(const IntRect& r);
+
+ void loadStateChanged();
+ void rateChanged();
+ void sizeChanged();
+ void timeChanged();
+ void didEnd();
+
+ void repaint();
+ void paint(GraphicsContext*, const IntRect&);
+
+ static void getSupportedTypes(HashSet<String>& types);
+ static bool isAvailable();
+
+private:
+ void createQTMovie(const String& url);
+ void setUpVideoRendering();
+ void tearDownVideoRendering();
+ void createQTMovieView();
+ void detachQTMovieView();
+ void createQTVideoRenderer();
+ void destroyQTVideoRenderer();
+ QTTime createQTTime(float time) const;
+
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivate>*);
+ void endPointTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded() const;
+ void startEndPointTimerIfNeeded();
+ void disableUnsupportedTracks(unsigned& enabledTrackCount);
+
+ MediaPlayer* m_player;
+ RetainPtr<QTMovie> m_qtMovie;
+ RetainPtr<QTMovieView> m_qtMovieView;
+ RetainPtr<QTVideoRendererWebKitOnly> m_qtVideoRenderer;
+ RetainPtr<WebCoreMovieObserver> m_objcObserver;
+ float m_seekTo;
+ float m_endTime;
+ Timer<MediaPlayerPrivate> m_seekTimer;
+ Timer<MediaPlayerPrivate> m_endPointTimer;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+ bool m_visible;
+#if DRAW_FRAME_RATE
+ int m_frameCountWhilePlaying;
+ double m_timeStartedPlaying;
+ double m_timeStoppedPlaying;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
new file mode 100644
index 0000000..0ec56d6
--- /dev/null
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (C) 2007, 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 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.
+ */
+
+#import "config.h"
+
+#if ENABLE(VIDEO)
+
+#import "MediaPlayerPrivateQTKit.h"
+
+#import "BlockExceptions.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>
+
+#if DRAW_FRAME_RATE
+#import "Font.h"
+#import "Frame.h"
+#import "Document.h"
+#import "RenderObject.h"
+#import "RenderStyle.h"
+#endif
+
+#ifdef BUILDING_ON_TIGER
+static IMP method_setImplementation(Method m, IMP imp)
+{
+ IMP result = m->method_imp;
+ m->method_imp = imp;
+ return result;
+}
+#endif
+
+SOFT_LINK_FRAMEWORK(QTKit)
+
+SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (timeValue, timeScale))
+
+SOFT_LINK_CLASS(QTKit, QTMovie)
+SOFT_LINK_CLASS(QTKit, QTMovieView)
+
+SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeSound, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieAskUnresolvedDataRefsAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieDataSizeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieDidEndNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieHasVideoAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieNaturalSizeAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMoviePreventExternalURLLinksAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieSizeDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieTimeDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieTimeScaleAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieURLAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTMovieVolumeDidChangeNotification, NSString *)
+SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *)
+SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, NSString *)
+
+#define QTMovie getQTMovieClass()
+#define QTMovieView getQTMovieViewClass()
+
+#define QTMediaTypeAttribute getQTMediaTypeAttribute()
+#define QTMediaTypeBase getQTMediaTypeBase()
+#define QTMediaTypeSound getQTMediaTypeSound()
+#define QTMediaTypeText getQTMediaTypeText()
+#define QTMediaTypeVideo getQTMediaTypeVideo()
+#define QTMovieAskUnresolvedDataRefsAttribute getQTMovieAskUnresolvedDataRefsAttribute()
+#define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute()
+#define QTMovieDidEndNotification getQTMovieDidEndNotification()
+#define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute()
+#define QTMovieIsActiveAttribute getQTMovieIsActiveAttribute()
+#define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute()
+#define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification()
+#define QTMovieNaturalSizeAttribute getQTMovieNaturalSizeAttribute()
+#define QTMoviePreventExternalURLLinksAttribute getQTMoviePreventExternalURLLinksAttribute()
+#define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification()
+#define QTMovieSizeDidChangeNotification getQTMovieSizeDidChangeNotification()
+#define QTMovieTimeDidChangeNotification getQTMovieTimeDidChangeNotification()
+#define QTMovieTimeScaleAttribute getQTMovieTimeScaleAttribute()
+#define QTMovieURLAttribute getQTMovieURLAttribute()
+#define QTMovieVolumeDidChangeNotification getQTMovieVolumeDidChangeNotification()
+#define QTSecurityPolicyNoCrossSiteAttribute getQTSecurityPolicyNoCrossSiteAttribute()
+#define QTVideoRendererWebKitOnlyNewImageAvailableNotification getQTVideoRendererWebKitOnlyNewImageAvailableNotification()
+
+// Older versions of the QTKit header don't have these constants.
+#if !defined QTKIT_VERSION_MAX_ALLOWED || QTKIT_VERSION_MAX_ALLOWED <= QTKIT_VERSION_7_0
+enum {
+ QTMovieLoadStateError = -1L,
+ QTMovieLoadStateLoaded = 2000L,
+ QTMovieLoadStatePlayable = 10000L,
+ QTMovieLoadStatePlaythroughOK = 20000L,
+ QTMovieLoadStateComplete = 100000L
+};
+#endif
+
+using namespace WebCore;
+using namespace std;
+
+@interface WebCoreMovieObserver : NSObject
+{
+ MediaPlayerPrivate* m_callback;
+ NSView* m_view;
+ BOOL m_delayCallbacks;
+}
+-(id)initWithCallback:(MediaPlayerPrivate*)callback;
+-(void)disconnect;
+-(void)setView:(NSView*)view;
+-(void)repaint;
+-(void)setDelayCallbacks:(BOOL)shouldDelay;
+-(void)loadStateChanged:(NSNotification *)notification;
+-(void)rateChanged:(NSNotification *)notification;
+-(void)sizeChanged:(NSNotification *)notification;
+-(void)timeChanged:(NSNotification *)notification;
+-(void)didEnd:(NSNotification *)notification;
+@end
+
+@protocol WebKitVideoRenderingDetails
+-(void)setMovie:(id)movie;
+-(void)drawInRect:(NSRect)rect;
+@end
+
+namespace WebCore {
+
+static const float endPointTimerInterval = 0.020f;
+
+#ifdef BUILDING_ON_TIGER
+static const long minimumQuickTimeVersion = 0x07300000; // 7.3
+#endif
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_objcObserver(AdoptNS, [[WebCoreMovieObserver alloc] initWithCallback:this])
+ , m_seekTo(-1)
+ , m_endTime(numeric_limits<float>::infinity())
+ , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
+ , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::DataUnavailable)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+ , m_visible(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
+{
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+ tearDownVideoRendering();
+
+ [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
+ [m_objcObserver.get() disconnect];
+}
+
+void MediaPlayerPrivate::createQTMovie(const String& url)
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
+
+ if (m_qtMovie) {
+ destroyQTVideoRenderer();
+ m_qtMovie = 0;
+ }
+
+ // Disable streaming support for now, <rdar://problem/5693967>
+ if (protocolIs(url, "rtsp"))
+ return;
+
+ NSURL *cocoaURL = KURL(url);
+ NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ cocoaURL, QTMovieURLAttribute,
+ [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute,
+ [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute,
+ [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute,
+ [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", // FIXME: Use defined attribute when required version of QT supports this attribute
+ nil];
+
+ NSError* error = nil;
+ m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]);
+
+ // FIXME: Find a proper way to detect streaming content.
+ m_isStreaming = protocolIs(url, "rtsp");
+
+ if (!m_qtMovie)
+ return;
+
+ [m_qtMovie.get() setVolume:m_player->volume()];
+
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(loadStateChanged:)
+ name:QTMovieLoadStateDidChangeNotification
+ object:m_qtMovie.get()];
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(rateChanged:)
+ name:QTMovieRateDidChangeNotification
+ object:m_qtMovie.get()];
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(sizeChanged:)
+ name:QTMovieSizeDidChangeNotification
+ object:m_qtMovie.get()];
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(timeChanged:)
+ name:QTMovieTimeDidChangeNotification
+ object:m_qtMovie.get()];
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(didEnd:)
+ name:QTMovieDidEndNotification
+ object:m_qtMovie.get()];
+}
+
+static void mainThreadSetNeedsDisplay(id self, SEL _cmd)
+{
+ id movieView = [self superview];
+ ASSERT(!movieView || [movieView isKindOfClass:[QTMovieView class]]);
+ if (!movieView || ![movieView isKindOfClass:[QTMovieView class]])
+ return;
+
+ WebCoreMovieObserver* delegate = [movieView delegate];
+ ASSERT(!delegate || [delegate isKindOfClass:[WebCoreMovieObserver class]]);
+ if (!delegate || ![delegate isKindOfClass:[WebCoreMovieObserver class]])
+ return;
+
+ [delegate repaint];
+}
+
+static Class QTVideoRendererClass()
+{
+ static Class QTVideoRendererWebKitOnlyClass = NSClassFromString(@"QTVideoRendererWebKitOnly");
+ return QTVideoRendererWebKitOnlyClass;
+}
+
+void MediaPlayerPrivate::createQTMovieView()
+{
+ detachQTMovieView();
+
+ static bool addedCustomMethods = false;
+ if (!addedCustomMethods) {
+ Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView");
+ ASSERT(QTMovieContentViewClass);
+
+ Method mainThreadSetNeedsDisplayMethod = class_getInstanceMethod(QTMovieContentViewClass, @selector(_mainThreadSetNeedsDisplay));
+ ASSERT(mainThreadSetNeedsDisplayMethod);
+
+ method_setImplementation(mainThreadSetNeedsDisplayMethod, reinterpret_cast<IMP>(mainThreadSetNeedsDisplay));
+ addedCustomMethods = true;
+ }
+
+ m_qtMovieView.adoptNS([[QTMovieView alloc] init]);
+ setRect(m_player->rect());
+ NSView* parentView = m_player->m_frameView->documentView();
+ [parentView addSubview:m_qtMovieView.get()];
+#ifdef BUILDING_ON_TIGER
+ // setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy
+ [m_qtMovieView.get() performSelector:@selector(setDelegate:) withObject:m_objcObserver.get()];
+#else
+ [m_qtMovieView.get() setDelegate:m_objcObserver.get()];
+#endif
+ [m_objcObserver.get() setView:m_qtMovieView.get()];
+ [m_qtMovieView.get() setMovie:m_qtMovie.get()];
+ [m_qtMovieView.get() setControllerVisible:NO];
+ [m_qtMovieView.get() setPreservesAspectRatio:NO];
+ // the area not covered by video should be transparent
+ [m_qtMovieView.get() setFillColor:[NSColor clearColor]];
+
+ // If we're in a media document, allow QTMovieView to render in its default mode;
+ // otherwise tell it to draw synchronously.
+ // Note that we expect mainThreadSetNeedsDisplay to be invoked only when synchronous drawing is requested.
+ if (!m_player->inMediaDocument())
+ wkQTMovieViewSetDrawSynchronously(m_qtMovieView.get(), YES);
+}
+
+void MediaPlayerPrivate::detachQTMovieView()
+{
+ if (m_qtMovieView) {
+ [m_objcObserver.get() setView:nil];
+#ifdef BUILDING_ON_TIGER
+ // setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy
+ [m_qtMovieView.get() performSelector:@selector(setDelegate:) withObject:nil];
+#else
+ [m_qtMovieView.get() setDelegate:nil];
+#endif
+ [m_qtMovieView.get() removeFromSuperview];
+ m_qtMovieView = nil;
+ }
+}
+
+void MediaPlayerPrivate::createQTVideoRenderer()
+{
+ destroyQTVideoRenderer();
+
+ m_qtVideoRenderer.adoptNS([[QTVideoRendererClass() alloc] init]);
+ if (!m_qtVideoRenderer)
+ return;
+
+ // associate our movie with our instance of QTVideoRendererWebKitOnly
+ [(id<WebKitVideoRenderingDetails>)m_qtVideoRenderer.get() setMovie:m_qtMovie.get()];
+
+ // listen to QTVideoRendererWebKitOnly's QTVideoRendererWebKitOnlyNewImageDidBecomeAvailableNotification
+ [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get()
+ selector:@selector(newImageAvailable:)
+ name:QTVideoRendererWebKitOnlyNewImageAvailableNotification
+ object:m_qtVideoRenderer.get()];
+}
+
+void MediaPlayerPrivate::destroyQTVideoRenderer()
+{
+ if (!m_qtVideoRenderer)
+ return;
+
+ // stop observing the renderer's notifications before we toss it
+ [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()
+ name:QTVideoRendererWebKitOnlyNewImageAvailableNotification
+ object:m_qtVideoRenderer.get()];
+
+ // disassociate our movie from our instance of QTVideoRendererWebKitOnly
+ [(id<WebKitVideoRenderingDetails>)m_qtVideoRenderer.get() setMovie:nil];
+
+ m_qtVideoRenderer = nil;
+}
+
+void MediaPlayerPrivate::setUpVideoRendering()
+{
+ if (!m_player->m_frameView || !m_qtMovie)
+ return;
+
+ if (m_player->inMediaDocument() || !QTVideoRendererClass() )
+ createQTMovieView();
+ else
+ createQTVideoRenderer();
+}
+
+void MediaPlayerPrivate::tearDownVideoRendering()
+{
+ if (m_qtMovieView)
+ detachQTMovieView();
+ else
+ destroyQTVideoRenderer();
+}
+
+QTTime MediaPlayerPrivate::createQTTime(float time) const
+{
+ if (!m_qtMovie)
+ return QTMakeTime(0, 600);
+ long timeScale = [[m_qtMovie.get() attributeForKey:QTMovieTimeScaleAttribute] longValue];
+ return QTMakeTime(time * timeScale, timeScale);
+}
+
+void MediaPlayerPrivate::load(const String& url)
+{
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::DataUnavailable) {
+ m_readyState = MediaPlayer::DataUnavailable;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+ m_endPointTimer.stop();
+
+ [m_objcObserver.get() setDelayCallbacks:YES];
+
+ createQTMovie(url);
+
+ [m_objcObserver.get() loadStateChanged:nil];
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+void MediaPlayerPrivate::play()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ [m_qtMovie.get() setRate:m_player->rate()];
+ [m_objcObserver.get() setDelayCallbacks:NO];
+ startEndPointTimerIfNeeded();
+}
+
+void MediaPlayerPrivate::pause()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
+#endif
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ [m_qtMovie.get() stop];
+ [m_objcObserver.get() setDelayCallbacks:NO];
+ m_endPointTimer.stop();
+}
+
+float MediaPlayerPrivate::duration() const
+{
+ if (!m_qtMovie)
+ return 0;
+ QTTime time = [m_qtMovie.get() duration];
+ if (time.flags == kQTTimeIsIndefinite)
+ return numeric_limits<float>::infinity();
+ return static_cast<float>(time.timeValue) / time.timeScale;
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ if (!m_qtMovie)
+ return 0;
+ QTTime time = [m_qtMovie.get() currentTime];
+ return min(static_cast<float>(time.timeValue) / time.timeScale, m_endTime);
+}
+
+void MediaPlayerPrivate::seek(float time)
+{
+ cancelSeek();
+
+ if (!m_qtMovie)
+ return;
+
+ if (time > duration())
+ time = duration();
+
+ m_seekTo = time;
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else
+ m_seekTimer.start(0, 0.5f);
+}
+
+void MediaPlayerPrivate::doSeek()
+{
+ QTTime qttime = createQTTime(m_seekTo);
+ // setCurrentTime generates several event callbacks, update afterwards
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ float oldRate = [m_qtMovie.get() rate];
+ [m_qtMovie.get() setRate:0];
+ [m_qtMovie.get() setCurrentTime:qttime];
+ float timeAfterSeek = currentTime();
+ // restore playback only if not at end, othewise QTMovie will loop
+ if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ [m_qtMovie.get() setRate:oldRate];
+ cancelSeek();
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+void MediaPlayerPrivate::cancelSeek()
+{
+ m_seekTo = -1;
+ m_seekTimer.stop();
+}
+
+void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ return;
+ }
+
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else {
+ MediaPlayer::NetworkState state = networkState();
+ if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ }
+ }
+}
+
+void MediaPlayerPrivate::setEndTime(float time)
+{
+ m_endTime = time;
+ startEndPointTimerIfNeeded();
+}
+
+void MediaPlayerPrivate::startEndPointTimerIfNeeded()
+{
+ if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())
+ m_endPointTimer.startRepeating(endPointTimerInterval);
+}
+
+void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ float time = currentTime();
+
+ // just do end for now
+ if (time >= m_endTime) {
+ pause();
+ didEnd();
+ }
+}
+
+bool MediaPlayerPrivate::paused() const
+{
+ if (!m_qtMovie)
+ return true;
+ return [m_qtMovie.get() rate] == 0;
+}
+
+bool MediaPlayerPrivate::seeking() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_seekTo >= 0;
+}
+
+IntSize MediaPlayerPrivate::naturalSize() const
+{
+ if (!m_qtMovie)
+ return IntSize();
+ return IntSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]);
+}
+
+bool MediaPlayerPrivate::hasVideo() const
+{
+ if (!m_qtMovie)
+ return false;
+ return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue];
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ if (!m_qtMovie)
+ return;
+ [m_qtMovie.get() setVolume:volume];
+}
+
+void MediaPlayerPrivate::setRate(float rate)
+{
+ if (!m_qtMovie)
+ return;
+ if (!paused())
+ [m_qtMovie.get() setRate:rate];
+}
+
+int MediaPlayerPrivate::dataRate() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return wkQTMovieDataRate(m_qtMovie.get());
+}
+
+
+float MediaPlayerPrivate::maxTimeBuffered() const
+{
+ // rtsp streams are not buffered
+ return m_isStreaming ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeSeekable() const
+{
+ // infinite duration means live stream
+ return isinf(duration()) ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeLoaded() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return wkQTMovieMaxTimeLoaded(m_qtMovie.get());
+}
+
+unsigned MediaPlayerPrivate::bytesLoaded() const
+{
+ float dur = duration();
+ if (!dur)
+ return 0;
+ return totalBytes() * maxTimeLoaded() / dur;
+}
+
+bool MediaPlayerPrivate::totalBytesKnown() const
+{
+ return totalBytes() > 0;
+}
+
+unsigned MediaPlayerPrivate::totalBytes() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return [[m_qtMovie.get() attributeForKey:QTMovieDataSizeAttribute] intValue];
+}
+
+void MediaPlayerPrivate::cancelLoad()
+{
+ // FIXME: Is there a better way to check for this?
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ tearDownVideoRendering();
+ m_qtMovie = nil;
+
+ updateStates();
+}
+
+void MediaPlayerPrivate::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError);
+
+ if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) {
+ unsigned enabledTrackCount;
+ disableUnsupportedTracks(enabledTrackCount);
+ // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
+ if (!enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+ }
+
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
+ if (m_networkState < MediaPlayer::Loaded)
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
+ m_networkState = MediaPlayer::LoadedFirstFrame;
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
+ m_networkState = MediaPlayer::LoadedFirstFrame;
+ // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ if (m_networkState < MediaPlayer::LoadedMetaData)
+ m_networkState = MediaPlayer::LoadedMetaData;
+ m_readyState = MediaPlayer::DataUnavailable;
+ } else if (loadState > QTMovieLoadStateError) {
+ if (m_networkState < MediaPlayer::Loading)
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::DataUnavailable;
+ } else {
+ m_networkState = MediaPlayer::LoadFailed;
+ m_readyState = MediaPlayer::DataUnavailable;
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::DataUnavailable;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+
+ if (loadState >= QTMovieLoadStateLoaded && oldNetworkState < MediaPlayer::LoadedMetaData && m_player->visible())
+ setUpVideoRendering();
+}
+
+void MediaPlayerPrivate::loadStateChanged()
+{
+ updateStates();
+}
+
+void MediaPlayerPrivate::rateChanged()
+{
+ updateStates();
+}
+
+void MediaPlayerPrivate::sizeChanged()
+{
+}
+
+void MediaPlayerPrivate::timeChanged()
+{
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::didEnd()
+{
+ m_endPointTimer.stop();
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
+#endif
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::setRect(const IntRect& r)
+{
+ if (!m_qtMovieView)
+ return;
+
+ if (m_player->inMediaDocument())
+ // We need the QTMovieView to be placed in the proper location for document mode.
+ [m_qtMovieView.get() setFrame:r];
+ else {
+ // We don't really need the QTMovieView in any specific location so let's just get it out of the way
+ // where it won't intercept events or try to bring up the context menu.
+ IntRect farAwayButCorrectSize(r);
+ farAwayButCorrectSize.move(-1000000, -1000000);
+ [m_qtMovieView.get() setFrame:farAwayButCorrectSize];
+ }
+}
+
+void MediaPlayerPrivate::setVisible(bool b)
+{
+ if (m_visible != b) {
+ m_visible = b;
+ if (b) {
+ if (m_networkState >= MediaPlayer::LoadedMetaData)
+ setUpVideoRendering();
+ } else
+ tearDownVideoRendering();
+ }
+}
+
+void MediaPlayerPrivate::repaint()
+{
+#if DRAW_FRAME_RATE
+ if (m_startedPlaying) {
+ m_frameCountWhilePlaying++;
+ // to eliminate preroll costs from our calculation,
+ // our frame rate calculation excludes the first frame drawn after playback starts
+ if (1==m_frameCountWhilePlaying)
+ m_timeStartedPlaying = [NSDate timeIntervalSinceReferenceDate];
+ }
+#endif
+ m_player->repaint();
+}
+
+void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
+{
+ if (context->paintingDisabled())
+ return;
+ NSView *view = m_qtMovieView.get();
+ id qtVideoRenderer = m_qtVideoRenderer.get();
+ if (!view && !qtVideoRenderer)
+ return;
+
+ [m_objcObserver.get() setDelayCallbacks:YES];
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ context->save();
+ context->translate(r.x(), r.y() + r.height());
+ context->scale(FloatSize(1.0f, -1.0f));
+ context->setImageInterpolationQuality(InterpolationLow);
+ IntRect paintRect(IntPoint(0, 0), IntSize(r.width(), r.height()));
+ NSGraphicsContext* newContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context->platformContext() flipped:NO];
+
+ // draw the current video frame
+ if (qtVideoRenderer) {
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:newContext];
+ [(id<WebKitVideoRenderingDetails>)qtVideoRenderer drawInRect:paintRect];
+ [NSGraphicsContext restoreGraphicsState];
+ } else
+ [view displayRectIgnoringOpacity:paintRect inContext:newContext];
+
+#if DRAW_FRAME_RATE
+ // Draw the frame rate only after having played more than 10 frames.
+ if (m_frameCountWhilePlaying > 10) {
+ Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL;
+ Document* document = frame ? frame->document() : NULL;
+ RenderObject* renderer = document ? document->renderer() : NULL;
+ RenderStyle* styleToUse = renderer ? renderer->style() : NULL;
+ if (styleToUse) {
+ double frameRate = (m_frameCountWhilePlaying - 1) / ( m_startedPlaying ? ([NSDate timeIntervalSinceReferenceDate] - m_timeStartedPlaying) :
+ (m_timeStoppedPlaying - m_timeStartedPlaying) );
+ String text = String::format("%1.2f", frameRate);
+ TextRun textRun(text.characters(), text.length());
+ const Color color(255, 0, 0);
+ context->scale(FloatSize(1.0f, -1.0f));
+ context->setFont(styleToUse->font());
+ context->setStrokeColor(color);
+ context->setStrokeStyle(SolidStroke);
+ context->setStrokeThickness(1.0f);
+ context->setFillColor(color);
+ context->drawText(textRun, IntPoint(2, -3));
+ }
+ }
+#endif
+
+ context->restore();
+ END_BLOCK_OBJC_EXCEPTIONS;
+ [m_objcObserver.get() setDelayCallbacks:NO];
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes];
+ int count = [fileTypes count];
+ for (int n = 0; n < count; n++) {
+ CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]);
+ RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL));
+ if (!uti)
+ continue;
+ RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType));
+ if (!mime)
+ continue;
+ types.add(mime.get());
+ }
+}
+
+bool MediaPlayerPrivate::isAvailable()
+{
+#ifdef BUILDING_ON_TIGER
+ SInt32 version;
+ OSErr result;
+ result = Gestalt(gestaltQuickTime, &version);
+ if (result != noErr) {
+ LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
+ return false;
+ }
+ if (version < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", version, minimumQuickTimeVersion);
+ return false;
+ }
+ return true;
+#else
+ // On 10.5 and higher, QuickTime will always be new enough for <video> and <audio> support, so we just check that the framework can be loaded.
+ return QTKitLibrary();
+#endif
+}
+
+void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
+{
+ if (!m_qtMovie) {
+ enabledTrackCount = 0;
+ return;
+ }
+
+ static HashSet<String>* allowedTrackTypes = 0;
+ if (!allowedTrackTypes) {
+ allowedTrackTypes = new HashSet<String>;
+ allowedTrackTypes->add(QTMediaTypeVideo);
+ allowedTrackTypes->add(QTMediaTypeSound);
+ allowedTrackTypes->add(QTMediaTypeText);
+ allowedTrackTypes->add(QTMediaTypeBase);
+ allowedTrackTypes->add("clcp");
+ allowedTrackTypes->add("sbtl");
+ }
+
+ NSArray *tracks = [m_qtMovie.get() tracks];
+
+ unsigned trackCount = [tracks count];
+ enabledTrackCount = trackCount;
+ for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++) {
+ // Grab the track at the current index. If there isn't one there, then
+ // we can move onto the next one.
+ QTTrack *track = [tracks objectAtIndex:trackIndex];
+ if (!track)
+ continue;
+
+ // Check to see if the track is disabled already, we should move along.
+ // We don't need to re-disable it.
+ if (![track isEnabled])
+ continue;
+
+ // Grab the track's media. We're going to check to see if we need to
+ // disable the tracks. They could be unsupported.
+ QTMedia *trackMedia = [track media];
+ if (!trackMedia)
+ continue;
+
+ // Grab the media type for this track.
+ NSString *mediaType = [trackMedia attributeForKey:QTMediaTypeAttribute];
+ if (!mediaType)
+ continue;
+
+ // Test whether the media type is in our white list.
+ if (!allowedTrackTypes->contains(mediaType)) {
+ // If this track type is not allowed, then we need to disable it.
+ [track setEnabled:NO];
+ --enabledTrackCount;
+ }
+
+ // Disable chapter tracks. These are most likely to lead to trouble, as
+ // they will be composited under the video tracks, forcing QT to do extra
+ // work.
+ QTTrack *chapterTrack = [track performSelector:@selector(chapterlist)];
+ if (!chapterTrack)
+ continue;
+
+ // Try to grab the media for the track.
+ QTMedia *chapterMedia = [chapterTrack media];
+ if (!chapterMedia)
+ continue;
+
+ // Grab the media type for this track.
+ id chapterMediaType = [chapterMedia attributeForKey:QTMediaTypeAttribute];
+ if (!chapterMediaType)
+ continue;
+
+ // Check to see if the track is a video track. We don't care about
+ // other non-video tracks.
+ if (![chapterMediaType isEqual:QTMediaTypeVideo])
+ continue;
+
+ // Check to see if the track is already disabled. If it is, we
+ // should move along.
+ if (![chapterTrack isEnabled])
+ continue;
+
+ // Disable the evil, evil track.
+ [chapterTrack setEnabled:NO];
+ --enabledTrackCount;
+ }
+}
+
+}
+
+@implementation WebCoreMovieObserver
+
+- (id)initWithCallback:(MediaPlayerPrivate *)callback
+{
+ m_callback = callback;
+ return [super init];
+}
+
+- (void)disconnect
+{
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+ m_callback = 0;
+}
+
+-(NSMenu*)menuForEventDelegate:(NSEvent*)theEvent
+{
+ // Get the contextual menu from the QTMovieView's superview, the frame view
+ return [[m_view superview] menuForEvent:theEvent];
+}
+
+-(void)setView:(NSView*)view
+{
+ m_view = view;
+}
+
+-(void)repaint
+{
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0.];
+ else if (m_callback)
+ m_callback->repaint();
+}
+
+- (void)loadStateChanged:(NSNotification *)notification
+{
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->loadStateChanged();
+}
+
+- (void)rateChanged:(NSNotification *)notification
+{
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->rateChanged();
+}
+
+- (void)sizeChanged:(NSNotification *)notification
+{
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->sizeChanged();
+}
+
+- (void)timeChanged:(NSNotification *)notification
+{
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->timeChanged();
+}
+
+- (void)didEnd:(NSNotification *)notification
+{
+ if (m_delayCallbacks)
+ [self performSelector:_cmd withObject:nil afterDelay:0];
+ else
+ m_callback->didEnd();
+}
+
+- (void)newImageAvailable:(NSNotification *)notification
+{
+ [self repaint];
+}
+
+- (void)setDelayCallbacks:(BOOL)shouldDelay
+{
+ m_delayCallbacks = shouldDelay;
+}
+
+@end
+
+#endif
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
new file mode 100644
index 0000000..4ee5933
--- /dev/null
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov
+ *
+ * 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.
+ */
+
+#import "config.h"
+#import "SimpleFontData.h"
+
+#import "BlockExceptions.h"
+#import "Color.h"
+#import "FloatRect.h"
+#import "Font.h"
+#import "FontCache.h"
+#import "FontDescription.h"
+#import "SharedBuffer.h"
+#import "WebCoreSystemInterface.h"
+#import <ApplicationServices/ApplicationServices.h>
+#import <float.h>
+#import <unicode/uchar.h>
+#import <wtf/Assertions.h>
+#import <wtf/RetainPtr.h>
+
+@interface NSFont (WebAppKitSecretAPI)
+- (BOOL)_isFakeFixedPitch;
+@end
+
+namespace WebCore {
+
+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)
+{
+ if (!fontData->m_font.cgFont())
+ return false;
+
+#ifdef BUILDING_ON_TIGER
+ ATSUStyle fontStyle;
+ if (ATSUCreateStyle(&fontStyle) != noErr)
+ return false;
+
+ ATSUFontID fontId = fontData->m_font.m_atsuFontID;
+ if (!fontId) {
+ ATSUDisposeStyle(fontStyle);
+ return false;
+ }
+
+ ATSUAttributeTag tag = kATSUFontTag;
+ ByteCount size = sizeof(ATSUFontID);
+ ATSUFontID *valueArray[1] = {&fontId};
+ OSStatus status = ATSUSetAttributes(fontStyle, 1, &tag, &size, (void* const*)valueArray);
+ if (status != noErr) {
+ ATSUDisposeStyle(fontStyle);
+ return false;
+ }
+
+ if (wkGetATSStyleGroup(fontStyle, &fontData->m_styleGroup) != noErr) {
+ ATSUDisposeStyle(fontStyle);
+ return false;
+ }
+
+ ATSUDisposeStyle(fontStyle);
+#endif
+
+ return true;
+}
+
+static NSString *webFallbackFontFamily(void)
+{
+ static RetainPtr<NSString> webFallbackFontFamily = nil;
+ if (!webFallbackFontFamily)
+ webFallbackFontFamily = [[NSFont systemFontOfSize:16.0f] familyName];
+ return webFallbackFontFamily.get();
+}
+
+#if !ERROR_DISABLED
+#ifdef __LP64__
+static NSString* pathFromFont(NSFont*)
+{
+ // FMGetATSFontRefFromFont is not available in 64-bit. As pathFromFont is only used for debugging
+ // purposes, returning nil is acceptable.
+ return nil;
+}
+#else
+static NSString* pathFromFont(NSFont *font)
+{
+#ifndef BUILDING_ON_TIGER
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(CTFontGetPlatformFont(toCTFontRef(font), 0));
+#else
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(wkGetNSFontATSUFontId(font));
+#endif
+ FSRef fileRef;
+
+#ifndef BUILDING_ON_TIGER
+ OSStatus status = ATSFontGetFileReference(atsFont, &fileRef);
+ if (status != noErr)
+ return nil;
+#else
+ FSSpec oFile;
+ OSStatus status = ATSFontGetFileSpecification(atsFont, &oFile);
+ if (status != noErr)
+ return nil;
+
+ status = FSpMakeFSRef(&oFile, &fileRef);
+ if (status != noErr)
+ return nil;
+#endif
+
+ UInt8 filePathBuffer[PATH_MAX];
+ status = FSRefMakePath(&fileRef, filePathBuffer, PATH_MAX);
+ if (status == noErr)
+ return [NSString stringWithUTF8String:(const char*)filePathBuffer];
+
+ return nil;
+}
+#endif // __LP64__
+#endif // !ERROR_DISABLED
+
+void SimpleFontData::platformInit()
+{
+#ifdef BUILDING_ON_TIGER
+ m_styleGroup = 0;
+#endif
+#if USE(ATSUI)
+ m_ATSUStyleInitialized = false;
+ m_ATSUMirrors = false;
+ m_checkedShapesArabic = false;
+ m_shapesArabic = false;
+#endif
+
+ m_syntheticBoldOffset = m_font.m_syntheticBold ? 1.0f : 0.f;
+
+ bool failedSetup = false;
+ if (!initFontData(this)) {
+ // Ack! Something very bad happened, like a corrupt font.
+ // Try looking for an alternate 'base' font for this renderer.
+
+ // Special case hack to use "Times New Roman" in place of "Times".
+ // "Times RO" is a common font whose family name is "Times".
+ // It overrides the normal "Times" family font.
+ // It also appears to have a corrupt regular variant.
+ NSString *fallbackFontFamily;
+ if ([[m_font.font() familyName] isEqual:@"Times"])
+ fallbackFontFamily = @"Times New Roman";
+ else
+ fallbackFontFamily = webFallbackFontFamily();
+
+ // Try setting up the alternate font.
+ // This is a last ditch effort to use a substitute font when something has gone wrong.
+#if !ERROR_DISABLED
+ RetainPtr<NSFont> initialFont = m_font.font();
+#endif
+ if (m_font.font())
+ m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:fallbackFontFamily]);
+ else
+ m_font.setFont([NSFont fontWithName:fallbackFontFamily size:m_font.size()]);
+#if !ERROR_DISABLED
+ NSString *filePath = pathFromFont(initialFont.get());
+ if (!filePath)
+ filePath = @"not known";
+#endif
+ if (!initFontData(this)) {
+ if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
+ // OK, couldn't setup Times New Roman as an alternate to Times, fallback
+ // on the system font. If this fails we have no alternative left.
+ m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:webFallbackFontFamily()]);
+ if (!initFontData(this)) {
+ // We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
+ LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath);
+ failedSetup = true;
+ }
+ } else {
+ // We tried the requested font and the system font. No joy. We have to give up.
+ LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath);
+ failedSetup = true;
+ }
+ }
+
+ // Report the problem.
+ LOG_ERROR("Corrupt font detected, using %@ in place of %@ located at \"%@\".",
+ [m_font.font() familyName], [initialFont.get() familyName], filePath);
+ }
+
+ // If all else fails, try to set up using the system font.
+ // This is probably because Times and Times New Roman are both unavailable.
+ if (failedSetup) {
+ m_font.setFont([NSFont systemFontOfSize:[m_font.font() pointSize]]);
+ LOG_ERROR("failed to set up font, using system font %s", m_font.font());
+ initFontData(this);
+ }
+
+ int iAscent;
+ int iDescent;
+ int iLineGap;
+#ifdef BUILDING_ON_TIGER
+ wkGetFontMetrics(m_font.cgFont(), &iAscent, &iDescent, &iLineGap, &m_unitsPerEm);
+#else
+ iAscent = CGFontGetAscent(m_font.cgFont());
+ iDescent = CGFontGetDescent(m_font.cgFont());
+ iLineGap = CGFontGetLeading(m_font.cgFont());
+ m_unitsPerEm = CGFontGetUnitsPerEm(m_font.cgFont());
+#endif
+
+ float pointSize = m_font.m_size;
+ float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize;
+ float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize;
+ float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize;
+
+ // We need to adjust Times, Helvetica, and Courier to closely match the
+ // vertical metrics of their Microsoft counterparts that are the de facto
+ // web standard. The AppKit adjustment of 20% is too big and is
+ // incorrectly added to line spacing, so we use a 15% adjustment instead
+ // and add it to the ascent.
+ NSString *familyName = [m_font.font() familyName];
+ if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"])
+ fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f);
+ else if ([familyName isEqualToString:@"Geeza Pro"]) {
+ // Geeza Pro has glyphs that draw slightly above the ascent or far below the descent. Adjust
+ // those vertical metrics to better match reality, so that diacritics at the bottom of one line
+ // do not overlap diacritics at the top of the next line.
+ fAscent *= 1.08f;
+ fDescent *= 2.f;
+ }
+
+ m_ascent = lroundf(fAscent);
+ m_descent = lroundf(fDescent);
+ m_lineGap = lroundf(fLineGap);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ // Hack Hiragino line metrics to allow room for marked text underlines.
+ // <rdar://problem/5386183>
+ if (m_descent < 3 && m_lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) {
+ m_lineGap -= 3 - m_descent;
+ m_descent = 3;
+ }
+
+ // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
+ // Unfortunately, NSFont will round this for us so we don't quite get the right value.
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+ NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
+ if (xGlyph) {
+ NSRect xBox = [m_font.font() boundingRectForGlyph:xGlyph];
+ // Use the maximum of either width or height because "x" is nearly square
+ // and web pages that foolishly use this metric for width will be laid out
+ // poorly if we return an accurate height. Classic case is Times 13 point,
+ // which has an "x" that is 7x6 pixels.
+ m_xHeight = MAX(NSMaxX(xBox), NSMaxY(xBox));
+ } else
+ m_xHeight = [m_font.font() xHeight];
+}
+
+void SimpleFontData::platformDestroy()
+{
+#ifdef BUILDING_ON_TIGER
+ if (m_styleGroup)
+ wkReleaseStyleGroup(m_styleGroup);
+#endif
+#if USE(ATSUI)
+ if (m_ATSUStyleInitialized)
+ ATSUDisposeStyle(m_ATSUStyle);
+#endif
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ if (isCustomFont()) {
+ FontPlatformData smallCapsFontData(m_font);
+ smallCapsFontData.m_size = smallCapsFontData.m_size * smallCapsFontSizeMultiplier;
+ m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false);
+ } else {
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ float size = [m_font.font() pointSize] * smallCapsFontSizeMultiplier;
+ FontPlatformData smallCapsFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toSize:size]);
+
+ // AppKit resets the type information (screen/printer) when you convert a font to a different size.
+ // We have to fix up the font that we're handed back.
+ smallCapsFont.setFont(fontDescription.usePrinterFont() ? [smallCapsFont.font() printerFont] : [smallCapsFont.font() screenFont]);
+
+ if (smallCapsFont.font()) {
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_font.font()];
+
+ if (m_font.m_syntheticBold)
+ fontTraits |= NSBoldFontMask;
+ if (m_font.m_syntheticOblique)
+ fontTraits |= NSItalicFontMask;
+
+ NSFontTraitMask smallCapsFontTraits = [fontManager traitsOfFont:smallCapsFont.font()];
+ smallCapsFont.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(smallCapsFontTraits & NSBoldFontMask);
+ smallCapsFont.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(smallCapsFontTraits & NSItalicFontMask);
+
+ m_smallCapsFontData = FontCache::getCachedFontData(&smallCapsFont);
+ }
+ END_BLOCK_OBJC_EXCEPTIONS;
+ }
+ }
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:(UniChar*)characters length:length freeWhenDone:NO];
+ NSCharacterSet *set = [[m_font.font() coveredCharacterSet] invertedSet];
+ bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound;
+ [string release];
+ return result;
+}
+
+void SimpleFontData::determinePitch()
+{
+ NSFont* f = m_font.font();
+ // Special case Osaka-Mono.
+ // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixed pitch.
+ // Note that the AppKit does not report Osaka-Mono as fixed pitch.
+
+ // Special case MS-PGothic.
+ // According to <rdar://problem/4032938>, we should not treat MS-PGothic as fixed pitch.
+ // Note that AppKit does report MS-PGothic as fixed pitch.
+
+ // Special case MonotypeCorsiva
+ // According to <rdar://problem/5454704>, we should not treat MonotypeCorsiva as fixed pitch.
+ // Note that AppKit does report MonotypeCorsiva as fixed pitch.
+
+ NSString *name = [f fontName];
+ m_treatAsFixedPitch = ([f isFixedPitch] || [f _isFakeFixedPitch] ||
+ [name caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame) &&
+ [name caseInsensitiveCompare:@"MS-PGothic"] != NSOrderedSame &&
+ [name caseInsensitiveCompare:@"MonotypeCorsiva"] != NSOrderedSame;
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ NSFont* font = m_font.font();
+ float pointSize = m_font.m_size;
+ CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
+ CGSize advance;
+ if (!wkGetGlyphTransformedAdvances(m_font.cgFont(), font, &m, &glyph, &advance)) {
+ LOG_ERROR("Unable to cache glyph widths for %@ %f", [font displayName], pointSize);
+ advance.width = 0;
+ }
+ return advance.width + m_syntheticBoldOffset;
+}
+
+#if USE(ATSUI)
+void SimpleFontData::checkShapesArabic() const
+{
+ ASSERT(!m_checkedShapesArabic);
+
+ m_checkedShapesArabic = true;
+
+ ATSUFontID fontID = m_font.m_atsuFontID;
+ if (!fontID) {
+ LOG_ERROR("unable to get ATSUFontID for %@", m_font.font());
+ return;
+ }
+
+ // This function is called only on fonts that contain Arabic glyphs. Our
+ // heuristic is that if such a font has a glyph metamorphosis table, then
+ // it includes shaping information for Arabic.
+ FourCharCode tables[] = { 'morx', 'mort' };
+ for (unsigned i = 0; i < sizeof(tables) / sizeof(tables[0]); ++i) {
+ ByteCount tableSize;
+ OSStatus status = ATSFontGetTable(fontID, tables[i], 0, 0, 0, &tableSize);
+ if (status == noErr) {
+ m_shapesArabic = true;
+ return;
+ }
+
+ if (status != kATSInvalidFontTableAccess)
+ LOG_ERROR("ATSFontGetTable failed (%d)", status);
+ }
+}
+#endif
+
+#if USE(CORE_TEXT)
+CTFontRef SimpleFontData::getCTFont() const
+{
+ if (getNSFont())
+ return toCTFontRef(getNSFont());
+ if (!m_CTFont)
+ m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_font.cgFont(), m_font.size(), NULL, NULL));
+ return m_CTFont.get();
+}
+
+CFDictionaryRef SimpleFontData::getCFStringAttributes() const
+{
+ if (m_CFStringAttributes)
+ return m_CFStringAttributes.get();
+
+ static const float kerningAdjustmentValue = 0;
+ static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue);
+
+ static const int ligaturesNotAllowedValue = 0;
+ static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue);
+
+ static const int ligaturesAllowedValue = 1;
+ static CFNumberRef ligaturesAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesAllowedValue);
+
+ static const void* attributeKeys[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName };
+ const void* attributeValues[] = { getCTFont(), kerningAdjustment, platformData().allowsLigatures() ? ligaturesAllowed : ligaturesNotAllowed };
+
+ m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, attributeKeys, attributeValues, sizeof(attributeKeys) / sizeof(*attributeKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+
+ return m_CFStringAttributes.get();
+}
+
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/qt/AffineTransformQt.cpp b/WebCore/platform/graphics/qt/AffineTransformQt.cpp
new file mode 100644
index 0000000..2793043
--- /dev/null
+++ b/WebCore/platform/graphics/qt/AffineTransformQt.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+
+#include "IntRect.h"
+#include "FloatRect.h"
+
+namespace WebCore {
+
+AffineTransform::AffineTransform()
+ : m_transform()
+{
+}
+
+AffineTransform::AffineTransform(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)
+ : m_transform(matrix)
+{
+}
+
+void AffineTransform::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
+{
+ qreal tx2, ty2;
+ m_transform.map(qreal(x), qreal(y), &tx2, &ty2);
+ *x2 = tx2;
+ *y2 = ty2;
+}
+
+IntRect AffineTransform::mapRect(const IntRect& rect) const
+{
+ return m_transform.mapRect(rect);
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect& rect) const
+{
+ return m_transform.mapRect(rect);
+}
+
+bool AffineTransform::isIdentity() const
+{
+ return m_transform.isIdentity();
+}
+
+double AffineTransform::a() const
+{
+ return m_transform.m11();
+}
+
+void AffineTransform::setA(double a)
+{
+ m_transform.setMatrix(a, b(), c(), d(), e(), f());
+}
+
+double AffineTransform::b() const
+{
+ return m_transform.m12();
+}
+
+void AffineTransform::setB(double b)
+{
+ m_transform.setMatrix(a(), b, c(), d(), e(), f());
+}
+
+double AffineTransform::c() const
+{
+ return m_transform.m21();
+}
+
+void AffineTransform::setC(double c)
+{
+ m_transform.setMatrix(a(), b(), c, d(), e(), f());
+}
+
+double AffineTransform::d() const
+{
+ return m_transform.m22();
+}
+
+void AffineTransform::setD(double d)
+{
+ m_transform.setMatrix(a(), b(), c(), d, e(), f());
+}
+
+double AffineTransform::e() const
+{
+ return m_transform.dx();
+}
+
+void AffineTransform::setE(double e)
+{
+ m_transform.setMatrix(a(), b(), c(), d(), e, f());
+}
+
+double AffineTransform::f() const
+{
+ return m_transform.dy();
+}
+
+void AffineTransform::setF(double f)
+{
+ m_transform.setMatrix(a(), b(), c(), d(), e(), f);
+}
+
+void AffineTransform::reset()
+{
+ m_transform.reset();
+}
+
+AffineTransform& AffineTransform::scale(double sx, double sy)
+{
+ m_transform.scale(sx, sy);
+ return *this;
+}
+
+AffineTransform& AffineTransform::rotate(double d)
+{
+ m_transform.rotate(d);
+ return *this;
+}
+
+AffineTransform& AffineTransform::translate(double tx, double ty)
+{
+ m_transform.translate(tx, ty);
+ return *this;
+}
+
+AffineTransform& AffineTransform::shear(double sx, double sy)
+{
+ m_transform.shear(sx, sy);
+ return *this;
+}
+
+double AffineTransform::det() const
+{
+ return m_transform.det();
+}
+
+AffineTransform AffineTransform::inverse() const
+{
+ if(!isInvertible())
+ return AffineTransform();
+
+ return m_transform.inverted();
+}
+
+AffineTransform::operator QMatrix() const
+{
+ return m_transform;
+}
+
+bool AffineTransform::operator==(const AffineTransform& other) const
+{
+ return m_transform == other.m_transform;
+}
+
+AffineTransform& AffineTransform::operator*=(const AffineTransform& other)
+{
+ m_transform *= other.m_transform;
+ return *this;
+}
+
+AffineTransform AffineTransform::operator*(const AffineTransform& other)
+{
+ return m_transform * other.m_transform;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/ColorQt.cpp b/WebCore/platform/graphics/qt/ColorQt.cpp
new file mode 100644
index 0000000..5d16740
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ColorQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * 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"
+
+#include <QColor>
+
+namespace WebCore {
+
+Color::Color(const QColor& c)
+ : m_color(makeRGBA(c.red(), c.green(), c.blue(), c.alpha()))
+{
+ m_valid = c.isValid();
+}
+
+Color::operator QColor() const
+{
+ return QColor(red(), green(), blue(), alpha());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/FloatPointQt.cpp b/WebCore/platform/graphics/qt/FloatPointQt.cpp
new file mode 100644
index 0000000..82093d8
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FloatPointQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * 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 "FloatPoint.h"
+
+#include <QPointF>
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const QPointF& p)
+ : m_x(p.x())
+ , m_y(p.y())
+{
+}
+
+FloatPoint::operator QPointF() const
+{
+ return QPointF(m_x, m_y);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/FloatRectQt.cpp b/WebCore/platform/graphics/qt/FloatRectQt.cpp
new file mode 100644
index 0000000..1c918e3
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FloatRectQt.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * 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 "FloatRect.h"
+
+#include <QRectF>
+
+namespace WebCore {
+
+FloatRect::FloatRect(const QRectF& r)
+ : m_location(r.topLeft())
+ , m_size(r.width()
+ , r.height())
+{
+}
+
+FloatRect::operator QRectF() const
+{
+ return QRectF(x(), y(), width(), height());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp
new file mode 100644
index 0000000..be31d96
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+
+ 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 "FontCache.h"
+#include "FontDescription.h"
+#include "Font.h"
+
+namespace WebCore {
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+}
+
+FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&)
+{
+ return 0;
+}
+
+void FontCache::addClient(FontSelector*)
+{
+}
+
+void FontCache::removeClient(FontSelector*)
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..8fc3ea0
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+
+ 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 "FontCustomPlatformData.h"
+
+#include "FontPlatformData.h"
+#include "SharedBuffer.h"
+#include <QFontDatabase>
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ QFontDatabase::removeApplicationFont(handle);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
+{
+ FontPlatformData result;
+ result.handle = handle;
+ return result;
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ int id = QFontDatabase::addApplicationFontFromData(QByteArray(buffer->data(), buffer->size()));
+ if (id == -1)
+ return 0;
+ FontCustomPlatformData *data = new FontCustomPlatformData;
+ data->handle = id;
+ return data;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/WebCore/platform/graphics/qt/FontCustomPlatformData.h
new file mode 100644
index 0000000..da5159d
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+
+ 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.
+*/
+#ifndef FontCustomPlatformData_h_
+#define FontCustomPlatformData_h_
+
+#include "FontRenderingMode.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+class FontPlatformData;
+
+struct FontCustomPlatformData : Noncopyable {
+ ~FontCustomPlatformData();
+
+ int handle; // for use with QFontDatabase::addApplicationFont/removeApplicationFont
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+} // namespace WebCore
+
+#endif // FontCustomPlatformData_h_
diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h
new file mode 100644
index 0000000..e4363be
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontPlatformData.h
@@ -0,0 +1,37 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+
+ 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.
+*/
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+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;
+};
+
+} // namespace WebCore
+
+#endif // FontPlatformData_h
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
new file mode 100644
index 0000000..e2ef605
--- /dev/null
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -0,0 +1,706 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 "FontSelector.h"
+
+#include "GraphicsContext.h"
+#include <QTextLayout>
+#include <QPainter>
+#include <QFontMetrics>
+#include <QFontInfo>
+#include <qalgorithms.h>
+#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;
+}
+
+
+static QString qstring(const TextRun& run)
+{
+ QString string((QChar *)run.characters(), run.length());
+ QChar *uc = string.data();
+ for (int i = 0; i < string.length(); ++i) {
+ if (Font::treatAsSpace(uc[i].unicode()))
+ uc[i] = 0x20;
+ else if (Font::treatAsZeroWidthSpace(uc[i].unicode()))
+ uc[i] = 0x200c;
+ }
+ return string;
+}
+
+
+static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
+{
+ int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
+ if (style.padding())
+ flags |= Qt::TextJustificationForced;
+ layout->setFlags(flags);
+ layout->beginLayout();
+ QTextLine line = layout->createLine();
+ line.setLineWidth(INT_MAX/256);
+ if (style.padding())
+ line.setLineWidth(line.naturalTextWidth() + style.padding());
+ layout->endLayout();
+ return line;
+}
+
+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));
+
+ QString string = qstring(run);
+
+ // text shadow
+ IntSize shadowSize;
+ int shadowBlur;
+ Color shadowColor;
+ bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor);
+
+ if (from > 0 || to < run.length()) {
+ QTextLayout layout(string, m_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);
+ int ascent = fm.ascent();
+ QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height());
+
+ if (hasShadow) {
+ // TODO: when blur support is added, the clip will need to account
+ // for the blur radius
+ qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
+ if (shadowSize.width() > 0)
+ dx2 = shadowSize.width();
+ else
+ dx1 = -shadowSize.width();
+ if (shadowSize.height() > 0)
+ dy2 = shadowSize.height();
+ else
+ dy1 = -shadowSize.height();
+ // expand the clip rect to include the text shadow as well
+ clip.adjust(dx1, dx2, dy1, dy2);
+ }
+ p->save();
+ p->setClipRect(clip.toRect());
+ QPointF pt(point.x(), point.y() - ascent);
+ if (hasShadow) {
+ p->save();
+ p->setPen(QColor(shadowColor));
+ p->translate(shadowSize.width(), shadowSize.height());
+ line.draw(p, pt);
+ p->restore();
+ }
+ line.draw(p, pt);
+ p->restore();
+ return;
+ }
+
+ p->setFont(m_font);
+
+ QPointF pt(point.x(), point.y());
+ int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
+ if (hasShadow) {
+ // TODO: text shadow blur support
+ p->save();
+ p->setPen(QColor(shadowColor));
+ p->translate(shadowSize.width(), shadowSize.height());
+ p->drawText(pt, string, flags, run.padding());
+ p->restore();
+ }
+ p->drawText(pt, string, flags, run.padding());
+}
+
+int Font::width(const TextRun& run) const
+{
+ if (!run.length())
+ return 0;
+ QString string = qstring(run);
+ QTextLayout layout(string, m_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)
+ if (treatAsSpace(run[0]))
+ w -= m_wordSpacing;
+
+ 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
+{
+ QString string = qstring(run);
+ QTextLayout layout(string, m_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
+{
+ QString string = qstring(run);
+ QTextLayout layout(string, m_font);
+ QTextLine line = setupLayout(&layout, run);
+
+ float x1 = line.cursorToX(from);
+ float x2 = line.cursorToX(to);
+ if (x2 < x1)
+ qSwap(x1, x2);
+
+ 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
+{
+ charsConsumed = run.length();
+ glyphName = "";
+ return width(run);
+}
+
+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/GlyphPageTreeNodeQt.cpp b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
new file mode 100644
index 0000000..d32cc63
--- /dev/null
+++ b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
@@ -0,0 +1,31 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+
+ 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 "GlyphPageTreeNode.h"
+
+namespace WebCore {
+
+void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData)
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp
new file mode 100644
index 0000000..f414efa
--- /dev/null
+++ b/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "Gradient.h"
+
+#include "CSSParser.h"
+#include "NotImplemented.h"
+
+#include <QGradient>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ delete m_gradient;
+ m_gradient = 0;
+}
+
+QGradient* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ if (m_radial)
+ m_gradient = new QRadialGradient(m_p1.x(), m_p1.y(), m_r1, m_p0.x(), m_p0.y());
+ else
+ m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());
+
+ QColor stopColor;
+ Vector<ColorStop>::iterator stopIterator = m_stops.begin();
+ qreal lastStop;
+ const qreal lastStopDiff = 0.0000001;
+ while (stopIterator != m_stops.end()) {
+ stopColor.setRgbF(stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
+ if (qFuzzyCompare(lastStop, qreal(stopIterator->stop)))
+ lastStop = stopIterator->stop + lastStopDiff;
+ else
+ lastStop = stopIterator->stop;
+ if (m_radial && m_r0)
+ lastStop = m_r0 / m_r1 + lastStop * (1.0f - m_r0 / m_r1);
+ m_gradient->setColorAt(lastStop, stopColor);
+ ++stopIterator;
+ }
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ notImplemented();
+}
+
+} //namespace
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
new file mode 100644
index 0000000..600d77c
--- /dev/null
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -0,0 +1,1146 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ *
+ * 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"
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+#endif
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "FloatConversion.h"
+#include "Font.h"
+#include "GraphicsContext.h"
+#include "GraphicsContextPrivate.h"
+#include "ImageBuffer.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "Pen.h"
+#include "NotImplemented.h"
+
+#include <QDebug>
+#include <QGradient>
+#include <QPainter>
+#include <QPaintDevice>
+#include <QPaintEngine>
+#include <QPainterPath>
+#include <QPixmap>
+#include <QPolygonF>
+#include <QStack>
+#include <QVector>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op)
+{
+ switch (op) {
+ case CompositeClear:
+ return QPainter::CompositionMode_Clear;
+ case CompositeCopy:
+ return QPainter::CompositionMode_Source;
+ case CompositeSourceOver:
+ return QPainter::CompositionMode_SourceOver;
+ case CompositeSourceIn:
+ return QPainter::CompositionMode_SourceIn;
+ case CompositeSourceOut:
+ return QPainter::CompositionMode_SourceOut;
+ case CompositeSourceAtop:
+ return QPainter::CompositionMode_SourceAtop;
+ case CompositeDestinationOver:
+ return QPainter::CompositionMode_DestinationOver;
+ case CompositeDestinationIn:
+ return QPainter::CompositionMode_DestinationIn;
+ case CompositeDestinationOut:
+ return QPainter::CompositionMode_DestinationOut;
+ case CompositeDestinationAtop:
+ return QPainter::CompositionMode_DestinationAtop;
+ case CompositeXOR:
+ return QPainter::CompositionMode_Xor;
+ case CompositePlusDarker:
+ return QPainter::CompositionMode_SourceOver;
+ case CompositeHighlight:
+ return QPainter::CompositionMode_SourceOver;
+ case CompositePlusLighter:
+ return QPainter::CompositionMode_SourceOver;
+ }
+
+ return QPainter::CompositionMode_SourceOver;
+}
+
+static inline Qt::PenCapStyle toQtLineCap(LineCap lc)
+{
+ switch (lc) {
+ case ButtCap:
+ return Qt::FlatCap;
+ case RoundCap:
+ return Qt::RoundCap;
+ case SquareCap:
+ return Qt::SquareCap;
+ }
+
+ return Qt::FlatCap;
+}
+
+static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj)
+{
+ switch (lj) {
+ case MiterJoin:
+ return Qt::SvgMiterJoin;
+ case RoundJoin:
+ return Qt::RoundJoin;
+ case BevelJoin:
+ return Qt::BevelJoin;
+ }
+
+ return Qt::MiterJoin;
+}
+
+static Qt::PenStyle toQPenStyle(StrokeStyle style)
+{
+ switch (style) {
+ case NoStroke:
+ return Qt::NoPen;
+ break;
+ case SolidStroke:
+ return Qt::SolidLine;
+ break;
+ case DottedStroke:
+ return Qt::DotLine;
+ break;
+ case DashedStroke:
+ return Qt::DashLine;
+ break;
+ }
+ qWarning("couldn't recognize the pen style");
+ return Qt::NoPen;
+}
+
+static inline QGradient applySpreadMethod(QGradient gradient, GradientSpreadMethod spreadMethod)
+{
+ switch (spreadMethod) {
+ case SpreadMethodPad:
+ gradient.setSpread(QGradient::PadSpread);
+ break;
+ case SpreadMethodReflect:
+ gradient.setSpread(QGradient::ReflectSpread);
+ break;
+ case SpreadMethodRepeat:
+ gradient.setSpread(QGradient::RepeatSpread);
+ break;
+ }
+ return gradient;
+}
+
+struct TransparencyLayer
+{
+ TransparencyLayer(const QPainter* p, const QRect &rect)
+ : pixmap(rect.width(), rect.height())
+ {
+ offset = rect.topLeft();
+ pixmap.fill(Qt::transparent);
+ painter.begin(&pixmap);
+ painter.setRenderHint(QPainter::Antialiasing, p->testRenderHint(QPainter::Antialiasing));
+ painter.translate(-offset);
+ painter.setPen(p->pen());
+ painter.setBrush(p->brush());
+ painter.setTransform(p->transform(), true);
+ painter.setOpacity(p->opacity());
+ painter.setFont(p->font());
+ if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ painter.setCompositionMode(p->compositionMode());
+ painter.setClipPath(p->clipPath());
+ }
+
+ TransparencyLayer()
+ {
+ }
+
+ QPixmap pixmap;
+ QPoint offset;
+ QPainter painter;
+ qreal opacity;
+private:
+ TransparencyLayer(const TransparencyLayer &) {}
+ TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
+};
+
+class GraphicsContextPlatformPrivate
+{
+public:
+ GraphicsContextPlatformPrivate(QPainter* painter);
+ ~GraphicsContextPlatformPrivate();
+
+ inline QPainter* p()
+ {
+ if (layers.isEmpty()) {
+ if (redirect)
+ return redirect;
+
+ return painter;
+ } else
+ return &layers.top()->painter;
+ }
+
+ bool antiAliasingForRectsAndLines;
+
+ QStack<TransparencyLayer *> layers;
+ QPainter* redirect;
+
+ QBrush solidColor;
+
+ // Only used by SVG for now.
+ QPainterPath currentPath;
+
+private:
+ QPainter* painter;
+};
+
+
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p)
+{
+ painter = p;
+ redirect = 0;
+
+ solidColor = QBrush(Qt::black);
+
+ if (painter) {
+ // use the default the QPainter was constructed with
+ antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
+ // FIXME: Maybe only enable in SVG mode?
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ } else {
+ antiAliasingForRectsAndLines = false;
+ }
+}
+
+GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
+{
+}
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(context))
+{
+ setPaintingDisabled(!context);
+ if (context) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor());
+ setPlatformStrokeColor(strokeColor());
+ }
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ while(!m_data->layers.isEmpty())
+ endTransparencyLayer();
+
+ destroyGraphicsContextPrivate(m_common);
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ return m_data->p();
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ return platformContext()->combinedMatrix();
+}
+
+void GraphicsContext::savePlatformState()
+{
+ m_data->p()->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ m_data->p()->restore();
+}
+
+/* FIXME: DISABLED WHILE MERGING BACK FROM UNITY
+void GraphicsContext::drawTextShadow(const TextRun& run, const IntPoint& point, const FontStyle& style)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->shadow.isNull())
+ return;
+
+ TextShadow* shadow = &m_data->shadow;
+
+ if (shadow->blur <= 0) {
+ Pen p = pen();
+ setPen(shadow->color);
+ font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y));
+ setPen(p);
+ } else {
+ const int thickness = shadow->blur;
+ // FIXME: OPTIMIZE: limit the area to only the actually painted area + 2*thickness
+ const int w = m_data->p()->device()->width();
+ const int h = m_data->p()->device()->height();
+ const QRgb color = qRgb(255, 255, 255);
+ const QRgb bgColor = qRgb(0, 0, 0);
+ QImage image(QSize(w, h), QImage::Format_ARGB32);
+ image.fill(bgColor);
+ QPainter p;
+
+ Pen curPen = pen();
+ p.begin(&image);
+ setPen(color);
+ m_data->redirect = &p;
+ font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y));
+ m_data->redirect = 0;
+ p.end();
+ setPen(curPen);
+
+ int md = thickness * thickness; // max-dist^2
+
+ // blur map/precalculated shadow-decay
+ float* bmap = (float*) alloca(sizeof(float) * (md + 1));
+ for (int n = 0; n <= md; n++) {
+ float f;
+ f = n / (float) (md + 1);
+ f = 1.0 - f * f;
+ bmap[n] = f;
+ }
+
+ float factor = 0.0; // maximal potential opacity-sum
+ for (int n = -thickness; n <= thickness; n++) {
+ for (int m = -thickness; m <= thickness; m++) {
+ int d = n * n + m * m;
+ if (d <= md)
+ factor += bmap[d];
+ }
+ }
+
+ // alpha map
+ float* amap = (float*) alloca(sizeof(float) * (h * w));
+ memset(amap, 0, h * w * (sizeof(float)));
+
+ for (int j = thickness; j<h-thickness; j++) {
+ for (int i = thickness; i<w-thickness; i++) {
+ QRgb col = image.pixel(i,j);
+ if (col == bgColor)
+ continue;
+
+ float g = qAlpha(col);
+ g = g / 255;
+
+ for (int n = -thickness; n <= thickness; n++) {
+ for (int m = -thickness; m <= thickness; m++) {
+ int d = n * n + m * m;
+ if (d > md)
+ continue;
+
+ float f = bmap[d];
+ amap[(i + m) + (j + n) * w] += (g * f);
+ }
+ }
+ }
+ }
+
+ QImage res(QSize(w,h),QImage::Format_ARGB32);
+ int r = shadow->color.red();
+ int g = shadow->color.green();
+ int b = shadow->color.blue();
+ int a1 = shadow->color.alpha();
+
+ // arbitratry factor adjustment to make shadows more solid.
+ factor = 1.333 / factor;
+
+ for (int j = 0; j < h; j++) {
+ for (int i = 0; i < w; i++) {
+ int a = (int) (amap[i + j * w] * factor * a1);
+ if (a > 255)
+ a = 255;
+
+ res.setPixel(i,j, qRgba(r, g, b, a));
+ }
+ }
+
+ m_data->p()->drawImage(0, 0, res, 0, 0, -1, -1, Qt::DiffuseAlphaDither | Qt::ColorOnly | Qt::PreferDither);
+ }
+}
+*/
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+
+ p->drawRect(rect);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+// FIXME: Now that this is refactored, it should be shared by all contexts.
+static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth,
+ const StrokeStyle& penStyle)
+{
+ // 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.
+ if (penStyle == DottedStroke || penStyle == DashedStroke) {
+ if (p1.x() == p2.x()) {
+ p1.setY(p1.y() + strokeWidth);
+ p2.setY(p2.y() - strokeWidth);
+ } else {
+ p1.setX(p1.x() + strokeWidth);
+ p2.setX(p2.x() - strokeWidth);
+ }
+ }
+
+ if (((int) strokeWidth) % 2) {
+ if (p1.x() == p2.x()) {
+ // We're a vertical line. Adjust our x.
+ p1.setX(p1.x() + 0.5);
+ p2.setX(p2.x() + 0.5);
+ } else {
+ // We're a horizontal line. Adjust our y.
+ p1.setY(p1.y() + 0.5);
+ p2.setY(p2.y() + 0.5);
+ }
+ }
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+
+ QPainter *p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+ adjustLineToPixelBoundaries(p1, p2, strokeThickness(), strokeStyle());
+
+ IntSize shadowSize;
+ int shadowBlur;
+ Color shadowColor;
+ if (textDrawingMode() == cTextFill && getShadow(shadowSize, shadowBlur, shadowColor)) {
+ p->save();
+ p->translate(shadowSize.width(), shadowSize.height());
+ p->setPen(QColor(shadowColor));
+ p->drawLine(p1, p2);
+ p->restore();
+ }
+
+ p->drawLine(p1, p2);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->drawEllipse(rect);
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha())
+ return;
+
+ QPainter *p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+
+ p->drawArc(rect, startAngle * 16, angleSpan * 16);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ QPolygonF polygon(npoints);
+
+ for (size_t i = 0; i < npoints; i++)
+ polygon[i] = points[i];
+
+ QPainter *p = m_data->p();
+ p->save();
+ p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
+ p->drawConvexPolygon(polygon);
+ p->restore();
+}
+
+void GraphicsContext::fillPath()
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QPainterPath path = m_data->currentPath;
+
+ switch (m_common->state.fillColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ p->fillPath(path, p->brush());
+ break;
+ case PatternColorSpace:
+ p->fillPath(path, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM())));
+ break;
+ case GradientColorSpace:
+ QGradient* gradient = m_common->state.fillGradient.get()->platformGradient();
+ *gradient = applySpreadMethod(*gradient, spreadMethod());
+ p->fillPath(path, QBrush(*gradient));
+ break;
+ }
+}
+
+void GraphicsContext::strokePath()
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QPen pen = p->pen();
+ QPainterPath path = m_data->currentPath;
+
+ switch (m_common->state.strokeColorSpace) {
+ case SolidColorSpace:
+ if (strokeColor().alpha())
+ p->strokePath(path, pen);
+ break;
+ case PatternColorSpace: {
+ pen.setBrush(QBrush(m_common->state.strokePattern.get()->createPlatformPattern(getCTM())));
+ p->setPen(pen);
+ p->strokePath(path, pen);
+ break;
+ }
+ case GradientColorSpace: {
+ QGradient* gradient = m_common->state.strokeGradient.get()->platformGradient();
+ *gradient = applySpreadMethod(*gradient, spreadMethod());
+ pen.setBrush(QBrush(*gradient));
+ p->setPen(pen);
+ p->strokePath(path, pen);
+ break;
+ }
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+
+ switch (m_common->state.fillColorSpace) {
+ case SolidColorSpace:
+ if (fillColor().alpha())
+ p->fillRect(rect, p->brush());
+ break;
+ case PatternColorSpace:
+ p->fillRect(rect, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM())));
+ break;
+ case GradientColorSpace:
+ p->fillRect(rect, QBrush(*(m_common->state.fillGradient.get()->platformGradient())));
+ break;
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& c)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->solidColor.setColor(QColor(c));
+ m_data->p()->fillRect(rect, m_data->solidColor);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
+{
+ if (paintingDisabled() || !color.alpha())
+ return;
+
+ Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight);
+ m_data->p()->fillPath(*path.platformPath(), QColor(color));
+}
+
+void GraphicsContext::beginPath()
+{
+ m_data->currentPath = QPainterPath();
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ m_data->currentPath = *(path.platformPath());
+}
+
+bool GraphicsContext::inTransparencyLayer() const
+{
+ return !m_data->layers.isEmpty();
+}
+
+PlatformPath* GraphicsContext::currentPath()
+{
+ return &m_data->currentPath;
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ if (p->clipRegion().isEmpty())
+ p->setClipRect(rect);
+ else p->setClipRect(rect, Qt::IntersectClip);
+}
+
+/**
+ * Focus ring handling is not handled here. Qt style in
+ * RenderTheme handles drawing focus on widgets which
+ * need it.
+ */
+Color focusRingColor() { return Color(0, 0, 0); }
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+
+ if (rects.size() == 0)
+ return;
+
+ QPainter *p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+
+ const QPen oldPen = p->pen();
+ const QBrush oldBrush = p->brush();
+
+ QPen nPen = p->pen();
+ nPen.setColor(color);
+ p->setBrush(Qt::NoBrush);
+ nPen.setStyle(Qt::DotLine);
+ p->setPen(nPen);
+#if 0
+ // FIXME How do we do a bounding outline with Qt?
+ QPainterPath path;
+ for (int i = 0; i < rectCount; ++i)
+ path.addRect(QRectF(rects[i]));
+ QPainterPathStroker stroker;
+ QPainterPath newPath = stroker.createStroke(path);
+ p->strokePath(newPath, nPen);
+#else
+ for (int i = 0; i < rectCount; ++i)
+ p->drawRect(QRectF(rects[i]));
+#endif
+ p->setPen(oldPen);
+ p->setBrush(oldBrush);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint endPoint = origin + IntSize(width, 0);
+ drawLine(origin, endPoint);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&,
+ int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ QRectF rect(frect);
+ rect = m_data->p()->deviceMatrix().mapRect(rect);
+
+ QRect result = rect.toRect(); //round it
+ return FloatRect(QRectF(result));
+}
+
+void GraphicsContext::setPlatformShadow(const IntSize& pos, int blur, const Color &color)
+{
+ // Qt doesn't support shadows natively, they are drawn manually in the draw*
+ // functions
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ // Qt doesn't support shadows natively, they are drawn manually in the draw*
+ // functions
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ int x, y, w, h;
+ x = y = 0;
+ QPainter *p = m_data->p();
+ const QPaintDevice *device = p->device();
+ w = device->width();
+ h = device->height();
+
+ QRectF clip = p->clipPath().boundingRect();
+ QRectF deviceClip = p->transform().mapRect(clip);
+ x = int(qBound(qreal(0), deviceClip.x(), (qreal)w));
+ y = int(qBound(qreal(0), deviceClip.y(), (qreal)h));
+ w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2);
+ h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2);
+
+ TransparencyLayer * layer = new TransparencyLayer(m_data->p(), QRect(x, y, w, h));
+
+ layer->opacity = opacity;
+ m_data->layers.push(layer);
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ TransparencyLayer *layer = m_data->layers.pop();
+ layer->painter.end();
+
+ QPainter *p = m_data->p();
+ p->save();
+ p->resetTransform();
+ p->setOpacity(layer->opacity);
+ p->drawPixmap(layer->offset, layer->pixmap);
+ p->restore();
+
+ delete layer;
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QPainter::CompositionMode currentCompositionMode = p->compositionMode();
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+ p->eraseRect(rect);
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(currentCompositionMode);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float width)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainterPath path;
+ path.addRect(rect);
+ setStrokeThickness(width);
+ m_data->currentPath = path;
+
+ strokePath();
+}
+
+void GraphicsContext::setLineCap(LineCap lc)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setCapStyle(toQtLineCap(lc));
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ QPainter* p = m_data->p();
+ QPen pen = p->pen();
+ unsigned dashLength = dashes.size();
+ if (dashLength) {
+ QVector<qreal> pattern;
+ unsigned count = dashLength;
+ if (dashLength % 2)
+ count *= 2;
+
+ for (unsigned i = 0; i < count; i++)
+ pattern.append(dashes[i % dashLength] / narrowPrecisionToFloat(pen.widthF()));
+
+ pen.setDashPattern(pattern);
+ pen.setDashOffset(dashOffset);
+ }
+ p->setPen(pen);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lj)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setJoinStyle(toQtLineJoin(lj));
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setMiterLimit(limit);
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setAlpha(float opacity)
+{
+ if (paintingDisabled())
+ return;
+ QPainter *p = m_data->p();
+ p->setOpacity(opacity);
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->p()->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ m_data->p()->setCompositionMode(toQtCompositionMode(op));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QRectF clipBounds = p->clipPath().boundingRect();
+ QPainterPath clippedOut = *path.platformPath();
+ QPainterPath newClip;
+ newClip.setFillRule(Qt::OddEvenFill);
+ newClip.addRect(clipBounds);
+ newClip.addPath(clippedOut);
+
+ p->setClipPath(newClip, Qt::IntersectClip);
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->translate(x, y);
+}
+
+IntPoint GraphicsContext::origin()
+{
+ if (paintingDisabled())
+ return IntPoint();
+ const QTransform &transform = m_data->p()->transform();
+ return IntPoint(qRound(transform.dx()), qRound(transform.dy()));
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->rotate(180/M_PI*radians);
+}
+
+void GraphicsContext::scale(const FloatSize& s)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->scale(s.width(), s.height());
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QRectF clipBounds = p->clipPath().boundingRect();
+ QPainterPath newClip;
+ newClip.setFillRule(Qt::OddEvenFill);
+ newClip.addRect(clipBounds);
+ newClip.addRect(QRect(rect));
+
+ p->setClipPath(newClip, Qt::IntersectClip);
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter *p = m_data->p();
+ QRectF clipBounds = p->clipPath().boundingRect();
+ QPainterPath newClip;
+ newClip.setFillRule(Qt::OddEvenFill);
+ newClip.addRect(clipBounds);
+ newClip.addEllipse(QRect(rect));
+
+ p->setClipPath(newClip, Qt::IntersectClip);
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
+{
+ notImplemented();
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
+ int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ clip(rect);
+ QPainterPath path;
+
+ // Add outer ellipse
+ path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height()));
+
+ // Add inner ellipse.
+ path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness,
+ rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
+
+ path.setFillRule(Qt::OddEvenFill);
+ m_data->p()->setClipPath(path, Qt::IntersectClip);
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->setMatrix(transform, true);
+}
+
+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())
+ return;
+ QPainter *p = m_data->p();
+ QPen newPen(p->pen());
+ newPen.setColor(color);
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle)
+{
+ if (paintingDisabled())
+ return;
+ QPainter *p = m_data->p();
+ QPen newPen(p->pen());
+ newPen.setStyle(toQPenStyle(strokeStyle));
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+ QPainter *p = m_data->p();
+ QPen newPen(p->pen());
+ newPen.setWidthF(thickness);
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+ m_data->p()->setBrush(QBrush(color));
+}
+
+void GraphicsContext::setUseAntialiasing(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ m_data->p()->setRenderHint(QPainter::Antialiasing, enable);
+}
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+
+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);
+
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = dstRect.width();
+ bitmapInfo.bmiHeader.biHeight = dstRect.height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC displayDC = ::GetDC(0);
+ HDC bitmapDC = ::CreateCompatibleDC(displayDC);
+ ::ReleaseDC(0, displayDC);
+
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend) {
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+ }
+
+ // Make sure we can do world transforms.
+ SetGraphicsMode(bitmapDC, GM_ADVANCED);
+
+ // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -dstRect.x();
+ xform.eDy = -dstRect.y();
+ ::SetWorldTransform(bitmapDC, &xform);
+
+
+ return bitmapDC;
+}
+
+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);
+
+ if (hdc) {
+
+ if (!dstRect.isEmpty()) {
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap, supportAlphaBlend ? QPixmap::PremultipliedAlpha : QPixmap::NoAlpha);
+ m_data->p()->drawPixmap(dstRect, pixmap);
+
+ ::DeleteObject(bitmap);
+ }
+
+ ::DeleteDC(hdc);
+ }
+}
+#endif
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return InterpolationDefault;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp
new file mode 100644
index 0000000..b04668c
--- /dev/null
+++ b/WebCore/platform/graphics/qt/IconQt.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.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.
+ *
+ */
+
+#include "config.h"
+#include "Icon.h"
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qrect.h>
+#include <qglobal.h>
+
+namespace WebCore {
+
+Icon::Icon()
+{
+}
+
+Icon::~Icon()
+{
+}
+
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
+{
+ RefPtr<Icon> i = adoptRef(new Icon);
+ i->m_icon = QIcon(filename);
+ return i.release();
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ //FIXME: Implement this
+ return 0;
+}
+
+void Icon::paint(GraphicsContext* ctx, const IntRect& rect)
+{
+ QPixmap px = m_icon.pixmap(rect.size());
+ QPainter *p = static_cast<QPainter*>(ctx->platformContext());
+ if (p && !px.isNull()) {
+ p->drawPixmap(rect.x(), rect.y(), px);
+ }
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/ImageBufferData.h b/WebCore/platform/graphics/qt/ImageBufferData.h
new file mode 100644
index 0000000..222dabe
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ImageBufferData.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+#include <QPainter>
+#include <QPixmap>
+
+#include "OwnPtr.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ QPixmap m_pixmap;
+ OwnPtr<QPainter> m_painter;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
new file mode 100644
index 0000000..d4ab59f
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "CString.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "NotImplemented.h"
+#include "StillImageQt.h"
+
+#include <QBuffer>
+#include <QImageWriter>
+#include <QPainter>
+#include <QPixmap>
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_pixmap(size)
+{
+ m_pixmap.fill(QColor(Qt::transparent));
+ m_painter.set(new QPainter(&m_pixmap));
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ m_context.set(new GraphicsContext(m_data.m_painter.get()));
+ success = true;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ ASSERT(m_data.m_painter->isActive());
+
+ return m_context.get();
+}
+
+Image* ImageBuffer::image() const
+{
+ if (!m_image) {
+ // It's assumed that if image() is called, the actual rendering to the
+ // GraphicsContext must be done.
+ ASSERT(context());
+ m_image = StillImage::create(m_data.m_pixmap);
+ }
+
+ return m_image.get();
+}
+
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const
+{
+ notImplemented();
+ return 0;
+}
+
+void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&)
+{
+ notImplemented();
+}
+
+// We get a mimeType here but QImageWriter does not support mimetypes but
+// only formats (png, gif, jpeg..., xpm). So assume we get image/ as image
+// mimetypes and then remove the image/ to get the Qt format.
+String ImageBuffer::toDataURL(const String& mimeType) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ if (!mimeType.startsWith("image/"))
+ return "data:,";
+
+ // prepare our target
+ QByteArray data;
+ QBuffer buffer(&data);
+ buffer.open(QBuffer::WriteOnly);
+
+ if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data()))
+ return "data:,";
+
+ buffer.close();
+ return String::format("data:%s;base64,%s", mimeType.utf8().data(), data.toBase64().data());
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
new file mode 100644
index 0000000..e3b00a1
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "ImageDecoderQt.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QBuffer>
+
+#include <QtGui/QImageReader>
+#include <qdebug.h>
+
+namespace {
+ const QImage::Format DesiredFormat = QImage::Format_ARGB32;
+ const bool debugImageDecoderQt = false;
+}
+
+namespace WebCore {
+ImageDecoderQt::ImageData::ImageData(const QImage& image, ImageState imageState, int duration) :
+ m_image(image), m_imageState(imageState), m_duration(duration)
+{
+}
+
+// Context, maintains IODevice on a data buffer.
+class ImageDecoderQt::ReadContext {
+public:
+
+ enum LoadMode {
+ // Load images incrementally. This is still experimental and
+ // will cause the image plugins to report errors.
+ // Also note that as of Qt 4.2.2, the JPEG loader does not return error codes
+ // on "preliminary end of data".
+ LoadIncrementally,
+ // Load images only if all data have been received
+ LoadComplete };
+
+ ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target);
+
+ enum ReadResult { ReadEOF, ReadFailed, ReadPartial, ReadComplete };
+
+ // Append data and read out all images. Returns the result
+ // of the last read operation, so, even if ReadPartial is returned,
+ // a few images might have been read.
+ ReadResult read(bool allDataReceived);
+
+ QImageReader *reader() { return &m_reader; }
+
+private:
+ enum IncrementalReadResult { IncrementalReadFailed, IncrementalReadPartial, IncrementalReadComplete };
+ // Incrementally read an image
+ IncrementalReadResult readImageLines(ImageData &);
+
+ const LoadMode m_loadMode;
+
+ QByteArray m_data;
+ QBuffer m_buffer;
+ QImageReader m_reader;
+
+ ImageList &m_target;
+
+ // Detected data format of the stream
+ enum QImage::Format m_dataFormat;
+ QSize m_size;
+
+};
+
+ImageDecoderQt::ReadContext::ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target)
+ : m_loadMode(loadMode)
+ , m_data(data.data(), data.size())
+ , m_buffer(&m_data)
+ , m_reader(&m_buffer)
+ , m_target(target)
+ , m_dataFormat(QImage::Format_Invalid)
+{
+ m_buffer.open(QIODevice::ReadOnly);
+}
+
+
+ImageDecoderQt::ReadContext::ReadResult
+ ImageDecoderQt::ReadContext::read(bool allDataReceived)
+{
+ // Complete mode: Read only all all data received
+ if (m_loadMode == LoadComplete && !allDataReceived)
+ return ReadPartial;
+
+ // Attempt to read out all images
+ while (true) {
+ if (m_target.empty() || m_target.back().m_imageState == ImageComplete) {
+ // Start a new image.
+ if (!m_reader.canRead())
+ return ReadEOF;
+
+ // Attempt to construct an empty image of the matching size and format
+ // for efficient reading
+ QImage newImage = m_dataFormat != QImage::Format_Invalid ?
+ QImage(m_size,m_dataFormat) : QImage();
+ m_target.push_back(ImageData(newImage));
+ }
+
+ // read chunks
+ switch (readImageLines(m_target.back())) {
+ case IncrementalReadFailed:
+ m_target.pop_back();
+ return ReadFailed;
+ case IncrementalReadPartial:
+ return ReadPartial;
+ case IncrementalReadComplete:
+ m_target.back().m_imageState = ImageComplete;
+ //store for next
+ m_dataFormat = m_target.back().m_image.format();
+ m_size = m_target.back().m_image.size();
+ const bool supportsAnimation = m_reader.supportsAnimation();
+
+ if (debugImageDecoderQt)
+ qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size << " format " << m_dataFormat
+ << " supportsAnimation=" << supportsAnimation ;
+ // No point in readinfg further
+ if (!supportsAnimation)
+ return ReadComplete;
+
+ break;
+ }
+ }
+ return ReadComplete;
+}
+
+
+
+ImageDecoderQt::ReadContext::IncrementalReadResult
+ ImageDecoderQt::ReadContext::readImageLines(ImageData &imageData)
+{
+ // TODO: Implement incremental reading here,
+ // set state to reflect complete header, etc.
+ // For now, we read the whole image.
+
+ const qint64 startPos = m_buffer.pos ();
+ // Oops, failed. Rewind.
+ if (!m_reader.read(&imageData.m_image)) {
+ m_buffer.seek(startPos);
+ const bool gotHeader = imageData.m_image.size().width();
+
+ if (debugImageDecoderQt)
+ qDebug() << "readImageLines(): read() failed: " << m_reader.errorString()
+ << " got header=" << gotHeader;
+ // [Experimental] Did we manage to read the header?
+ if (gotHeader) {
+ imageData.m_imageState = ImageHeaderValid;
+ return IncrementalReadPartial;
+ }
+ return IncrementalReadFailed;
+ }
+ imageData.m_duration = m_reader.nextImageDelay();
+ return IncrementalReadComplete;
+}
+
+
+// ImageDecoderQt
+ImageDecoderQt::ImageDecoderQt( )
+{
+}
+
+ImageDecoderQt::~ImageDecoderQt()
+{
+}
+
+bool ImageDecoderQt::hasFirstImageHeader() const
+{
+ return !m_imageList.empty() && m_imageList[0].m_imageState >= ImageHeaderValid;
+}
+
+void ImageDecoderQt::reset()
+{
+ m_failed = false;
+ m_imageList.clear();
+ m_pixmapCache.clear();
+ m_sizeAvailable = false;
+ m_loopCount = cAnimationNone;
+ m_size = IntSize(-1, -1);
+}
+
+void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived)
+{
+ reset();
+ ReadContext readContext(data, ReadContext::LoadComplete, m_imageList);
+
+ if (debugImageDecoderQt)
+ qDebug() << " setData " << data.size() << " image bytes, complete=" << allDataReceived;
+
+ const ReadContext::ReadResult readResult = readContext.read(allDataReceived);
+
+ if (debugImageDecoderQt)
+ qDebug() << " read returns " << readResult;
+
+ switch ( readResult) {
+ case ReadContext::ReadFailed:
+ m_failed = true;
+ break;
+ case ReadContext::ReadEOF:
+ case ReadContext::ReadPartial:
+ case ReadContext::ReadComplete:
+ // Did we read anything - try to set the size.
+ if (hasFirstImageHeader()) {
+ m_sizeAvailable = true;
+ m_size = m_imageList[0].m_image.size();
+
+ if (readContext.reader()->supportsAnimation()) {
+ if (readContext.reader()->loopCount() != -1)
+ m_loopCount = readContext.reader()->loopCount();
+ else
+ m_loopCount = 0; //loop forever
+ }
+ }
+ break;
+ }
+}
+
+
+bool ImageDecoderQt::isSizeAvailable() const
+{
+ if (debugImageDecoderQt)
+ qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << m_sizeAvailable;
+ return m_sizeAvailable;
+}
+
+int ImageDecoderQt::frameCount() const
+{
+ if (debugImageDecoderQt)
+ qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size();
+ return m_imageList.size();
+}
+
+
+int ImageDecoderQt::repetitionCount() const
+{
+ if (debugImageDecoderQt)
+ qDebug() << " ImageDecoderQt::repetitionCount() returns" << m_loopCount;
+ return m_loopCount;
+}
+
+
+bool ImageDecoderQt::supportsAlpha() const
+{
+ return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel();
+}
+
+int ImageDecoderQt::duration(size_t index) const
+{
+ if (index >= m_imageList.size())
+ return 0;
+ return m_imageList[index].m_duration;
+}
+
+RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
+{
+ Q_ASSERT("use imageAtIndex instead");
+ return 0;
+}
+
+QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const
+{
+ if (debugImageDecoderQt)
+ qDebug() << "ImageDecoderQt::imageAtIndex(" << index << ')';
+
+ if (index >= m_imageList.size())
+ return 0;
+
+ if (!m_pixmapCache.contains(index)) {
+ m_pixmapCache.insert(index,
+ QPixmap::fromImage(m_imageList[index].m_image));
+ }
+ return &m_pixmapCache[index];
+}
+
+void ImageDecoderQt::clearFrame(size_t index)
+{
+ if (m_imageList.size() < (int)index)
+ m_imageList[index].m_image = QImage();
+ m_pixmapCache.take(index);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h
new file mode 100644
index 0000000..3573dd0
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageDecoderQt_h
+#define ImageDecoderQt_h
+
+#include "ImageDecoder.h"
+#include <QtGui/QImage>
+#include <QtGui/QPixmap>
+#include <QtCore/QList>
+#include <QtCore/QHash>
+
+namespace WebCore {
+
+
+class ImageDecoderQt : public ImageDecoder
+{
+ ImageDecoderQt(const ImageDecoderQt&);
+ ImageDecoderQt &operator=(const ImageDecoderQt&);
+public:
+ ImageDecoderQt();
+ ~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;
+
+ void clearFrame(size_t index);
+private:
+ class ReadContext;
+ void reset();
+ bool hasFirstImageHeader() const;
+
+ enum ImageState {
+ // Started image reading
+ ImagePartial,
+ // Header (size / alpha) are known
+ ImageHeaderValid,
+ // Image is complete
+ ImageComplete };
+
+ struct ImageData {
+ ImageData(const QImage& image, ImageState imageState = ImagePartial, int duration=0);
+ QImage m_image;
+ ImageState m_imageState;
+ int m_duration;
+ };
+
+ typedef QList<ImageData> ImageList;
+ ImageList m_imageList;
+ mutable QHash<int, QPixmap> m_pixmapCache;
+ int m_loopCount;
+};
+
+
+
+}
+
+#endif
+
diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp
new file mode 100644
index 0000000..9234c69
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ *
+ * 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 "Image.h"
+
+#include "BitmapImage.h"
+#include "FloatRect.h"
+#include "PlatformString.h"
+#include "GraphicsContext.h"
+#include "AffineTransform.h"
+#include "NotImplemented.h"
+#include "StillImageQt.h"
+#include "qwebsettings.h"
+
+#include <QPixmap>
+#include <QPainter>
+#include <QImage>
+#include <QImageReader>
+#if QT_VERSION >= 0x040300
+#include <QTransform>
+#endif
+
+#include <QDebug>
+
+#include <math.h>
+
+// This function loads resources into WebKit
+static QPixmap loadResourcePixmap(const char *name)
+{
+ QPixmap pixmap;
+ if (qstrcmp(name, "missingImage") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic);
+ else if (qstrcmp(name, "nullPlugin") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic);
+ else if (qstrcmp(name, "urlIcon") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic);
+ else if (qstrcmp(name, "textAreaResizeCorner") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic);
+
+ return pixmap;
+}
+
+namespace WebCore {
+
+void FrameData::clear()
+{
+ 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.
+ }
+}
+
+
+
+// ================================================
+// Image Class
+// ================================================
+
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ return StillImage::create(loadResourcePixmap(name));
+}
+
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
+{
+ notImplemented();
+}
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+// Drawing Routines
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
+ const FloatRect& src, CompositeOperator op)
+{
+ startAnimation();
+
+ QPixmap* image = nativeImageForCurrentFrame();
+ if (!image)
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, dst, solidColor(), op);
+ return;
+ }
+
+ IntSize selfSize = size();
+
+ ctxt->save();
+
+ // Set the compositing operation.
+ ctxt->setCompositeOperation(op);
+
+ QPainter* painter(ctxt->platformContext());
+
+ // Test using example site at
+ // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ painter->drawPixmap(dst, *image, src);
+
+ ctxt->restore();
+}
+
+void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
+{
+ QPixmap* framePixmap = nativeImageForCurrentFrame();
+ if (!framePixmap) // If it's too early we won't have an image yet.
+ return;
+
+ QPixmap pixmap = *framePixmap;
+ QRect tr = QRectF(tileRect).toRect();
+ if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) {
+ pixmap = pixmap.copy(tr);
+ }
+
+ QBrush b(pixmap);
+ b.setMatrix(patternTransform);
+ ctxt->save();
+ ctxt->setCompositeOperation(op);
+ QPainter* p = ctxt->platformContext();
+ p->setBrushOrigin(phase);
+ p->fillRect(destRect, b);
+ ctxt->restore();
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1.
+ m_isSolidColor = false;
+}
+
+}
+
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
new file mode 100644
index 0000000..1d14f9d
--- /dev/null
+++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "ImageSource.h"
+#include "ImageDecoderQt.h"
+#include "SharedBuffer.h"
+
+#include <QBuffer>
+#include <QImage>
+#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)
+{
+}
+
+ImageSource::~ImageSource()
+{
+ delete m_decoder;
+}
+
+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);
+
+ if (!m_decoder)
+ return;
+
+ m_decoder->setData(data->buffer(), 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
+{
+ 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->frameCount();
+}
+
+NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return 0;
+
+ return m_decoder->imageAtIndex(index);
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return 0;
+
+ // Many annoying ads specify a 0 duration to make an image flash as quickly
+ // as possible. We follow WinIE's behavior and use a duration of 100 ms
+ // for any frames that specify a duration of <= 50 ms. See
+ // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for
+ // more.
+ const float duration = m_decoder->duration(index) / 1000.0f;
+ return (duration < 0.051f) ? 0.100f : duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ if (!m_decoder || !m_decoder->supportsAlpha())
+ return false;
+
+ const QPixmap* source = m_decoder->imageAtIndex( index);
+ if (!source)
+ return false;
+
+ return source->hasAlphaChannel();
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ return (m_decoder && m_decoder->imageAtIndex(index) != 0);
+}
+
+void ImageSource::clear()
+{
+ delete m_decoder;
+ m_decoder = 0;
+}
+
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/IntPointQt.cpp b/WebCore/platform/graphics/qt/IntPointQt.cpp
new file mode 100644
index 0000000..f9d336a
--- /dev/null
+++ b/WebCore/platform/graphics/qt/IntPointQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * 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 "IntPoint.h"
+
+#include <QPoint>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const QPoint& p)
+ : m_x(p.x())
+ , m_y(p.y())
+{
+}
+
+IntPoint::operator QPoint() const
+{
+ return QPoint(m_x, m_y);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/IntRectQt.cpp b/WebCore/platform/graphics/qt/IntRectQt.cpp
new file mode 100644
index 0000000..ccc153e
--- /dev/null
+++ b/WebCore/platform/graphics/qt/IntRectQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * 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 "IntRect.h"
+
+#include <QRect>
+
+namespace WebCore {
+
+IntRect::IntRect(const QRect& r)
+ : m_location(r.topLeft())
+ , m_size(r.width(), r.height())
+{
+}
+
+IntRect::operator QRect() const
+{
+ return QRect(x(), y(), width(), height());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/IntSizeQt.cpp b/WebCore/platform/graphics/qt/IntSizeQt.cpp
new file mode 100644
index 0000000..4f2bf35
--- /dev/null
+++ b/WebCore/platform/graphics/qt/IntSizeQt.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * 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 <QSize>
+
+#include "IntSize.h"
+
+namespace WebCore {
+
+IntSize::IntSize(const QSize& r)
+ : m_width(r.width())
+ , m_height(r.height())
+{
+}
+
+IntSize::operator QSize() const
+{
+ return QSize(width(), height());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
new file mode 100644
index 0000000..431e68e
--- /dev/null
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -0,0 +1,533 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 "MediaPlayerPrivatePhonon.h"
+
+#include <limits>
+
+#include "CString.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "Widget.h"
+#include <wtf/HashSet.h>
+
+#include <QDebug>
+#include <QPainter>
+#include <QWidget>
+#include <QMetaEnum>
+#include <QUrl>
+#include <QEvent>
+#include <phonon>
+
+using namespace Phonon;
+
+#define LOG_MEDIAOBJECT() (LOG(Media,"%s", debugMediaObject(this, *m_mediaObject).constData()))
+
+static QByteArray debugMediaObject(WebCore::MediaPlayerPrivate* mediaPlayer, const MediaObject& mediaObject)
+{
+ QByteArray byteArray;
+ QTextStream stream(&byteArray);
+
+ const QMetaObject* metaObj = mediaPlayer->metaObject();
+ QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
+
+ stream << "debugMediaObject -> Phonon::MediaObject(";
+ stream << "State: " << phononStates.valueToKey(mediaObject.state());
+ stream << " | Current time: " << mediaObject.currentTime();
+ stream << " | Remaining time: " << mediaObject.remainingTime();
+ stream << " | Total time: " << mediaObject.totalTime();
+ stream << " | Meta-data: ";
+ QMultiMap<QString, QString> map = mediaObject.metaData();
+ for (QMap<QString, QString>::const_iterator it = map.constBegin();
+ it != map.constEnd(); ++it) {
+ stream << "(" << it.key() << ", " << it.value() << ")";
+ }
+ stream << " | Has video: " << mediaObject.hasVideo();
+ stream << " | Is seekable: " << mediaObject.isSeekable();
+ stream << ")";
+
+ stream.flush();
+
+ return byteArray;
+}
+
+using namespace WTF;
+
+namespace WebCore {
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::DataUnavailable)
+ , m_mediaObject(new MediaObject())
+ , m_videoWidget(new VideoWidget(0))
+ , m_audioOutput(new AudioOutput())
+ , m_isVisible(false)
+{
+ // Hint to Phonon to disable overlay painting
+ m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen);
+
+ createPath(m_mediaObject, m_videoWidget);
+ createPath(m_mediaObject, m_audioOutput);
+
+ // Make sure we get updates for each frame
+ m_videoWidget->installEventFilter(this);
+ foreach(QWidget* widget, qFindChildren<QWidget*>(m_videoWidget)) {
+ widget->installEventFilter(this);
+ }
+
+ connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
+ this, SLOT(stateChanged(Phonon::State, Phonon::State)));
+ 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)));
+ connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int)));
+ connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished()));
+ 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)));
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget");
+ m_videoWidget->close();
+ delete m_videoWidget;
+ m_videoWidget = 0;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting audiooutput");
+ delete m_audioOutput;
+ m_audioOutput = 0;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting mediaobject");
+ delete m_mediaObject;
+ m_mediaObject = 0;
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
+{
+ notImplemented();
+}
+
+bool MediaPlayerPrivate::hasVideo() const
+{
+ bool hasVideo = m_mediaObject->hasVideo();
+ LOG(Media, "MediaPlayerPrivatePhonon::hasVideo() -> %s", hasVideo ? "true" : "false");
+ return hasVideo;
+}
+
+void MediaPlayerPrivate::load(String url)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data());
+
+ // We are now loading
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+
+ // And we don't have any data yet
+ if (m_readyState != MediaPlayer::DataUnavailable) {
+ m_readyState = MediaPlayer::DataUnavailable;
+ m_player->readyStateChanged();
+ }
+
+ m_mediaObject->setCurrentSource(QUrl(url));
+ m_audioOutput->setVolume(m_player->volume());
+ setVisible(m_player->visible());
+}
+
+void MediaPlayerPrivate::cancelLoad()
+{
+ notImplemented();
+}
+
+
+void MediaPlayerPrivate::play()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::play()");
+ m_mediaObject->play();
+}
+
+void MediaPlayerPrivate::pause()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::pause()");
+ m_mediaObject->pause();
+}
+
+
+bool MediaPlayerPrivate::paused() const
+{
+ bool paused = m_mediaObject->state() == Phonon::PausedState;
+ LOG(Media, "MediaPlayerPrivatePhonon::paused() --> %s", paused ? "true" : "false");
+ return paused;
+}
+
+void MediaPlayerPrivate::seek(float position)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::seek(%f)", position);
+
+ if (!m_mediaObject->isSeekable())
+ return;
+
+ if (position > duration())
+ position = duration();
+
+ m_mediaObject->seek(position * 1000.0f);
+}
+
+bool MediaPlayerPrivate::seeking() const
+{
+ return false;
+}
+
+float MediaPlayerPrivate::duration() const
+{
+ if (m_networkState < MediaPlayer::LoadedMetaData)
+ return 0.0f;
+
+ float duration = m_mediaObject->totalTime() / 1000.0f;
+
+ if (duration == 0.0f) // We are streaming
+ duration = std::numeric_limits<float>::infinity();
+
+ LOG(Media, "MediaPlayerPrivatePhonon::duration() --> %f", duration);
+ return duration;
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ float currentTime = m_mediaObject->currentTime() / 1000.0f;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::currentTime() --> %f", currentTime);
+ return currentTime;
+}
+
+void MediaPlayerPrivate::setEndTime(float endTime)
+{
+ notImplemented();
+}
+
+float MediaPlayerPrivate::maxTimeBuffered() const
+{
+ notImplemented();
+ return 0.0f;
+}
+
+float MediaPlayerPrivate::maxTimeSeekable() const
+{
+ notImplemented();
+ return 0.0f;
+}
+
+unsigned MediaPlayerPrivate::bytesLoaded() const
+{
+ notImplemented();
+ return 0;
+}
+
+bool MediaPlayerPrivate::totalBytesKnown() const
+{
+ //notImplemented();
+ return false;
+}
+
+unsigned MediaPlayerPrivate::totalBytes() const
+{
+ //notImplemented();
+ return 0;
+}
+
+void MediaPlayerPrivate::setRate(float)
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::setVolume()");
+ m_audioOutput->setVolume(volume);
+}
+
+void MediaPlayerPrivate::setMuted(bool muted)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::setMuted()");
+ m_audioOutput->setMuted(muted);
+}
+
+
+int MediaPlayerPrivate::dataRate() const
+{
+ // This is not used at the moment
+ return 0;
+}
+
+
+MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::networkState() --> %s", networkStates.valueToKey(m_networkState));
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::readyState() --> %s", readyStates.valueToKey(m_readyState));
+ return m_readyState;
+}
+
+void MediaPlayerPrivate::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ Phonon::State phononState = m_mediaObject->state();
+
+ if (phononState == Phonon::StoppedState) {
+ if (oldNetworkState < MediaPlayer::LoadedMetaData) {
+ m_networkState = MediaPlayer::LoadedMetaData;
+ m_readyState = MediaPlayer::DataUnavailable;
+ m_mediaObject->pause();
+ }
+ } else if (phononState == Phonon::PausedState) {
+ m_networkState = MediaPlayer::LoadedFirstFrame;
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (phononState == Phonon::ErrorState) {
+ if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) {
+ m_networkState = MediaPlayer::LoadFailed;
+ m_readyState = MediaPlayer::DataUnavailable;
+ cancelLoad();
+ } else {
+ m_mediaObject->pause();
+ }
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::DataUnavailable;
+
+ if (m_networkState != oldNetworkState) {
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
+ LOG(Media, "Network state changed from '%s' to '%s'",
+ networkStates.valueToKey(oldNetworkState),
+ networkStates.valueToKey(m_networkState));
+ m_player->networkStateChanged();
+ }
+
+ if (m_readyState != oldReadyState) {
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
+ LOG(Media, "Ready state changed from '%s' to '%s'",
+ readyStates.valueToKey(oldReadyState),
+ readyStates.valueToKey(m_readyState));
+ m_player->readyStateChanged();
+ }
+}
+
+void MediaPlayerPrivate::setVisible(bool visible)
+{
+ m_isVisible = visible;
+ LOG(Media, "MediaPlayerPrivatePhonon::setVisible(%s)", visible ? "true" : "false");
+
+ m_videoWidget->setVisible(m_isVisible);
+}
+
+void MediaPlayerPrivate::setRect(const IntRect& newRect)
+{
+ if (!m_videoWidget)
+ return;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::setRect(%d,%d %dx%d)",
+ newRect.x(), newRect.y(),
+ newRect.width(), newRect.height());
+
+ QRect currentRect = m_videoWidget->rect();
+
+ if (newRect.width() != currentRect.width() || newRect.height() != currentRect.height())
+ 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()) {
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ 0, 0);
+ return IntSize();
+ }
+
+ if (m_networkState < MediaPlayer::LoadedMetaData) {
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ 0, 0);
+ return IntSize();
+ }
+
+ QSize videoSize = m_videoWidget->sizeHint();
+ IntSize naturalSize(videoSize.width(), videoSize.height());
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ naturalSize.width(), naturalSize.height());
+ return naturalSize;
+}
+
+bool MediaPlayerPrivate::eventFilter(QObject* obj, QEvent* event)
+{
+ if (event->type() == QEvent::Paint)
+ 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())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ QPainter* painter = graphicsContect->platformContext();
+
+ painter->fillRect(rect, Qt::black);
+
+ m_videoWidget->render(painter, QPoint(rect.x(), rect.y()),
+ QRegion(0, 0, rect.width(), rect.height()));
+}
+
+// ====================== Phonon::MediaObject signals ======================
+
+void MediaPlayerPrivate::stateChanged(Phonon::State newState, Phonon::State oldState)
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::stateChanged(newState=%s, oldState=%s)",
+ phononStates.valueToKey(newState), phononStates.valueToKey(oldState));
+
+ updateStates();
+}
+
+void MediaPlayerPrivate::tick(qint64)
+{
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::metaDataChanged()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()");
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivate::seekableChanged(bool)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivate::hasVideoChanged(bool hasVideo)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::hasVideoChanged(%s)", hasVideo ? "true" : "false");
+}
+
+void MediaPlayerPrivate::bufferStatus(int)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivate::finished()
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivate::currentSourceChanged(const Phonon::MediaSource&)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivate::aboutToFinish()
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivate::prefinishMarkReached(qint32)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%d)", totalTime);
+ LOG_MEDIAOBJECT();
+}
+
+} // namespace WebCore
+
+#include "moc_MediaPlayerPrivatePhonon.cpp"
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
new file mode 100644
index 0000000..5eb2a09
--- /dev/null
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -0,0 +1,159 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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 MediaPlayerPrivatePhonon_h
+#define MediaPlayerPrivatePhonon_h
+
+#include "MediaPlayer.h"
+#include <wtf/Noncopyable.h>
+
+#include <QObject>
+#include <phononnamespace.h>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+class QUrl;
+
+namespace Phonon {
+ class MediaObject;
+ class VideoWidget;
+ class AudioOutput;
+ class MediaSource;
+}
+QT_END_NAMESPACE
+
+namespace WebCore {
+
+ class MediaPlayerPrivate : public QObject, Noncopyable {
+
+ Q_OBJECT
+
+ public:
+ MediaPlayerPrivate(MediaPlayer*);
+ ~MediaPlayerPrivate();
+
+ // These enums are used for debugging
+ Q_ENUMS(ReadyState NetworkState PhononState)
+
+ enum ReadyState {
+ DataUnavailable,
+ CanShowCurrentFrame,
+ CanPlay,
+ CanPlayThrough
+ };
+
+ enum NetworkState {
+ Empty,
+ LoadFailed,
+ Loading,
+ LoadedMetaData,
+ LoadedFirstFrame,
+ Loaded
+ };
+
+ enum PhononState {
+ LoadingState,
+ StoppedState,
+ PlayingState,
+ BufferingState,
+ PausedState,
+ ErrorState
+ };
+
+ IntSize naturalSize() const;
+ bool hasVideo() const;
+
+ void load(String url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float);
+ void setEndTime(float);
+
+ void setRate(float);
+ void setVolume(float);
+ void setMuted(bool);
+
+ int dataRate() const;
+
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
+
+ float maxTimeBuffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ bool totalBytesKnown() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void 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; }
+
+ protected:
+ bool eventFilter(QObject*, QEvent*);
+
+ private slots:
+ void stateChanged(Phonon::State, Phonon::State);
+ void tick(qint64);
+ void metaDataChanged();
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+ void finished();
+ void currentSourceChanged(const Phonon::MediaSource&);
+ void aboutToFinish();
+ void prefinishMarkReached(qint32);
+ void totalTimeChanged(qint64);
+
+ private:
+ void updateStates();
+
+ MediaPlayer* m_player;
+
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+
+ Phonon::MediaObject* m_mediaObject;
+ Phonon::VideoWidget* m_videoWidget;
+ Phonon::AudioOutput* m_audioOutput;
+
+ bool m_isVisible;
+ };
+}
+
+#endif // MediaPlayerPrivatePhonon_h
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
new file mode 100644
index 0000000..76f375c
--- /dev/null
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * 2006 Rob Buis <buis@kde.org>
+ *
+ * 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 "Path.h"
+
+#include "FloatRect.h"
+#include "PlatformString.h"
+#include "AffineTransform.h"
+#include <QPainterPath>
+#include <QMatrix>
+#include <QString>
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+namespace WebCore {
+
+Path::Path()
+ : m_path(new QPainterPath())
+{
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path::Path(const Path& other)
+ : m_path(new QPainterPath(*other.platformPath()))
+{
+}
+
+Path& Path::operator=(const Path& other)
+{
+ if (&other != this) {
+ delete m_path;
+ m_path = new QPainterPath(*other.platformPath());
+ }
+
+ return *this;
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ Qt::FillRule savedRule = m_path->fillRule();
+ m_path->setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+
+ bool contains = m_path->contains(point);
+
+ m_path->setFillRule(savedRule);
+ return contains;
+}
+
+void Path::translate(const FloatSize& size)
+{
+ QMatrix matrix;
+ matrix.translate(size.width(), size.height());
+ *m_path = (*m_path) * matrix;
+}
+
+FloatRect Path::boundingRect() const
+{
+ return m_path->boundingRect();
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path->moveTo(point);
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ m_path->lineTo(p);
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ m_path->quadTo(cp, p);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ m_path->cubicTo(cp1, cp2, p);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ //FIXME: busted
+ qWarning("arcTo is busted");
+ m_path->arcTo(p1.x(), p1.y(), p2.x(), p2.y(), radius, 90);
+}
+
+void Path::closeSubpath()
+{
+ m_path->closeSubpath();
+}
+
+#define DEGREES(t) ((t) * 180.0 / M_PI)
+void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise)
+{
+ qreal xc = p.x();
+ qreal yc = p.y();
+ qreal radius = r;
+
+
+ //### HACK
+ // In Qt we don't switch the coordinate system for degrees
+ // and still use the 0,0 as bottom left for degrees so we need
+ // to switch
+ sar = -sar;
+ ear = -ear;
+ anticlockwise = !anticlockwise;
+ //end hack
+
+ float sa = DEGREES(sar);
+ float ea = DEGREES(ear);
+
+ double span = 0;
+
+ double xs = xc - radius;
+ double ys = yc - radius;
+ double width = radius*2;
+ double height = radius*2;
+
+ if (!anticlockwise && (ea < sa))
+ span += 360;
+ else if (anticlockwise && (sa < ea))
+ span -= 360;
+
+ // this is also due to switched coordinate system
+ // we would end up with a 0 span instead of 360
+ if (!(qFuzzyCompare(span + (ea - sa) + 1, 1.0) &&
+ qFuzzyCompare(qAbs(span), 360.0))) {
+ span += ea - sa;
+ }
+
+ m_path->moveTo(QPointF(xc + radius * cos(sar),
+ yc - radius * sin(sar)));
+
+ m_path->arcTo(xs, ys, width, height, sa, span);
+}
+
+void Path::addRect(const FloatRect& r)
+{
+ m_path->addRect(r.x(), r.y(), r.width(), r.height());
+}
+
+void Path::addEllipse(const FloatRect& r)
+{
+ m_path->addEllipse(r.x(), r.y(), r.width(), r.height());
+}
+
+void Path::clear()
+{
+ *m_path = QPainterPath();
+}
+
+bool Path::isEmpty() const
+{
+ return m_path->isEmpty();
+}
+
+String Path::debugString() const
+{
+ QString ret;
+ for (int i = 0; i < m_path->elementCount(); ++i) {
+ const QPainterPath::Element &cur = m_path->elementAt(i);
+
+ switch (cur.type) {
+ case QPainterPath::MoveToElement:
+ ret += QString(QLatin1String("M %1 %2")).arg(cur.x).arg(cur.y);
+ break;
+ case QPainterPath::LineToElement:
+ ret += QString(QLatin1String("L %1 %2")).arg(cur.x).arg(cur.y);
+ break;
+ case QPainterPath::CurveToElement:
+ {
+ const QPainterPath::Element &c1 = m_path->elementAt(i + 1);
+ const QPainterPath::Element &c2 = m_path->elementAt(i + 2);
+
+ Q_ASSERT(c1.type == QPainterPath::CurveToDataElement);
+ Q_ASSERT(c2.type == QPainterPath::CurveToDataElement);
+
+ ret += QString(QLatin1String("C %1 %2 %3 %4 %5 %6")).arg(cur.x).arg(cur.y).arg(c1.x).arg(c1.y).arg(c2.x).arg(c2.y);
+
+ i += 2;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ Q_ASSERT(false);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ PathElement pelement;
+ FloatPoint points[3];
+ pelement.points = points;
+ for (int i = 0; i < m_path->elementCount(); ++i) {
+ const QPainterPath::Element& cur = m_path->elementAt(i);
+
+ switch (cur.type) {
+ case QPainterPath::MoveToElement:
+ pelement.type = PathElementMoveToPoint;
+ pelement.points[0] = QPointF(cur);
+ function(info, &pelement);
+ break;
+ case QPainterPath::LineToElement:
+ pelement.type = PathElementAddLineToPoint;
+ pelement.points[0] = QPointF(cur);
+ function(info, &pelement);
+ break;
+ case QPainterPath::CurveToElement:
+ {
+ const QPainterPath::Element& c1 = m_path->elementAt(i + 1);
+ const QPainterPath::Element& c2 = m_path->elementAt(i + 2);
+
+ Q_ASSERT(c1.type == QPainterPath::CurveToDataElement);
+ Q_ASSERT(c2.type == QPainterPath::CurveToDataElement);
+
+ pelement.type = PathElementAddCurveToPoint;
+ pelement.points[0] = QPointF(cur);
+ pelement.points[1] = QPointF(c1);
+ pelement.points[2] = QPointF(c2);
+ function(info, &pelement);
+
+ i += 2;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ Q_ASSERT(false);
+ }
+ }
+}
+
+void Path::transform(const AffineTransform& transform)
+{
+ if (m_path) {
+ QMatrix mat = transform;
+ QPainterPath temp = mat.map(*m_path);
+ delete m_path;
+ m_path = new QPainterPath(temp);
+ }
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/PatternQt.cpp b/WebCore/platform/graphics/qt/PatternQt.cpp
new file mode 100644
index 0000000..883a258
--- /dev/null
+++ b/WebCore/platform/graphics/qt/PatternQt.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 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
+ * 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 "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+QBrush Pattern::createPlatformPattern(const AffineTransform& transform) const
+{
+ QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame();
+ if (!pixmap)
+ return QBrush();
+
+ QBrush brush(*pixmap);
+ brush.setMatrix(transform);
+
+ return brush;
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
new file mode 100644
index 0000000..1ffce33
--- /dev/null
+++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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.
+
+ 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"
+
+namespace WebCore {
+
+SimpleFontData::SimpleFontData(const FontPlatformData& font, bool customFont, bool loading, SVGFontData*)
+ : m_font(font)
+ , m_isCustomFont(customFont)
+ , m_isLoading(loading)
+{
+}
+
+SimpleFontData::~SimpleFontData()
+{
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ return true;
+}
+
+const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
+{
+ return this;
+}
+
+bool SimpleFontData::isSegmented() const
+{
+ return false;
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp
new file mode 100644
index 0000000..95b3bc8
--- /dev/null
+++ b/WebCore/platform/graphics/qt/StillImageQt.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * 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 "StillImageQt.h"
+
+#include "GraphicsContext.h"
+#include "IntSize.h"
+
+#include <QPainter>
+
+namespace WebCore {
+
+StillImage::StillImage(const QPixmap& pixmap)
+ : m_pixmap(pixmap)
+{}
+
+IntSize StillImage::size() const
+{
+ return IntSize(m_pixmap.width(), m_pixmap.height());
+}
+
+NativeImagePtr StillImage::nativeImageForCurrentFrame()
+{
+ return const_cast<NativeImagePtr>(&m_pixmap);
+}
+
+void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
+ const FloatRect& src, CompositeOperator op)
+{
+ if (m_pixmap.isNull())
+ return;
+
+ ctxt->save();
+ ctxt->setCompositeOperation(op);
+ QPainter* painter(ctxt->platformContext());
+ painter->drawPixmap(dst, m_pixmap, src);
+ ctxt->restore();
+}
+
+}
diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h
new file mode 100644
index 0000000..37b8b2c
--- /dev/null
+++ b/WebCore/platform/graphics/qt/StillImageQt.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StillImageQt_h
+#define StillImageQt_h
+
+#include "Image.h"
+
+namespace WebCore {
+
+ class StillImage : public Image {
+ public:
+ static PassRefPtr<StillImage> create(const QPixmap& pixmap)
+ {
+ return adoptRef(new StillImage(pixmap));
+ }
+
+ // 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 unsigned decodedSize() const { return 0; }
+
+ virtual IntSize size() const;
+ virtual NativeImagePtr nativeImageForCurrentFrame();
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
+
+ private:
+ StillImage(const QPixmap& pixmap);
+
+ QPixmap m_pixmap;
+ };
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/win/ColorSafari.cpp b/WebCore/platform/graphics/win/ColorSafari.cpp
new file mode 100644
index 0000000..a04fd81
--- /dev/null
+++ b/WebCore/platform/graphics/win/ColorSafari.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include "NotImplemented.h"
+#include <CoreGraphics/CGColor.h>
+#include <SafariTheme/SafariTheme.h>
+#include <wtf/Assertions.h>
+#include <wtf/RetainPtr.h>
+
+using namespace SafariTheme;
+
+namespace WebCore {
+
+typedef CGColorRef (APIENTRY*stCopyThemeColorPtr)(unsigned, SafariTheme::ThemeControlState);
+static const unsigned stFocusRingColorID = 4;
+
+static const unsigned aquaFocusRingColor = 0xFF7DADD9;
+
+static RGBA32 makeRGBAFromCGColor(CGColorRef c)
+{
+ const CGFloat* components = CGColorGetComponents(c);
+ return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]);
+}
+
+Color focusRingColor()
+{
+ static Color focusRingColor;
+ focusRingColor.isValid();
+
+ if (!focusRingColor.isValid()) {
+ if (HMODULE module = LoadLibrary(SAFARITHEMEDLL))
+ if (stCopyThemeColorPtr stCopyThemeColor = (stCopyThemeColorPtr)GetProcAddress(module, "STCopyThemeColor")) {
+ RetainPtr<CGColorRef> c(AdoptCF, stCopyThemeColor(stFocusRingColorID, SafariTheme::ActiveState));
+ focusRingColor = makeRGBAFromCGColor(c.get());
+ }
+ if (!focusRingColor.isValid())
+ focusRingColor = aquaFocusRingColor;
+ }
+
+ return focusRingColor;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
new file mode 100644
index 0000000..1766cd9
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2006, 2007, 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "AffineTransform.h"
+#include "FloatConversion.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "SimpleFontData.h"
+#include "UniscribeController.h"
+#include "WebCoreTextRenderer.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+const int syntheticObliqueAngle = 14;
+
+static inline CGFloat toCGFloat(FIXED f)
+{
+ return f.value + f.fract / CGFloat(65536.0);
+}
+
+static CGPathRef createPathForGlyph(HDC hdc, Glyph glyph)
+{
+ CGMutablePathRef path = CGPathCreateMutable();
+
+ static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 };
+ GLYPHMETRICS glyphMetrics;
+ // GGO_NATIVE matches the outline perfectly when Windows font smoothing is off.
+ // GGO_NATIVE | GGO_UNHINTED does not match perfectly either when Windows font smoothing is on or off.
+ DWORD outlineLength = GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, 0, 0, &identity);
+ ASSERT(outlineLength >= 0);
+ if (outlineLength < 0)
+ return path;
+
+ Vector<UInt8> outline(outlineLength);
+ GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, &glyphMetrics, outlineLength, outline.data(), &identity);
+
+ unsigned offset = 0;
+ while (offset < outlineLength) {
+ LPTTPOLYGONHEADER subpath = reinterpret_cast<LPTTPOLYGONHEADER>(outline.data() + offset);
+ ASSERT(subpath->dwType == TT_POLYGON_TYPE);
+ if (subpath->dwType != TT_POLYGON_TYPE)
+ return path;
+
+ CGPathMoveToPoint(path, 0, toCGFloat(subpath->pfxStart.x), toCGFloat(subpath->pfxStart.y));
+
+ unsigned subpathOffset = sizeof(*subpath);
+ while (subpathOffset < subpath->cb) {
+ LPTTPOLYCURVE segment = reinterpret_cast<LPTTPOLYCURVE>(reinterpret_cast<UInt8*>(subpath) + subpathOffset);
+ switch (segment->wType) {
+ case TT_PRIM_LINE:
+ for (unsigned i = 0; i < segment->cpfx; i++)
+ CGPathAddLineToPoint(path, 0, toCGFloat(segment->apfx[i].x), toCGFloat(segment->apfx[i].y));
+ break;
+
+ case TT_PRIM_QSPLINE:
+ for (unsigned i = 0; i < segment->cpfx; i++) {
+ CGFloat x = toCGFloat(segment->apfx[i].x);
+ CGFloat y = toCGFloat(segment->apfx[i].y);
+ CGFloat cpx;
+ CGFloat cpy;
+
+ if (i == segment->cpfx - 2) {
+ cpx = toCGFloat(segment->apfx[i + 1].x);
+ cpy = toCGFloat(segment->apfx[i + 1].y);
+ i++;
+ } else {
+ cpx = (toCGFloat(segment->apfx[i].x) + toCGFloat(segment->apfx[i + 1].x)) / 2;
+ cpy = (toCGFloat(segment->apfx[i].y) + toCGFloat(segment->apfx[i + 1].y)) / 2;
+ }
+
+ CGPathAddQuadCurveToPoint(path, 0, x, y, cpx, cpy);
+ }
+ break;
+
+ case TT_PRIM_CSPLINE:
+ for (unsigned i = 0; i < segment->cpfx; i += 3) {
+ CGFloat cp1x = toCGFloat(segment->apfx[i].x);
+ CGFloat cp1y = toCGFloat(segment->apfx[i].y);
+ CGFloat cp2x = toCGFloat(segment->apfx[i + 1].x);
+ CGFloat cp2y = toCGFloat(segment->apfx[i + 1].y);
+ CGFloat x = toCGFloat(segment->apfx[i + 2].x);
+ CGFloat y = toCGFloat(segment->apfx[i + 2].y);
+
+ CGPathAddCurveToPoint(path, 0, cp1x, cp1y, cp2x, cp2y, x, y);
+ }
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ return path;
+ }
+
+ subpathOffset += sizeof(*segment) + (segment->cpfx - 1) * sizeof(segment->apfx[0]);
+ }
+ CGPathCloseSubpath(path);
+ offset += subpath->cb;
+ }
+ return path;
+}
+
+static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point)
+{
+ Color fillColor = graphicsContext->fillColor();
+
+ bool drawIntoBitmap = false;
+ int drawingMode = graphicsContext->textDrawingMode();
+ if (drawingMode == cTextFill) {
+ if (!fillColor.alpha())
+ return;
+
+ drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer();
+ if (!drawIntoBitmap) {
+ IntSize size;
+ int blur;
+ Color color;
+ graphicsContext->getShadow(size, blur, color);
+ drawIntoBitmap = !size.isEmpty() || blur;
+ }
+ }
+
+ // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances.
+ Vector<int, 2048> gdiAdvances;
+ int totalWidth = 0;
+ for (int i = 0; i < numGlyphs; i++) {
+ gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i)));
+ totalWidth += gdiAdvances[i];
+ }
+
+ HDC hdc = 0;
+ OwnPtr<GraphicsContext::WindowsBitmap> bitmap;
+ IntRect textRect;
+ if (!drawIntoBitmap)
+ hdc = graphicsContext->getWindowsContext(textRect, true, false);
+ if (!hdc) {
+ drawIntoBitmap = true;
+ // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges.
+ // FIXME: Can get glyphs' optical bounds (even from CG) to get this right.
+ int lineGap = font->lineGap();
+ textRect = IntRect(point.x() - (font->ascent() + font->descent()) / 2, point.y() - font->ascent() - lineGap, totalWidth + font->ascent() + font->descent(), font->lineSpacing());
+ bitmap.set(graphicsContext->createWindowsBitmap(textRect.size()));
+ memset(bitmap->buffer(), 255, bitmap->bufferLength());
+ hdc = bitmap->hdc();
+
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -textRect.x();
+ xform.eDy = -textRect.y();
+ SetWorldTransform(hdc, &xform);
+ }
+
+ SelectObject(hdc, font->m_font.hfont());
+
+ // Set the correct color.
+ if (drawIntoBitmap)
+ SetTextColor(hdc, RGB(0, 0, 0));
+ else
+ SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue()));
+
+ SetBkMode(hdc, TRANSPARENT);
+ SetTextAlign(hdc, TA_LEFT | TA_BASELINE);
+
+ // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
+ FloatSize translation = glyphBuffer.offsetAt(from);
+ if (translation.width() || translation.height()) {
+ XFORM xform;
+ xform.eM11 = 1.0;
+ xform.eM12 = 0;
+ xform.eM21 = 0;
+ xform.eM22 = 1.0;
+ xform.eDx = translation.width();
+ xform.eDy = translation.height();
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ }
+
+ if (drawingMode == cTextFill) {
+ XFORM xform;
+ xform.eM11 = 1.0;
+ xform.eM12 = 0;
+ xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0;
+ xform.eM22 = 1.0;
+ xform.eDx = point.x();
+ xform.eDy = point.y();
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
+ if (font->m_syntheticBoldOffset) {
+ xform.eM21 = 0;
+ xform.eDx = font->m_syntheticBoldOffset;
+ xform.eDy = 0;
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+ ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data());
+ }
+ } else {
+ RetainPtr<CGMutablePathRef> path(AdoptCF, CGPathCreateMutable());
+
+ XFORM xform;
+ GetWorldTransform(hdc, &xform);
+ AffineTransform 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));
+ initialGlyphTransform.tx = 0;
+ initialGlyphTransform.ty = 0;
+ CGAffineTransform glyphTranslation = CGAffineTransformIdentity;
+
+ for (unsigned i = 0; i < numGlyphs; ++i) {
+ RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i)));
+ CGAffineTransform glyphTransform = CGAffineTransformConcat(initialGlyphTransform, glyphTranslation);
+ CGPathAddPath(path.get(), &glyphTransform, glyphPath.get());
+ glyphTranslation = CGAffineTransformTranslate(glyphTranslation, gdiAdvances[i], 0);
+ }
+
+ CGContextRef cgContext = graphicsContext->platformContext();
+ CGContextSaveGState(cgContext);
+
+ BOOL fontSmoothingEnabled = false;
+ SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0);
+ CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled);
+
+ CGContextScaleCTM(cgContext, 1.0, -1.0);
+ CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height()));
+
+ if (drawingMode & cTextFill) {
+ CGContextAddPath(cgContext, path.get());
+ CGContextFillPath(cgContext);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, path.get());
+ CGContextFillPath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
+ }
+ if (drawingMode & cTextStroke) {
+ CGContextAddPath(cgContext, path.get());
+ CGContextStrokePath(cgContext);
+ if (font->m_syntheticBoldOffset) {
+ CGContextTranslateCTM(cgContext, font->m_syntheticBoldOffset, 0);
+ CGContextAddPath(cgContext, path.get());
+ CGContextStrokePath(cgContext);
+ CGContextTranslateCTM(cgContext, -font->m_syntheticBoldOffset, 0);
+ }
+ }
+ CGContextRestoreGState(cgContext);
+ }
+
+ if (drawIntoBitmap) {
+ UInt8* buffer = bitmap->buffer();
+ unsigned bufferLength = bitmap->bufferLength();
+ for (unsigned i = 0; i < bufferLength; i += 4) {
+ // Use green, which is always in the middle.
+ UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255;
+ buffer[i] = fillColor.blue();
+ buffer[i + 1] = fillColor.green();
+ buffer[i + 2] = fillColor.red();
+ buffer[i + 3] = alpha;
+ }
+ graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.topLeft());
+ } else
+ graphicsContext->releaseWindowsContext(hdc, textRect, true, false);
+}
+
+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();
+
+ uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, WebCoreShouldUseFontSmoothing());
+
+ const FontPlatformData& platformData = font->platformData();
+
+ CGContextSetFont(cgContext, platformData.cgFont());
+
+ CGAffineTransform matrix = CGAffineTransformIdentity;
+ matrix.b = -matrix.b;
+ matrix.d = -matrix.d;
+
+ if (platformData.syntheticOblique()) {
+ static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f);
+ matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0));
+ }
+
+ CGContextSetTextMatrix(cgContext, matrix);
+
+ // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
+ FloatSize translation = glyphBuffer.offsetAt(from);
+
+ CGContextSetFontSize(cgContext, platformData.size());
+ wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false);
+
+ IntSize shadowSize;
+ int shadowBlur;
+ Color shadowColor;
+ graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor);
+
+ bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur;
+ if (hasSimpleShadow) {
+ // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
+ graphicsContext->clearShadow();
+ Color fillColor = graphicsContext->fillColor();
+ Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
+ graphicsContext->setFillColor(shadowFillColor);
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->m_syntheticBoldOffset) {
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->m_syntheticBoldOffset, point.y() + translation.height() + shadowSize.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+ graphicsContext->setFillColor(fillColor);
+ }
+
+ CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ if (font->m_syntheticBoldOffset) {
+ CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->m_syntheticBoldOffset, point.y() + translation.height());
+ CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
+ }
+
+ if (hasSimpleShadow)
+ graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor);
+
+ wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp
new file mode 100644
index 0000000..49b3d76
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2006, 2007, 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 <winsock2.h>
+#include "FontCache.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+#include "StringHash.h"
+#include "UnicodeRange.h"
+#include <windows.h>
+#include <mlang.h>
+#if PLATFORM(CG)
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
+
+using std::min;
+
+namespace WebCore
+{
+
+void FontCache::platformInit()
+{
+#if PLATFORM(CG)
+ wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
+#endif
+}
+
+IMLangFontLink2* FontCache::getFontLinkInterface()
+{
+ static IMultiLanguage *multiLanguage;
+ if (!multiLanguage) {
+ if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK)
+ return 0;
+ }
+
+ static IMLangFontLink2* langFontLink;
+ if (!langFontLink) {
+ if (multiLanguage->QueryInterface(&langFontLink) != S_OK)
+ return 0;
+ }
+
+ return langFontLink;
+}
+
+static int CALLBACK metaFileEnumProc(HDC hdc, HANDLETABLE* table, CONST ENHMETARECORD* record, int tableEntries, LPARAM logFont)
+{
+ if (record->iType == EMR_EXTCREATEFONTINDIRECTW) {
+ const EMREXTCREATEFONTINDIRECTW* createFontRecord = reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record);
+ *reinterpret_cast<LOGFONT*>(logFont) = createFontRecord->elfw.elfLogFont;
+ }
+ return true;
+}
+
+static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont)
+{
+ *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont);
+ return false;
+}
+
+static const Vector<String>* getLinkedFonts(String& family)
+{
+ static HashMap<String, Vector<String>*> systemLinkMap;
+ Vector<String>* result = systemLinkMap.get(family);
+ if (result)
+ return result;
+
+ result = new Vector<String>;
+ systemLinkMap.set(family, result);
+ HKEY fontLinkKey;
+ if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey)))
+ return result;
+
+ DWORD linkedFontsBufferSize = 0;
+ RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, NULL, &linkedFontsBufferSize);
+ WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize));
+ if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize))) {
+ unsigned i = 0;
+ unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts);
+ while (i < length) {
+ while (i < length && linkedFonts[i] != ',')
+ i++;
+ i++;
+ unsigned j = i;
+ while (j < length && linkedFonts[j])
+ j++;
+ result->append(String(linkedFonts + i, j - i));
+ i = j + 1;
+ }
+ }
+ free(linkedFonts);
+ RegCloseKey(fontLinkKey);
+ return result;
+}
+
+static const Vector<DWORD, 4>& getCJKCodePageMasks()
+{
+ // The default order in which we look for a font for a CJK character. If the user's default code page is
+ // one of these, we will use it first.
+ static const UINT CJKCodePages[] = {
+ 932, /* Japanese */
+ 936, /* Simplified Chinese */
+ 950, /* Traditional Chinese */
+ 949 /* Korean */
+ };
+
+ static Vector<DWORD, 4> codePageMasks;
+ static bool initialized;
+ if (!initialized) {
+ initialized = true;
+ IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface();
+ if (!langFontLink)
+ return codePageMasks;
+
+ UINT defaultCodePage;
+ DWORD defaultCodePageMask = 0;
+ if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
+ langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
+
+ if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
+ codePageMasks.append(defaultCodePageMask);
+ for (unsigned i = 0; i < 4; ++i) {
+ if (defaultCodePage != CJKCodePages[i]) {
+ DWORD codePageMask;
+ langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
+ codePageMasks.append(codePageMask);
+ }
+ }
+ }
+ return codePageMasks;
+}
+
+static bool currentFontContainsCharacter(HDC hdc, UChar character)
+{
+ static Vector<char, 512> glyphsetBuffer;
+ glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0));
+ GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data());
+ GetFontUnicodeRanges(hdc, glyphset);
+
+ // FIXME: Change this to a binary search.
+ unsigned i = 0;
+ while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character)
+ i++;
+
+ return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > character;
+}
+
+static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
+{
+ HFONT MLangFont;
+ HFONT hfont = 0;
+ if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont)) && MLangFont) {
+ LOGFONT lf;
+ GetObject(MLangFont, sizeof(LOGFONT), &lf);
+ langFontLink->ReleaseFont(MLangFont);
+ hfont = CreateFontIndirect(&lf);
+ }
+ return hfont;
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ UChar character = characters[0];
+ SimpleFontData* fontData = 0;
+ HDC hdc = GetDC(0);
+ HFONT primaryFont = font.primaryFont()->fontDataForCharacter(character)->platformData().hfont();
+ HGDIOBJ oldFont = SelectObject(hdc, primaryFont);
+ HFONT hfont = 0;
+
+ if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
+ // Try MLang font linking first.
+ DWORD codePages = 0;
+ langFontLink->GetCharCodePages(character, &codePages);
+
+ if (codePages && findCharUnicodeRange(character) == cRangeSetCJK) {
+ // The CJK character may belong to multiple code pages. We want to
+ // do font linking against a single one of them, preferring the default
+ // code page for the user's locale.
+ const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
+ unsigned numCodePages = CJKCodePageMasks.size();
+ for (unsigned i = 0; i < numCodePages && !hfont; ++i) {
+ hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]);
+ if (hfont && !(codePages & CJKCodePageMasks[i])) {
+ // We asked about a code page that is not one of the code pages
+ // returned by MLang, so the font might not contain the character.
+ SelectObject(hdc, hfont);
+ if (!currentFontContainsCharacter(hdc, character)) {
+ DeleteObject(hfont);
+ hfont = 0;
+ }
+ SelectObject(hdc, primaryFont);
+ }
+ }
+ } else
+ hfont = createMLangFont(langFontLink, hdc, codePages, character);
+ }
+
+ // A font returned from MLang is trusted to contain the character.
+ bool containsCharacter = hfont;
+
+ if (!hfont) {
+ // To find out what font Uniscribe would use, we make it draw into a metafile and intercept
+ // calls to CreateFontIndirect().
+ HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
+ SelectObject(metaFileDc, primaryFont);
+
+ bool scriptStringOutSucceeded = false;
+ SCRIPT_STRING_ANALYSIS ssa;
+
+ // FIXME: If length is greater than 1, we actually return the font for the last character.
+ // This function should be renamed getFontDataForCharacter and take a single 32-bit character.
+ if (SUCCEEDED(ScriptStringAnalyse(metaFileDc, characters, length, 0, -1, SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,
+ 0, NULL, NULL, NULL, NULL, NULL, &ssa))) {
+ scriptStringOutSucceeded = SUCCEEDED(ScriptStringOut(ssa, 0, 0, 0, NULL, 0, 0, FALSE));
+ ScriptStringFree(&ssa);
+ }
+ HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDc);
+ if (scriptStringOutSucceeded) {
+ LOGFONT logFont;
+ logFont.lfFaceName[0] = 0;
+ EnumEnhMetaFile(0, metaFile, metaFileEnumProc, &logFont, NULL);
+ if (logFont.lfFaceName[0])
+ hfont = CreateFontIndirect(&logFont);
+ }
+ DeleteEnhMetaFile(metaFile);
+ }
+
+ String familyName;
+ const Vector<String>* linkedFonts = 0;
+ unsigned linkedFontIndex = 0;
+ while (hfont) {
+ SelectObject(hdc, hfont);
+ WCHAR name[LF_FACESIZE];
+ GetTextFace(hdc, LF_FACESIZE, name);
+ familyName = name;
+
+ if (containsCharacter || currentFontContainsCharacter(hdc, character))
+ break;
+
+ if (!linkedFonts)
+ linkedFonts = getLinkedFonts(familyName);
+ SelectObject(hdc, oldFont);
+ DeleteObject(hfont);
+ hfont = 0;
+
+ if (linkedFonts->size() <= linkedFontIndex)
+ break;
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ memcpy(logFont.lfFaceName, linkedFonts->at(linkedFontIndex).characters(), linkedFonts->at(linkedFontIndex).length() * sizeof(WCHAR));
+ logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0;
+ EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<LPARAM>(&hfont), 0);
+ linkedFontIndex++;
+ }
+
+ if (hfont) {
+ if (!familyName.isEmpty()) {
+ FontPlatformData* result = getCachedFontPlatformData(font.fontDescription(), familyName);
+ if (result)
+ fontData = getCachedFontData(result);
+ }
+
+ SelectObject(hdc, oldFont);
+ DeleteObject(hfont);
+ }
+
+ ReleaseDC(0, hdc);
+ return fontData;
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ // 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");
+ return getCachedFontPlatformData(fontDescription, timesStr);
+}
+
+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];
+}
+
+static inline bool isGDIFontWeightBold(LONG gdiFontWeight)
+{
+ return gdiFontWeight >= FW_SEMIBOLD;
+}
+
+static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
+{
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr)) {
+ if (gdiFontWeight == FW_NORMAL)
+ return FW_MEDIUM;
+ if (gdiFontWeight == FW_BOLD)
+ return FW_SEMIBOLD;
+ }
+ return gdiFontWeight;
+}
+
+struct MatchImprovingProcData {
+ MatchImprovingProcData(LONG desiredWeight, bool desiredItalic)
+ : m_desiredWeight(desiredWeight)
+ , m_desiredItalic(desiredItalic)
+ , m_hasMatched(false)
+ {
+ }
+
+ LONG m_desiredWeight;
+ bool m_desiredItalic;
+ bool m_hasMatched;
+ LOGFONT m_chosen;
+};
+
+static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ MatchImprovingProcData* matchData = reinterpret_cast<MatchImprovingProcData*>(lParam);
+
+ if (!matchData->m_hasMatched) {
+ matchData->m_hasMatched = true;
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ if (!candidate->lfItalic != !matchData->m_chosen.lfItalic) {
+ if (!candidate->lfItalic == !matchData->m_desiredItalic)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+ }
+
+ unsigned chosenWeightDeltaMagnitude = abs(matchData->m_chosen.lfWeight - matchData->m_desiredWeight);
+ unsigned candidateWeightDeltaMagnitude = abs(candidate->lfWeight - matchData->m_desiredWeight);
+
+ // If both are the same distance from the desired weight, prefer the candidate if it is further from regular.
+ if (chosenWeightDeltaMagnitude == candidateWeightDeltaMagnitude && abs(candidate->lfWeight - FW_NORMAL) > abs(matchData->m_chosen.lfWeight - FW_NORMAL)) {
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ // Otherwise, prefer the one closer to the desired weight.
+ if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+}
+
+static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(family.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, family.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ MatchImprovingProcData matchData(desiredWeight, desiredItalic);
+ EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<LPARAM>(&matchData), 0);
+
+ ReleaseDC(0, hdc);
+
+ if (!matchData.m_hasMatched)
+ return 0;
+
+ matchData.m_chosen.lfHeight = -size;
+ matchData.m_chosen.lfWidth = 0;
+ matchData.m_chosen.lfEscapement = 0;
+ matchData.m_chosen.lfOrientation = 0;
+ matchData.m_chosen.lfUnderline = false;
+ matchData.m_chosen.lfStrikeOut = false;
+ matchData.m_chosen.lfCharSet = DEFAULT_CHARSET;
+#if PLATFORM(CG) || PLATFORM(CAIRO)
+ matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+#else
+ matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS;
+#endif
+ matchData.m_chosen.lfQuality = DEFAULT_QUALITY;
+ matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ return CreateFontIndirect(&matchData.m_chosen);
+}
+
+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 = adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+void FontCache::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)
+{
+ bool isLucidaGrande = false;
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr))
+ isLucidaGrande = true;
+
+ bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande;
+
+ // The logical size constant is 32. We do this for subpixel precision when rendering using Uniscribe.
+ // This masks rounding errors related to the HFONT metrics being different from the CGFont metrics.
+ // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't
+ // look as nice. That may be solvable though.
+ LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family);
+ HFONT hfont = createGDIFont(family, weight, fontDescription.italic(), fontDescription.computedPixelSize() * (useGDI ? 1 : 32));
+
+ if (!hfont)
+ return 0;
+
+ if (isLucidaGrande)
+ useGDI = false; // Never use GDI for Lucida Grande.
+
+ LOGFONT logFont;
+ GetObject(hfont, sizeof(LOGFONT), &logFont);
+
+ bool synthesizeBold = isGDIFontWeightBold(weight) && !isGDIFontWeightBold(logFont.lfWeight);
+ bool synthesizeItalic = fontDescription.italic() && !logFont.lfItalic;
+
+ FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI);
+
+#if PLATFORM(CG)
+ bool fontCreationFailed = !result->cgFont();
+#elif PLATFORM(CAIRO)
+ bool fontCreationFailed = !result->fontFace();
+#endif
+
+ if (fontCreationFailed) {
+ // The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make
+ // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next
+ // font.
+ delete result;
+ DeleteObject(hfont);
+ return 0;
+ }
+
+ return result;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..26fceba
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "Base64.h"
+#include "FontPlatformData.h"
+#include "OpenTypeUtilities.h"
+#include "SharedBuffer.h"
+#include "SoftLinking.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/RetainPtr.h>
+
+// From t2embapi.h, which is missing from the Microsoft Platform SDK.
+typedef unsigned long(WINAPIV *READEMBEDPROC) (void*, void*, unsigned long);
+struct TTLOADINFO;
+#define TTLOAD_PRIVATE 0x00000001
+#define LICENSE_PREVIEWPRINT 0x0004
+#define E_NONE 0x0000L
+
+namespace WebCore {
+
+using namespace std;
+
+SOFT_LINK_LIBRARY(T2embed);
+SOFT_LINK(T2embed, TTLoadEmbeddedFont, LONG, __stdcall, (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus, READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName, LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo), (phFontReference, ulFlags,pulPrivStatus, ulPrivs, pulStatus, lpfnReadFromStream, lpvReadStream, szWinFamilyName, szMacFamilyName, pTTLoadInfo));
+SOFT_LINK(T2embed, TTGetNewFontName, LONG, __stdcall, (HANDLE* phFontReference, LPWSTR szWinFamilyName, long cchMaxWinName, LPSTR szMacFamilyName, long cchMaxMacName), (phFontReference, szWinFamilyName, cchMaxWinName, szMacFamilyName, cchMaxMacName));
+SOFT_LINK(T2embed, TTDeleteEmbeddedFont, LONG, __stdcall, (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus), (hFontReference, ulFlags, pulStatus));
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ CGFontRelease(m_cgFont);
+ if (m_fontReference) {
+ if (m_name.isNull()) {
+ ASSERT(T2embedLibrary());
+ ULONG status;
+ TTDeleteEmbeddedFont(m_fontReference, 0, &status);
+ } else
+ RemoveFontMemResourceEx(m_fontReference);
+ }
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode renderingMode)
+{
+ ASSERT(m_cgFont);
+ ASSERT(m_fontReference);
+ ASSERT(T2embedLibrary());
+
+ LOGFONT logFont;
+ if (m_name.isNull())
+ TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0);
+ else
+ memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), sizeof(logFont.lfFaceName[0]) * min(static_cast<size_t>(LF_FACESIZE), 1 + m_name.length()));
+
+ logFont.lfHeight = -size;
+ if (renderingMode == NormalRenderingMode)
+ logFont.lfHeight *= 32;
+ 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 = CLEARTYPE_QUALITY;
+ logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ logFont.lfItalic = italic;
+ logFont.lfWeight = bold ? 700 : 400;
+
+ HFONT hfont = CreateFontIndirect(&logFont);
+ return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode);
+}
+
+const void* getData(void* info)
+{
+ SharedBuffer* buffer = static_cast<SharedBuffer*>(info);
+ buffer->ref();
+ return (void*)buffer->data();
+}
+
+void releaseData(void* info, const void* data)
+{
+ static_cast<SharedBuffer*>(info)->deref();
+}
+
+size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count)
+{
+ SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+ size_t availBytes = count;
+ if (offset + count > sharedBuffer->size())
+ availBytes -= (offset + count) - sharedBuffer->size();
+ memcpy(buffer, sharedBuffer->data() + offset, availBytes);
+ return availBytes;
+}
+
+// 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 = 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 = 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 = max<int>(m_overlayDst - m_offset, 0);
+ size_t srcOffset = max<int>(0, m_offset - m_overlayDst);
+ size_t bytesToCopy = 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());
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+ ASSERT(T2embedLibrary());
+
+ // Get CG to create the font.
+ CGDataProviderDirectAccessCallbacks callbacks = { &getData, &releaseData, &getBytesWithOffset, NULL };
+ RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirectAccess(buffer, buffer->size(), &callbacks));
+ CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider.get());
+ if (!cgFont)
+ return 0;
+
+ // 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)) {
+ CGFontRelease(cgFont);
+ 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) {
+ CGFontRelease(cgFont);
+ return 0;
+ }
+ }
+
+ return new FontCustomPlatformData(cgFont, fontReference, fontName);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.h b/WebCore/platform/graphics/win/FontCustomPlatformData.h
new file mode 100644
index 0000000..34a9851
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
+#include <wtf/Noncopyable.h>
+
+typedef struct CGFont* CGFontRef;
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ FontCustomPlatformData(CGFontRef cgFont, HANDLE fontReference, const String& name)
+ : m_cgFont(cgFont)
+ , m_fontReference(fontReference)
+ , m_name(name)
+ {
+ }
+
+ ~FontCustomPlatformData();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
+
+ CGFontRef m_cgFont;
+ HANDLE m_fontReference;
+ String m_name;
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
new file mode 100644
index 0000000..e54d85a
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontCustomPlatformDataCairo.h"
+
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+FontCustomPlatformDataCairo::~FontCustomPlatformDataCairo()
+{
+ cairo_font_face_destroy(m_fontFace);
+}
+
+FontPlatformData FontCustomPlatformDataCairo::fontPlatformData(int size, bool bold, bool italic)
+{
+ return FontPlatformData(m_fontFace, size, bold, italic);
+}
+
+static void releaseData(void* data)
+{
+ static_cast<SharedBuffer*>(data)->deref();
+}
+
+FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ buffer->ref();
+ HFONT font = reinterpret_cast<HFONT>(buffer);
+ cairo_font_face_t* fontFace = cairo_win32_font_face_create_for_hfont(font);
+ if (!fontFace)
+ return 0;
+
+ static cairo_user_data_key_t bufferKey;
+ cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData);
+
+ return new FontCustomPlatformDataCairo(fontFace);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
new file mode 100644
index 0000000..87794b5
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontCustomPlatformDataCairo_h
+#define FontCustomPlatformDataCairo_h
+
+#include <wtf/Noncopyable.h>
+
+#include <cairo.h>
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformDataCairo : Noncopyable {
+ FontCustomPlatformDataCairo(cairo_font_face_t* fontFace)
+ : m_fontFace(fontFace)
+ {
+ }
+ ~FontCustomPlatformDataCairo();
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+
+ cairo_font_face_t* m_fontFace;
+};
+
+FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer*);
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/win/FontDatabase.cpp b/WebCore/platform/graphics/win/FontDatabase.cpp
new file mode 100644
index 0000000..1308ff0
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontDatabase.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FontDatabase.h"
+
+#include "CString.h"
+#include "FileSystem.h"
+#include "PlatformString.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <shlobj.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+static String systemFontsDirectory()
+{
+ static bool initialized;
+ static String directory;
+
+ if (!initialized) {
+ initialized = true;
+
+ Vector<UChar> buffer(MAX_PATH);
+ if (FAILED(SHGetFolderPath(0, CSIDL_FONTS | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
+ return directory;
+ buffer.resize(wcslen(buffer.data()));
+
+ directory = String::adopt(buffer);
+ }
+
+ return directory;
+}
+
+static String fontsPlistPath()
+{
+ static String path = pathByAppendingComponent(localUserSpecificStorageDirectory(), "FontsList.plist");
+ return path;
+}
+
+static bool systemHasFontsNewerThanFontsPlist()
+{
+ WIN32_FILE_ATTRIBUTE_DATA plistAttributes = {0};
+ if (!GetFileAttributesEx(fontsPlistPath().charactersWithNullTermination(), GetFileExInfoStandard, &plistAttributes))
+ return true;
+
+ WIN32_FILE_ATTRIBUTE_DATA fontsDirectoryAttributes = {0};
+ if (!GetFileAttributesEx(systemFontsDirectory().charactersWithNullTermination(), GetFileExInfoStandard, &fontsDirectoryAttributes))
+ return true;
+
+ return CompareFileTime(&plistAttributes.ftLastWriteTime, &fontsDirectoryAttributes.ftLastWriteTime) < 0;
+}
+
+static RetainPtr<CFPropertyListRef> readFontPlist()
+{
+ CString plistPath = fontsPlistPath().utf8();
+
+ RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateFromFileSystemRepresentation(0, reinterpret_cast<const UInt8*>(plistPath.data()), plistPath.length(), false));
+ if (!url)
+ return 0;
+
+ RetainPtr<CFReadStreamRef> stream(AdoptCF, CFReadStreamCreateWithFile(0, url.get()));
+ if (!stream)
+ return 0;
+
+ if (!CFReadStreamOpen(stream.get()))
+ return 0;
+
+ CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0 | kCFPropertyListXMLFormat_v1_0;
+ RetainPtr<CFPropertyListRef> plist(AdoptCF, CFPropertyListCreateFromStream(0, stream.get(), 0, kCFPropertyListMutableContainersAndLeaves, &format, 0));
+
+ CFReadStreamClose(stream.get());
+
+ return plist;
+}
+
+static bool populateFontDatabaseFromPlist()
+{
+ RetainPtr<CFPropertyListRef> plist = readFontPlist();
+ if (!plist)
+ return false;
+
+ RetainPtr<CFDataRef> data(AdoptCF, CFPropertyListCreateXMLData(0, plist.get()));
+ if (!data)
+ return false;
+
+ wkAddFontsFromPlistRepresentation(data.get());
+ return true;
+}
+
+static bool populateFontDatabaseFromFileSystem()
+{
+ RetainPtr<CFStringRef> directory(AdoptCF, systemFontsDirectory().createCFString());
+ if (!directory)
+ return false;
+
+ wkAddFontsInDirectory(directory.get());
+ return true;
+}
+
+static void writeFontDatabaseToPlist()
+{
+ RetainPtr<CFDataRef> data(AdoptCF, wkCreateFontsPlistRepresentation());
+ if (!data)
+ return;
+
+ safeCreateFile(fontsPlistPath(), data.get());
+}
+
+void populateFontDatabase()
+{
+ static bool initialized;
+ if (initialized)
+ return;
+ initialized = true;
+
+ if (!systemHasFontsNewerThanFontsPlist())
+ if (populateFontDatabaseFromPlist())
+ return;
+
+ if (populateFontDatabaseFromFileSystem())
+ writeFontDatabaseToPlist();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/FontDatabase.h b/WebCore/platform/graphics/win/FontDatabase.h
new file mode 100644
index 0000000..4f76c9e
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontDatabase.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FontDatabase_h
+#define FontDatabase_h
+
+namespace WebCore {
+
+ void populateFontDatabase();
+
+} // namespace WebCore
+
+#endif // !defined(FontDatabase_h)
diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h
new file mode 100644
index 0000000..d61afa8
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformData.h
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FontPlatformData_H
+#define FontPlatformData_H
+
+#include "StringImpl.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/RefCounted.h>
+
+#if PLATFORM(CAIRO)
+#include <cairo-win32.h>
+#endif
+
+typedef struct HFONT__* HFONT;
+typedef struct CGFont* CGFontRef;
+
+namespace WebCore {
+
+class FontDescription;
+
+class FontPlatformData {
+public:
+ FontPlatformData()
+#if PLATFORM(CAIRO)
+ : m_fontFace(0)
+ ,
+#else
+ :
+#endif
+ m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_useGDI(false)
+ {
+ }
+
+ FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI);
+ FontPlatformData(float size, bool bold, bool oblique);
+
+#if PLATFORM(CG)
+ FontPlatformData(HFONT, CGFontRef, float size, bool bold, bool oblique, bool useGDI);
+#elif PLATFORM(CAIRO)
+ FontPlatformData(cairo_font_face_t*, float size, bool bold, bool oblique);
+#endif
+ ~FontPlatformData();
+
+ FontPlatformData(WTF::HashTableDeletedValueType) : m_font(WTF::HashTableDeletedValue) { }
+ bool isHashTableDeletedValue() const { return m_font.isHashTableDeletedValue(); }
+
+ HFONT hfont() const { return m_font->hfont(); }
+#if PLATFORM(CG)
+ CGFontRef cgFont() const { return m_cgFont.get(); }
+#elif PLATFORM(CAIRO)
+ void setFont(cairo_t* ft) const;
+ cairo_font_face_t* fontFace() const { return m_fontFace; }
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+#endif
+
+ float size() const { return m_size; }
+ void setSize(float size) { m_size = size; }
+ bool syntheticBold() const { return m_syntheticBold; }
+ bool syntheticOblique() const { return m_syntheticOblique; }
+ bool useGDI() const { return m_useGDI; }
+
+ unsigned hash() const
+ {
+ return m_font->hash();
+ }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font &&
+#if PLATFORM(CG)
+ m_cgFont == other.m_cgFont &&
+#elif PLATFORM(CAIRO)
+ m_fontFace == other.m_fontFace &&
+ m_scaledFont == other.m_scaledFont &&
+#endif
+ m_size == other.m_size &&
+ m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique &&
+ m_useGDI == other.m_useGDI;
+ }
+
+private:
+ class RefCountedHFONT : public RefCounted<RefCountedHFONT> {
+ public:
+ static PassRefPtr<RefCountedHFONT> create(HFONT hfont) { return adoptRef(new RefCountedHFONT(hfont)); }
+ static PassRefPtr<RefCountedHFONT> createDeleted() { return adoptRef(new RefCountedHFONT(reinterpret_cast<HFONT>(-1))); }
+
+ ~RefCountedHFONT() { if (m_hfont != reinterpret_cast<HFONT>(-1)) DeleteObject(m_hfont); }
+
+ HFONT hfont() const { return m_hfont; }
+ unsigned hash() const
+ {
+ return StringImpl::computeHash(reinterpret_cast<const UChar*>(&m_hfont), sizeof(HFONT) / sizeof(UChar));
+ }
+
+ private:
+ RefCountedHFONT(HFONT hfont)
+ : m_hfont(hfont)
+ {
+ }
+
+ HFONT m_hfont;
+ };
+
+ void platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName);
+
+ RefPtr<RefCountedHFONT> m_font;
+#if PLATFORM(CG)
+ RetainPtr<CGFontRef> m_cgFont;
+#elif PLATFORM(CAIRO)
+ cairo_font_face_t* m_fontFace;
+ cairo_scaled_font_t* m_scaledFont;
+#endif
+
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+ bool m_useGDI;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
new file mode 100644
index 0000000..bbfdb9f
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include "StringHash.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+using std::min;
+
+namespace WebCore {
+
+static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; }
+
+static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc)
+{
+ const DWORD cMaxNameTableSize = 1024 * 1024;
+
+ static HashMap<String, RetainPtr<CFStringRef> > nameMap;
+
+ // Check our hash first.
+ String faceString(faceName);
+ RetainPtr<CFStringRef> result = nameMap.get(faceString);
+ if (result)
+ return result.get();
+
+ // We need to obtain the PostScript name from the name table and use it instead,.
+ DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards
+ if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize)
+ return NULL;
+
+ Vector<BYTE> bufferVector(bufferSize);
+ BYTE* buffer = bufferVector.data();
+ if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR)
+ return NULL;
+
+ if (bufferSize < 6)
+ return NULL;
+
+ USHORT numberOfRecords = readBigEndianWord(buffer + 2);
+ UINT stringsOffset = readBigEndianWord(buffer + 4);
+ if (bufferSize < stringsOffset)
+ return NULL;
+
+ BYTE* strings = buffer + stringsOffset;
+
+ // Now walk each name record looking for a Mac or Windows PostScript name.
+ UINT offset = 6;
+ for (int i = 0; i < numberOfRecords; i++) {
+ if (bufferSize < offset + 12)
+ return NULL;
+
+ USHORT platformID = readBigEndianWord(buffer + offset);
+ USHORT encodingID = readBigEndianWord(buffer + offset + 2);
+ USHORT languageID = readBigEndianWord(buffer + offset + 4);
+ USHORT nameID = readBigEndianWord(buffer + offset + 6);
+ USHORT length = readBigEndianWord(buffer + offset + 8);
+ USHORT nameOffset = readBigEndianWord(buffer + offset + 10);
+
+ if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) {
+ // This is a Windows PostScript name and is therefore UTF-16.
+ // Pass Big Endian as the encoding.
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false));
+ break;
+ } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) {
+ // This is a Mac PostScript name and is therefore ASCII.
+ // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false));
+ break;
+ }
+
+ offset += 12;
+ }
+
+ if (result)
+ nameMap.set(faceString, result);
+ return result.get();
+}
+
+void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
+{
+ // Try the face name first. Windows may end up localizing this name, and CG doesn't know about
+ // the localization. If the create fails, we'll try the PostScript name.
+ RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)));
+ m_cgFont.adoptCF(CGFontCreateWithFontName(fullName.get()));
+ if (!m_cgFont) {
+ CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc);
+ if (postScriptName) {
+ m_cgFont.adoptCF(CGFontCreateWithFontName(postScriptName));
+ ASSERT(m_cgFont);
+ }
+ }
+}
+
+FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedHFONT::create(hfont))
+ , m_size(size)
+ , m_cgFont(font)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(useGDI)
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
new file mode 100644
index 0000000..438d0a9
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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) 2007 Alp Toker
+ * Copyright (C) 2008 Brent Fulgham
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+#include <cairo-win32.h>
+
+using std::min;
+
+namespace WebCore {
+
+void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
+{
+ m_fontFace = cairo_win32_font_face_create_for_hfont(font);
+ cairo_matrix_t sizeMatrix, ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_matrix_init_scale(&sizeMatrix, size, size);
+
+ static cairo_font_options_t* fontOptions = 0;
+ if (!fontOptions)
+ {
+ fontOptions = cairo_font_options_create();
+ cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
+ }
+
+ m_scaledFont = cairo_scaled_font_create(m_fontFace, &sizeMatrix, &ctm, fontOptions);
+}
+
+FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool oblique)
+ : m_font(0)
+ , m_size(size)
+ , m_fontFace(fontFace)
+ , m_scaledFont(0)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(false)
+{
+ cairo_matrix_t fontMatrix;
+ cairo_matrix_init_scale(&fontMatrix, size, size);
+ cairo_matrix_t ctm;
+ cairo_matrix_init_identity(&ctm);
+ cairo_font_options_t* options = cairo_font_options_create();
+
+ // We force antialiasing and disable hinting to provide consistent
+ // typographic qualities for custom fonts on all platforms.
+ cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
+ cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
+
+ m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
+ cairo_font_options_destroy(options);
+}
+
+void FontPlatformData::setFont(cairo_t* cr) const
+{
+ ASSERT(m_scaledFont);
+
+ cairo_set_scaled_font(cr, m_scaledFont);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
new file mode 100644
index 0000000..4b4df5a
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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) 2008 Brent Fulgham
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "PlatformString.h"
+#include "StringHash.h"
+#include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+using std::min;
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
+ : m_font(RefCountedHFONT::create(font))
+ , m_size(size)
+#if PLATFORM(CG)
+ , m_cgFont(0)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(useGDI)
+{
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ SelectObject(hdc, font);
+ UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL);
+
+ ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics.");
+
+ if (bufferSize) {
+ OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize);
+
+ GetOutlineTextMetricsW(hdc, bufferSize, metrics);
+ WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName);
+
+ platformDataInit(font, size, hdc, faceName);
+
+ free(metrics);
+ }
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : m_size(size)
+#if PLATFORM(CG)
+ , m_cgFont(0)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(false)
+{
+}
+
+FontPlatformData::~FontPlatformData()
+{
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontWin.cpp b/WebCore/platform/graphics/win/FontWin.cpp
new file mode 100644
index 0000000..5e423e0
--- /dev/null
+++ b/WebCore/platform/graphics/win/FontWin.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2006, 2007, 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+#include "UniscribeController.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h,
+ int from, int to) const
+{
+ UniscribeController it(this, run);
+ it.advance(from);
+ float beforeWidth = it.runWidthSoFar();
+ it.advance(to);
+ float afterWidth = it.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.runWidthSoFar();
+ return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
+ }
+
+ return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
+}
+
+void Font::drawComplexText(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();
+ UniscribeController controller(this, run);
+ controller.advance(from);
+ float beforeWidth = controller.runWidthSoFar();
+ controller.advance(to, &glyphBuffer);
+
+ // We couldn't generate any glyphs for the run. Give up.
+ if (glyphBuffer.isEmpty())
+ return;
+
+ float afterWidth = controller.runWidthSoFar();
+
+ if (run.rtl()) {
+ controller.advance(run.length());
+ startX += controller.runWidthSoFar() - afterWidth;
+ } else
+ startX += beforeWidth;
+
+ // Draw the glyph buffer now at the starting point returned in startX.
+ FloatPoint startPoint(startX, point.y());
+ drawGlyphBuffer(context, glyphBuffer, run, startPoint);
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ UniscribeController controller(this, run);
+ controller.advance(run.length());
+ return controller.runWidthSoFar();
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ UniscribeController controller(this, run);
+ return controller.offsetForPosition(x, includePartialGlyphs);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
new file mode 100644
index 0000000..c11fc1b
--- /dev/null
+++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006, 2007, 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 "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
+ // We won't support this for now.
+ if (bufferLength > length)
+ return false;
+
+ bool haveGlyphs = false;
+ CGGlyph localGlyphBuffer[GlyphPage::size];
+ wkGetGlyphs(fontData->platformData().cgFont(), buffer, localGlyphBuffer, bufferLength);
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = localGlyphBuffer[i];
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+ return haveGlyphs;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
new file mode 100644
index 0000000..b679ced
--- /dev/null
+++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006, 2007, 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 "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
+ // We won't support this for now.
+ if (bufferLength > length)
+ return false;
+
+ bool haveGlyphs = false;
+
+ HDC dc = GetDC((HWND)0);
+ SaveDC(dc);
+ SelectObject(dc, fontData->platformData().hfont());
+
+ TEXTMETRIC tm;
+ GetTextMetrics(dc, &tm);
+
+ WORD localGlyphBuffer[GlyphPage::size * 2];
+ DWORD result = GetGlyphIndices(dc, buffer, bufferLength, localGlyphBuffer, 0);
+ bool success = result != GDI_ERROR && static_cast<unsigned>(result) == bufferLength;
+ if (success) {
+ for (unsigned i = 0; i < length; i++) {
+ Glyph glyph = localGlyphBuffer[i];
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+ }
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+
+ return haveGlyphs;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
new file mode 100644
index 0000000..5a4279a
--- /dev/null
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 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 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 "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "NotImplemented.h"
+#include "Path.h"
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include "GraphicsContextPlatformPrivateCG.h"
+
+using namespace std;
+
+namespace WebCore {
+
+static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha)
+{
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ BITMAP info;
+
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little | (hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst);
+ CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGB, bitmapInfo);
+ CGColorSpaceRelease(deviceRGB);
+
+ // Flip coords
+ CGContextTranslateCTM(context, 0, info.bmHeight);
+ CGContextScaleCTM(context, 1, -1);
+
+ // Put the HDC In advanced mode so it will honor affine transforms.
+ SetGraphicsMode(hdc, GM_ADVANCED);
+
+ return context;
+}
+
+GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha)))
+{
+ CGContextRelease(m_data->m_cgContext);
+ m_data->m_hdc = hdc;
+ setPaintingDisabled(!m_data->m_cgContext);
+ if (m_data->m_cgContext) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor());
+ setPlatformStrokeColor(strokeColor());
+ }
+}
+
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+// FIXME: Is it possible to merge getWindowsContext and createWindowsBitmap into a single API
+// suitable for all clients?
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // FIXME: Should a bitmap be created also when a shadow is set?
+ if (mayCreateBitmap && inTransparencyLayer()) {
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = dstRect.width();
+ bitmapInfo.bmiHeader.biHeight = dstRect.height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc);
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend) {
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+ }
+
+ // Make sure we can do world transforms.
+ SetGraphicsMode(bitmapDC, GM_ADVANCED);
+
+ // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -dstRect.x();
+ xform.eDy = -dstRect.y();
+ ::SetWorldTransform(bitmapDC, &xform);
+
+ return bitmapDC;
+ }
+
+ CGContextFlush(platformContext());
+ m_data->save();
+ return m_data->m_hdc;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ if (mayCreateBitmap && hdc && inTransparencyLayer()) {
+ if (dstRect.isEmpty())
+ return;
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+
+ // Need to make a CGImage out of the bitmap's pixel buffer and then draw
+ // it into our context.
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little |
+ (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst));
+ CGColorSpaceRelease(deviceRGB);
+
+ CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
+ CGContextDrawImage(m_data->m_cgContext, dstRect, image);
+
+ // Delete all our junk.
+ CGImageRelease(image);
+ CGContextRelease(bitmapContext);
+ ::DeleteDC(hdc);
+ ::DeleteObject(bitmap);
+
+ return;
+ }
+
+ m_data->restore();
+}
+
+GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
+ : m_hdc(0)
+ , m_size(size)
+{
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = m_size.width();
+ bitmapInfo.bmiHeader.biHeight = m_size.height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ m_bitmap = CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&m_bitmapBuffer), 0, 0);
+ if (!m_bitmap)
+ return;
+
+ m_hdc = CreateCompatibleDC(hdc);
+ SelectObject(m_hdc, m_bitmap);
+
+ BITMAP bmpInfo;
+ GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo);
+ m_bytesPerRow = bmpInfo.bmWidthBytes;
+ m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ SetGraphicsMode(m_hdc, GM_ADVANCED);
+}
+
+GraphicsContext::WindowsBitmap::~WindowsBitmap()
+{
+ if (!m_bitmap)
+ return;
+
+ DeleteDC(m_hdc);
+ DeleteObject(m_bitmap);
+}
+
+GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize size)
+{
+ return new WindowsBitmap(m_data->m_hdc, size);
+}
+
+void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
+{
+ RetainPtr<CGColorSpaceRef> deviceRGB(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, image->buffer(), image->bufferLength(), kCFAllocatorNull));
+ 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)
+{
+ if (!m_hdc)
+ return;
+
+ CGAffineTransform mat = transform;
+ XFORM xform;
+ xform.eM11 = mat.a;
+ xform.eM12 = mat.b;
+ xform.eM21 = mat.c;
+ xform.eM22 = mat.d;
+ xform.eDx = mat.tx;
+ xform.eDy = mat.ty;
+
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ float radius = (focusRingWidth() - 1) / 2.0f;
+ int offset = radius + focusRingOffset();
+ CGColorRef colorRef = color.isValid() ? cgColor(color) : 0;
+
+ CGMutablePathRef focusRingPath = CGPathCreateMutable();
+ const Vector<IntRect>& rects = focusRingRects();
+ unsigned rectCount = rects.size();
+ for (unsigned i = 0; i < rectCount; i++)
+ CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset));
+
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+
+ CGContextBeginPath(context);
+ CGContextAddPath(context, focusRingPath);
+
+ wkDrawFocusRing(context, colorRef, radius);
+
+ CGColorRelease(colorRef);
+
+ CGPathRelease(focusRingPath);
+
+ CGContextRestoreGState(context);
+}
+
+// Pulled from GraphicsContextCG
+static void setCGStrokeColor(CGContextRef context, const Color& color)
+{
+ CGFloat red, green, blue, alpha;
+ color.getRGBA(red, green, blue, alpha);
+ CGContextSetRGBStrokeColor(context, red, green, blue, alpha);
+}
+
+static const Color& spellingPatternColor() {
+ static const Color spellingColor(255, 0, 0);
+ return spellingColor;
+}
+
+static const Color& grammarPatternColor() {
+ static const Color grammarColor(0, 128, 0);
+ return grammarColor;
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ // These are the same for misspelling or bad grammar
+ const int patternHeight = 3; // 3 rows
+ ASSERT(cMisspellingLineThickness == patternHeight);
+ const int patternWidth = 4; // 4 pixels
+ ASSERT(patternWidth == cMisspellingLinePatternWidth);
+
+ // Make sure to draw only complete dots.
+ // NOTE: Code here used to shift the underline to the left and increase the width
+ // to make sure everything gets underlined, but that results in drawing out of
+ // bounds (e.g. when at the edge of a view) and could make it appear that the
+ // space between adjacent misspelled words was underlined.
+ // allow slightly more considering that the pattern ends with a transparent pixel
+ int widthMod = width % patternWidth;
+ if (patternWidth - widthMod > cMisspellingLinePatternGapWidth)
+ width -= widthMod;
+
+ // Draw the underline
+ CGContextRef context = platformContext();
+ CGContextSaveGState(context);
+
+ const Color& patternColor = grammar ? grammarPatternColor() : spellingPatternColor();
+ setCGStrokeColor(context, patternColor);
+
+ wkSetPatternPhaseInUserSpace(context, point);
+ CGContextSetBlendMode(context, kCGBlendModeNormal);
+
+ // 3 rows, each offset by half a pixel for blending purposes
+ const CGPoint upperPoints [] = {{point.x(), point.y() + patternHeight - 2.5 }, {point.x() + width, point.y() + patternHeight - 2.5}};
+ const CGPoint middlePoints [] = {{point.x(), point.y() + patternHeight - 1.5 }, {point.x() + width, point.y() + patternHeight - 1.5}};
+ const CGPoint lowerPoints [] = {{point.x(), point.y() + patternHeight - 0.5 }, {point.x() + width, point.y() + patternHeight - 0.5 }};
+
+ // Dash lengths for the top and bottom of the error underline are the same.
+ // These are magic.
+ static const float edge_dash_lengths[] = {2.0f, 2.0f};
+ static const float middle_dash_lengths[] = {2.76f, 1.24f};
+ static const float edge_offset = -(edge_dash_lengths[1] - 1.0f) / 2.0f;
+ static const float middle_offset = -(middle_dash_lengths[1] - 1.0f) / 2.0f;
+
+ // Line opacities. Once again, these are magic.
+ const float upperOpacity = 0.33f;
+ const float middleOpacity = 0.75f;
+ const float lowerOpacity = 0.88f;
+
+ //Top line
+ CGContextSetLineDash(context, edge_offset, edge_dash_lengths,
+ sizeof(edge_dash_lengths) / sizeof(edge_dash_lengths[0]));
+ CGContextSetAlpha(context, upperOpacity);
+ CGContextStrokeLineSegments(context, upperPoints, 2);
+
+ // Middle line
+ CGContextSetLineDash(context, middle_offset, middle_dash_lengths,
+ sizeof(middle_dash_lengths) / sizeof(middle_dash_lengths[0]));
+ CGContextSetAlpha(context, middleOpacity);
+ CGContextStrokeLineSegments(context, middlePoints, 2);
+
+ // Bottom line
+ CGContextSetLineDash(context, edge_offset, edge_dash_lengths,
+ sizeof(edge_dash_lengths) / sizeof(edge_dash_lengths[0]));
+ CGContextSetAlpha(context, lowerOpacity);
+ CGContextStrokeLineSegments(context, lowerPoints, 2);
+
+ CGContextRestoreGState(context);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
new file mode 100644
index 0000000..3dcf6ba
--- /dev/null
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 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 "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "NotImplemented.h"
+#include "Path.h"
+
+#include <cairo-win32.h>
+#include "GraphicsContextPlatformPrivateCairo.h"
+
+using namespace std;
+
+namespace WebCore {
+
+GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate)
+{
+ if (dc) {
+ cairo_surface_t* surface = cairo_win32_surface_create(dc);
+ m_data->cr = cairo_create(surface);
+ m_data->m_hdc = dc;
+ } else {
+ setPaintingDisabled(true);
+ m_data->cr = 0;
+ m_data->m_hdc = 0;
+ }
+
+ if (m_data->cr) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor());
+ setPlatformStrokeColor(strokeColor());
+ }
+}
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs
+ // to be addressed.
+ if (dstRect.isEmpty())
+ return 0;
+
+ // This is probably wrong, and definitely out of date. Pulled from old SVN
+ cairo_surface_t* surface = cairo_get_target(platformContext());
+ HDC hdc = cairo_win32_surface_get_dc(surface);
+ SaveDC(hdc);
+
+ // FIXME: We need to make sure a clip is really set on the HDC.
+ // Call SetWorldTransform to honor the current Cairo transform.
+ SetGraphicsMode(hdc, GM_ADVANCED); // We need this call for themes to honor world transforms.
+ cairo_matrix_t mat;
+ cairo_get_matrix(platformContext(), &mat);
+ XFORM xform;
+ xform.eM11 = mat.xx;
+ xform.eM12 = mat.xy;
+ xform.eM21 = mat.yx;
+ xform.eM22 = mat.yy;
+ xform.eDx = mat.x0;
+ xform.eDy = mat.y0;
+ ::SetWorldTransform(hdc, &xform);
+
+ return hdc;
+}
+
+bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // FIXME: We aren't really doing anything with the 'mayCreateBitmap' flag. This needs
+ // to be addressed.
+ if (dstRect.isEmpty())
+ return;
+
+ cairo_surface_t* surface = cairo_get_target(platformContext());
+ HDC hdc2 = cairo_win32_surface_get_dc(surface);
+ RestoreDC(hdc2, -1);
+ cairo_surface_mark_dirty(surface);
+}
+
+void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+{
+ cairo_surface_t* surface = cairo_get_target(cr);
+ HDC hdc = cairo_win32_surface_get_dc(surface);
+ SaveDC(hdc);
+
+ const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
+
+ XFORM xform;
+ xform.eM11 = matrix->xx;
+ xform.eM12 = matrix->xy;
+ xform.eM21 = matrix->yx;
+ xform.eM22 = matrix->yy;
+ xform.eDx = matrix->x0;
+ xform.eDy = matrix->y0;
+
+ ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
new file mode 100644
index 0000000..dbf9fad
--- /dev/null
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 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 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 "GraphicsContext.h"
+
+#if PLATFORM(CG)
+#include "GraphicsContextPlatformPrivateCG.h"
+#elif PLATFORM(CAIRO)
+#include "GraphicsContextPlatformPrivateCairo.h"
+#endif
+
+#include "AffineTransform.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include <wtf/MathExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+class SVGResourceImage;
+
+void GraphicsContextPlatformPrivate::save()
+{
+ if (!m_hdc)
+ return;
+ SaveDC(m_hdc);
+}
+
+void GraphicsContextPlatformPrivate::restore()
+{
+ if (!m_hdc)
+ return;
+ RestoreDC(m_hdc, -1);
+}
+
+void GraphicsContextPlatformPrivate::clip(const FloatRect& clipRect)
+{
+ if (!m_hdc)
+ return;
+ IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom());
+}
+
+void GraphicsContextPlatformPrivate::clip(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
+{
+ if (!m_hdc)
+ return;
+ XFORM xform;
+ xform.eM11 = size.width();
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = size.height();
+ xform.eDx = 0.0f;
+ xform.eDy = 0.0f;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+{
+ float radiansAngle = degreesAngle * deg2rad;
+ float cosAngle = cosf(radiansAngle);
+ float sinAngle = sinf(radiansAngle);
+ XFORM xform;
+ xform.eM11 = cosAngle;
+ xform.eM12 = -sinAngle;
+ xform.eM21 = sinAngle;
+ xform.eM22 = cosAngle;
+ xform.eDx = 0.0f;
+ xform.eDy = 0.0f;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::translate(float x , float y)
+{
+ if (!m_hdc)
+ return;
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = x;
+ xform.eDy = y;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+#if ENABLE(SVG)
+GraphicsContext* contextForImage(SVGResourceImage*)
+{
+ // FIXME: This should go in GraphicsContextCG.cpp
+ notImplemented();
+ return 0;
+}
+#endif
+
+}
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
new file mode 100644
index 0000000..c02b56e
--- /dev/null
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -0,0 +1,84 @@
+/*
+* Copyright (C) 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 "Icon.h"
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include <tchar.h>
+#include <windows.h>
+
+namespace WebCore {
+
+static const int shell32MultipleFileIconIndex = 54;
+
+Icon::Icon(HICON icon)
+ : m_hIcon(icon)
+{
+ ASSERT(icon);
+}
+
+Icon::~Icon()
+{
+ DestroyIcon(m_hIcon);
+}
+
+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>&)
+{
+ TCHAR buffer[MAX_PATH];
+ UINT length = ::GetSystemDirectory(buffer, ARRAYSIZE(buffer));
+ if (!length)
+ return 0;
+
+ if (_tcscat_s(buffer, TEXT("\\shell32.dll")))
+ return 0;
+
+ HICON hIcon;
+ if (!::ExtractIconEx(buffer, shell32MultipleFileIconIndex, 0, &hIcon, 1))
+ return 0;
+ return adoptRef(new Icon(hIcon));
+}
+
+void Icon::paint(GraphicsContext* context, const IntRect& r)
+{
+ if (context->paintingDisabled())
+ return;
+
+ HDC hdc = context->getWindowsContext(r);
+
+ DrawIconEx(hdc, r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL);
+
+ context->releaseWindowsContext(hdc, r);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp
new file mode 100644
index 0000000..752729c
--- /dev/null
+++ b/WebCore/platform/graphics/win/ImageCGWin.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2006, 2007, 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 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 "Image.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include <ApplicationServices/ApplicationServices.h>
+
+#include <windows.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
+{
+ ASSERT(bmp);
+
+ BITMAP bmpInfo;
+ GetObject(bmp, sizeof(BITMAP), &bmpInfo);
+
+ ASSERT(bmpInfo.bmBitsPixel == 32);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ CGContextRef cgContext = CGBitmapContextCreate(bmpInfo.bmBits, bmpInfo.bmWidth, bmpInfo.bmHeight,
+ 8, bmpInfo.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
+
+ GraphicsContext gc(cgContext);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy);
+
+ // Do cleanup
+ CGContextRelease(cgContext);
+ CGColorSpaceRelease(deviceRGB);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp)
+{
+ int frames = frameCount();
+ for (int i = 0; i < frames; ++i) {
+ CGImageRef image = frameAtIndex(i);
+ if (CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) {
+ size_t currentFrame = m_currentFrame;
+ m_currentFrame = i;
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp);
+ m_currentFrame = currentFrame;
+ return;
+ }
+ }
+
+ // No image of the correct size was found, fallback to drawing the current frame
+ IntSize imageSize = BitmapImage::size();
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp
new file mode 100644
index 0000000..95bb7bc
--- /dev/null
+++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 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 "Image.h"
+#include "BitmapImage.h"
+#include "GraphicsContext.h"
+#include <cairo.h>
+
+#include <windows.h>
+#include "PlatformString.h"
+
+namespace WebCore {
+
+bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size)
+{
+ ASSERT(bmp);
+
+ BITMAP bmpInfo;
+ GetObject(bmp, sizeof(BITMAP), &bmpInfo);
+
+ // If this is a 32bpp bitmap, which it always should be, we'll clear it so alpha-wise it will be visible
+ if (bmpInfo.bmBitsPixel == 32) {
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 255, bufferSize);
+ }
+
+ HDC tempDC = CreateCompatibleDC(0);
+ if (!tempDC) {
+ LOG_ERROR("Failed to create in-memory DC for Image::blit()");
+ return false;
+ }
+ SelectObject(tempDC, bmp);
+ GraphicsContext gc(tempDC);
+
+ IntSize imageSize = BitmapImage::size();
+ if (size)
+ drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy);
+ else
+ draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy);
+
+ // Do cleanup
+ DeleteDC(tempDC);
+
+ return true;
+}
+
+void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp)
+{
+ int frames = frameCount();
+ for (int i = 0; i < frames; ++i) {
+ cairo_surface_t* image = frameAtIndex(i);
+ if (cairo_image_surface_get_height(image) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast<size_t>(srcSize.width())) {
+ size_t currentFrame = m_currentFrame;
+ m_currentFrame = i;
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp);
+ m_currentFrame = currentFrame;
+ return;
+ }
+ }
+
+ // No image of the correct size was found, fallback to drawing the current frame
+ IntSize imageSize = BitmapImage::size();
+ draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/ImageWin.cpp b/WebCore/platform/graphics/win/ImageWin.cpp
new file mode 100644
index 0000000..54c5b41
--- /dev/null
+++ b/WebCore/platform/graphics/win/ImageWin.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2006, 2007, 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 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 "Image.h"
+#include "BitmapImage.h"
+
+#include "SharedBuffer.h"
+
+// This function loads resources from WebKit
+PassRefPtr<WebCore::SharedBuffer> loadResourceIntoBuffer(const char*);
+
+namespace WebCore {
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ RefPtr<SharedBuffer> buffer = loadResourceIntoBuffer(name);
+ RefPtr<BitmapImage> img = BitmapImage::create();
+ img->setData(buffer.release(), true);
+ return img.release();
+}
+
+bool BitmapImage::getHBITMAP(HBITMAP bmp)
+{
+ return getHBITMAPOfSize(bmp, 0);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/IntPointWin.cpp b/WebCore/platform/graphics/win/IntPointWin.cpp
new file mode 100644
index 0000000..a6ce0bb
--- /dev/null
+++ b/WebCore/platform/graphics/win/IntPointWin.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "IntPoint.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const POINT& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator POINT() const
+{
+ POINT p = {m_x, m_y};
+ return p;
+}
+
+IntPoint::IntPoint(const POINTS& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator POINTS() const
+{
+ POINTS p = {m_x, m_y};
+ return p;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/IntRectWin.cpp b/WebCore/platform/graphics/win/IntRectWin.cpp
new file mode 100644
index 0000000..6228be8
--- /dev/null
+++ b/WebCore/platform/graphics/win/IntRectWin.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "IntRect.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const RECT& r)
+ : m_location(IntPoint(r.left, r.top)), m_size(IntSize(r.right-r.left, r.bottom-r.top))
+{
+}
+
+IntRect::operator RECT() const
+{
+ RECT rect = { x(), y(), right(), bottom() };
+ return rect;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/IntSizeWin.cpp b/WebCore/platform/graphics/win/IntSizeWin.cpp
new file mode 100644
index 0000000..8a27cdb
--- /dev/null
+++ b/WebCore/platform/graphics/win/IntSizeWin.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "IntSize.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntSize::IntSize(const SIZE& s)
+ : m_width(s.cx)
+ , m_height(s.cy)
+{
+}
+
+IntSize::operator SIZE() const
+{
+ SIZE s = {m_width, m_height};
+ return s;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
new file mode 100644
index 0000000..cef4217
--- /dev/null
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 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"
+
+#if ENABLE(VIDEO)
+#include "MediaPlayerPrivateQuickTimeWin.h"
+
+#include "GraphicsContext.h"
+#include "KURL.h"
+#include "QTMovieWin.h"
+#include "ScrollView.h"
+#include <wtf/MathExtras.h>
+
+#if DRAW_FRAME_RATE
+#include "Font.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "Document.h"
+#include "RenderObject.h"
+#include "RenderStyle.h"
+#include "Windows.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+static const double endPointTimerInterval = 0.020;
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_seekTo(-1)
+ , m_endTime(numeric_limits<float>::infinity())
+ , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired)
+ , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::DataUnavailable)
+ , m_startedPlaying(false)
+ , m_isStreaming(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
+{
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+}
+
+void MediaPlayerPrivate::load(const String& url)
+{
+ if (!QTMovieWin::initializeQuickTime()) {
+ m_networkState = MediaPlayer::LoadFailed;
+ m_player->networkStateChanged();
+ return;
+ }
+
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::DataUnavailable) {
+ m_readyState = MediaPlayer::DataUnavailable;
+ m_player->readyStateChanged();
+ }
+ cancelSeek();
+ m_endPointTimer.stop();
+
+ m_qtMovie.set(new QTMovieWin(this));
+ m_qtMovie->load(url.characters(), url.length());
+ m_qtMovie->setVolume(m_player->m_volume);
+ m_qtMovie->setVisible(m_player->m_visible);
+}
+
+void MediaPlayerPrivate::play()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
+
+ m_qtMovie->play();
+ startEndPointTimerIfNeeded();
+}
+
+void MediaPlayerPrivate::pause()
+{
+ if (!m_qtMovie)
+ return;
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
+ m_qtMovie->pause();
+ m_endPointTimer.stop();
+}
+
+float MediaPlayerPrivate::duration() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->duration();
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return min(m_qtMovie->currentTime(), m_endTime);
+}
+
+void MediaPlayerPrivate::seek(float time)
+{
+ cancelSeek();
+
+ if (!m_qtMovie)
+ return;
+
+ if (time > duration())
+ time = duration();
+
+ m_seekTo = time;
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else
+ m_seekTimer.start(0, 0.5f);
+}
+
+void MediaPlayerPrivate::doSeek()
+{
+ float oldRate = m_qtMovie->rate();
+ m_qtMovie->setRate(0);
+ m_qtMovie->setCurrentTime(m_seekTo);
+ float timeAfterSeek = currentTime();
+ // restore playback only if not at end, othewise QTMovie will loop
+ if (timeAfterSeek < duration() && timeAfterSeek < m_endTime)
+ m_qtMovie->setRate(oldRate);
+ cancelSeek();
+}
+
+void MediaPlayerPrivate::cancelSeek()
+{
+ m_seekTo = -1;
+ m_seekTimer.stop();
+}
+
+void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ return;
+ }
+
+ if (maxTimeLoaded() >= m_seekTo)
+ doSeek();
+ else {
+ MediaPlayer::NetworkState state = networkState();
+ if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
+ cancelSeek();
+ updateStates();
+ m_player->timeChanged();
+ }
+ }
+}
+
+void MediaPlayerPrivate::setEndTime(float time)
+{
+ m_endTime = time;
+ startEndPointTimerIfNeeded();
+}
+
+void MediaPlayerPrivate::startEndPointTimerIfNeeded()
+{
+ if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive())
+ m_endPointTimer.startRepeating(endPointTimerInterval);
+}
+
+void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*)
+{
+ float time = currentTime();
+ if (time >= m_endTime) {
+ pause();
+ didEnd();
+ }
+}
+
+bool MediaPlayerPrivate::paused() const
+{
+ if (!m_qtMovie)
+ return true;
+ return m_qtMovie->rate() == 0.0f;
+}
+
+bool MediaPlayerPrivate::seeking() const
+{
+ if (!m_qtMovie)
+ return false;
+ return m_seekTo >= 0;
+}
+
+IntSize MediaPlayerPrivate::naturalSize() const
+{
+ if (!m_qtMovie)
+ return IntSize();
+ int width;
+ int height;
+ m_qtMovie->getNaturalSize(width, height);
+ return IntSize(width, height);
+}
+
+bool MediaPlayerPrivate::hasVideo() const
+{
+ // This is not used at the moment
+ return true;
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setVolume(volume);
+}
+
+void MediaPlayerPrivate::setRate(float rate)
+{
+ if (!m_qtMovie)
+ return;
+ if (!paused())
+ m_qtMovie->setRate(rate);
+}
+
+int MediaPlayerPrivate::dataRate() const
+{
+ // This is not used at the moment
+ return 0;
+}
+
+float MediaPlayerPrivate::maxTimeBuffered() const
+{
+ // rtsp streams are not buffered
+ return m_isStreaming ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeSeekable() const
+{
+ // infinite duration means live stream
+ return !isfinite(duration()) ? 0 : maxTimeLoaded();
+}
+
+float MediaPlayerPrivate::maxTimeLoaded() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->maxTimeLoaded();
+}
+
+unsigned MediaPlayerPrivate::bytesLoaded() const
+{
+ if (!m_qtMovie)
+ return 0;
+ float dur = duration();
+ float maxTime = maxTimeLoaded();
+ if (!dur)
+ return 0;
+ return totalBytes() * maxTime / dur;
+}
+
+bool MediaPlayerPrivate::totalBytesKnown() const
+{
+ return totalBytes() > 0;
+}
+
+unsigned MediaPlayerPrivate::totalBytes() const
+{
+ if (!m_qtMovie)
+ return 0;
+ return m_qtMovie->dataSize();
+}
+
+void MediaPlayerPrivate::cancelLoad()
+{
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ // Cancel the load by destroying the movie.
+ m_qtMovie.clear();
+
+ updateStates();
+}
+
+void MediaPlayerPrivate::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
+
+ if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) {
+ unsigned enabledTrackCount;
+ m_qtMovie->disableUnsupportedTracks(enabledTrackCount);
+ // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692>
+ if (!enabledTrackCount)
+ loadState = QTMovieLoadStateError;
+ }
+
+ // "Loaded" is reserved for fully buffered movies, never the case when streaming
+ if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
+ if (m_networkState < MediaPlayer::Loaded)
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
+ if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
+ m_networkState = MediaPlayer::LoadedFirstFrame;
+ m_readyState = MediaPlayer::CanPlayThrough;
+ } else if (loadState >= QTMovieLoadStatePlayable) {
+ if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking())
+ m_networkState = MediaPlayer::LoadedFirstFrame;
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable;
+ } else if (loadState >= QTMovieLoadStateLoaded) {
+ if (m_networkState < MediaPlayer::LoadedMetaData)
+ m_networkState = MediaPlayer::LoadedMetaData;
+ m_readyState = MediaPlayer::DataUnavailable;
+ } else if (loadState > QTMovieLoadStateError) {
+ if (m_networkState < MediaPlayer::Loading)
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::DataUnavailable;
+ } else {
+ m_networkState = MediaPlayer::LoadFailed;
+ m_readyState = MediaPlayer::DataUnavailable;
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::DataUnavailable;
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+}
+
+
+void MediaPlayerPrivate::didEnd()
+{
+ m_endPointTimer.stop();
+ m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::setRect(const IntRect& r)
+{
+ if (m_qtMovie)
+ m_qtMovie->setSize(r.width(), r.height());
+}
+
+void MediaPlayerPrivate::setVisible(bool b)
+{
+ if (!m_qtMovie)
+ return;
+ m_qtMovie->setVisible(b);
+}
+
+void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
+{
+ if (p->paintingDisabled() || !m_qtMovie)
+ return;
+ HDC hdc = p->getWindowsContext(r);
+ m_qtMovie->paint(hdc, r.x(), r.y());
+ p->releaseWindowsContext(hdc, r);
+
+#if DRAW_FRAME_RATE
+ if (m_frameCountWhilePlaying > 10) {
+ Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL;
+ Document* document = frame ? frame->document() : NULL;
+ RenderObject* renderer = document ? document->renderer() : NULL;
+ RenderStyle* styleToUse = renderer ? renderer->style() : NULL;
+ if (styleToUse) {
+ double frameRate = (m_frameCountWhilePlaying - 1) / (0.001 * ( m_startedPlaying ? (GetTickCount() - m_timeStartedPlaying) :
+ (m_timeStoppedPlaying - m_timeStartedPlaying) ));
+ String text = String::format("%1.2f", frameRate);
+ TextRun textRun(text.characters(), text.length());
+ const Color color(255, 0, 0);
+ p->save();
+ p->translate(r.x(), r.y() + r.height());
+ p->setFont(styleToUse->font());
+ p->setStrokeColor(color);
+ p->setStrokeStyle(SolidStroke);
+ p->setStrokeThickness(1.0f);
+ p->setFillColor(color);
+ p->drawText(textRun, IntPoint(2, -3));
+ p->restore();
+ }
+ }
+#endif
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
+{
+ unsigned count = QTMovieWin::countSupportedTypes();
+ for (unsigned n = 0; n < count; n++) {
+ const UChar* character;
+ unsigned len;
+ QTMovieWin::getSupportedType(n, character, len);
+ if (len)
+ types.add(String(character, len));
+ }
+}
+
+bool MediaPlayerPrivate::isAvailable()
+{
+ return QTMovieWin::initializeQuickTime();
+}
+
+void MediaPlayerPrivate::movieEnded(QTMovieWin* movie)
+{
+ ASSERT(m_qtMovie.get() == movie);
+ didEnd();
+}
+
+void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie)
+{
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+}
+
+void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie)
+{
+ ASSERT(m_qtMovie.get() == movie);
+ updateStates();
+ m_player->timeChanged();
+}
+
+void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie)
+{
+ ASSERT(m_qtMovie.get() == movie);
+#if DRAW_FRAME_RATE
+ if (m_startedPlaying) {
+ m_frameCountWhilePlaying++;
+ // to eliminate preroll costs from our calculation,
+ // our frame rate calculation excludes the first frame drawn after playback starts
+ if (1==m_frameCountWhilePlaying)
+ m_timeStartedPlaying = GetTickCount();
+ }
+#endif
+ m_player->repaint();
+}
+
+}
+
+#endif
+
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
new file mode 100644
index 0000000..c4c893c
--- /dev/null
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaPlayerPrivateQTKit_h
+#define MediaPlayerPrivateQTKit_h
+
+#if ENABLE(VIDEO)
+
+#include "MediaPlayer.h"
+#include "Timer.h"
+#include <QTMovieWin.h>
+#include <wtf/OwnPtr.h>
+
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
+namespace WebCore {
+
+class GraphicsContext;
+class IntSize;
+class IntRect;
+class String;
+
+class MediaPlayerPrivate : QTMovieWinClient, 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 { return m_networkState; }
+ MediaPlayer::ReadyState readyState() const { return m_readyState; }
+
+ float maxTimeBuffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ bool totalBytesKnown() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+ void setRect(const IntRect&);
+
+ void loadStateChanged();
+ void didEnd();
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ static void getSupportedTypes(HashSet<String>& types);
+ static bool isAvailable();
+
+private:
+ void updateStates();
+ void doSeek();
+ void cancelSeek();
+ void seekTimerFired(Timer<MediaPlayerPrivate>*);
+ void endPointTimerFired(Timer<MediaPlayerPrivate>*);
+ float maxTimeLoaded() const;
+ void startEndPointTimerIfNeeded();
+
+ virtual void movieEnded(QTMovieWin*);
+ virtual void movieLoadStateChanged(QTMovieWin*);
+ virtual void movieTimeChanged(QTMovieWin*);
+ virtual void movieNewImageAvailable(QTMovieWin*);
+
+ MediaPlayer* m_player;
+ OwnPtr<QTMovieWin> m_qtMovie;
+ float m_seekTo;
+ float m_endTime;
+ Timer<MediaPlayerPrivate> m_seekTimer;
+ Timer<MediaPlayerPrivate> m_endPointTimer;
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+ bool m_startedPlaying;
+ bool m_isStreaming;
+#if DRAW_FRAME_RATE
+ int m_frameCountWhilePlaying;
+ int m_timeStartedPlaying;
+ int m_timeStoppedPlaying;
+#endif
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/platform/graphics/win/OpenTypeUtilities.cpp b/WebCore/platform/graphics/win/OpenTypeUtilities.cpp
new file mode 100644
index 0000000..1951320
--- /dev/null
+++ b/WebCore/platform/graphics/win/OpenTypeUtilities.cpp
@@ -0,0 +1,387 @@
+/*
+ * 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 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 "OpenTypeUtilities.h"
+
+#include "SharedBuffer.h"
+
+namespace WebCore {
+
+struct BigEndianUShort {
+ operator unsigned short() const { return (v & 0x00ff) << 8 | v >> 8; }
+ BigEndianUShort(unsigned short u) : v((u & 0x00ff) << 8 | u >> 8) { }
+ unsigned short v;
+};
+
+struct BigEndianULong {
+ operator unsigned() const { return (v & 0xff) << 24 | (v & 0xff00) << 8 | (v & 0xff0000) >> 8 | v >> 24; }
+ BigEndianULong(unsigned u) : v((u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | u >> 24) { }
+ unsigned v;
+};
+
+#pragma pack(1)
+
+struct EOTPrefix {
+ unsigned eotSize;
+ unsigned fontDataSize;
+ unsigned version;
+ unsigned flags;
+ UInt8 fontPANOSE[10];
+ UInt8 charset;
+ UInt8 italic;
+ unsigned weight;
+ unsigned short fsType;
+ unsigned short magicNumber;
+ unsigned unicodeRange[4];
+ unsigned codePageRange[2];
+ unsigned checkSumAdjustment;
+ unsigned reserved[4];
+ unsigned short padding1;
+};
+
+struct TableDirectoryEntry {
+ BigEndianULong tag;
+ BigEndianULong checkSum;
+ BigEndianULong offset;
+ BigEndianULong length;
+};
+
+struct sfntHeader {
+ Fixed version;
+ BigEndianUShort numTables;
+ BigEndianUShort searchRange;
+ BigEndianUShort entrySelector;
+ BigEndianUShort rangeShift;
+ TableDirectoryEntry tables[1];
+};
+
+struct OS2Table {
+ BigEndianUShort version;
+ BigEndianUShort avgCharWidth;
+ BigEndianUShort weightClass;
+ BigEndianUShort widthClass;
+ BigEndianUShort fsType;
+ BigEndianUShort subscriptXSize;
+ BigEndianUShort subscriptYSize;
+ BigEndianUShort subscriptXOffset;
+ BigEndianUShort subscriptYOffset;
+ BigEndianUShort superscriptXSize;
+ BigEndianUShort superscriptYSize;
+ BigEndianUShort superscriptXOffset;
+ BigEndianUShort superscriptYOffset;
+ BigEndianUShort strikeoutSize;
+ BigEndianUShort strikeoutPosition;
+ BigEndianUShort familyClass;
+ UInt8 panose[10];
+ BigEndianULong unicodeRange[4];
+ UInt8 vendID[4];
+ BigEndianUShort fsSelection;
+ BigEndianUShort firstCharIndex;
+ BigEndianUShort lastCharIndex;
+ BigEndianUShort typoAscender;
+ BigEndianUShort typoDescender;
+ BigEndianUShort typoLineGap;
+ BigEndianUShort winAscent;
+ BigEndianUShort winDescent;
+ BigEndianULong codePageRange[2];
+ BigEndianUShort xHeight;
+ BigEndianUShort capHeight;
+ BigEndianUShort defaultChar;
+ BigEndianUShort breakChar;
+ BigEndianUShort maxContext;
+};
+
+struct headTable {
+ Fixed version;
+ Fixed fontRevision;
+ BigEndianULong checkSumAdjustment;
+ BigEndianULong magicNumber;
+ BigEndianUShort flags;
+ BigEndianUShort unitsPerEm;
+ long long created;
+ long long modified;
+ BigEndianUShort xMin;
+ BigEndianUShort xMax;
+ BigEndianUShort yMin;
+ BigEndianUShort yMax;
+ BigEndianUShort macStyle;
+ BigEndianUShort lowestRectPPEM;
+ BigEndianUShort fontDirectionHint;
+ BigEndianUShort indexToLocFormat;
+ BigEndianUShort glyphDataFormat;
+};
+
+struct nameRecord {
+ BigEndianUShort platformID;
+ BigEndianUShort encodingID;
+ BigEndianUShort languageID;
+ BigEndianUShort nameID;
+ BigEndianUShort length;
+ BigEndianUShort offset;
+};
+
+struct nameTable {
+ BigEndianUShort format;
+ BigEndianUShort count;
+ BigEndianUShort stringOffset;
+ nameRecord nameRecords[1];
+};
+
+#pragma pack()
+
+static void appendBigEndianStringToEOTHeader(Vector<UInt8, 512>& eotHeader, const BigEndianUShort* string, unsigned short length)
+{
+ size_t size = eotHeader.size();
+ eotHeader.resize(size + length + 2 * sizeof(unsigned short));
+ UChar* dst = reinterpret_cast<UChar*>(eotHeader.data() + size);
+ unsigned i = 0;
+ dst[i++] = length;
+ unsigned numCharacters = length / 2;
+ for (unsigned j = 0; j < numCharacters; j++)
+ dst[i++] = string[j];
+ dst[i] = 0;
+}
+
+bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
+{
+ overlayDst = 0;
+ overlaySrc = 0;
+ overlayLength = 0;
+
+ size_t dataLength = fontData->size();
+ const char* data = fontData->data();
+
+ eotHeader.resize(sizeof(EOTPrefix));
+ EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(eotHeader.data());
+
+ prefix->fontDataSize = dataLength;
+ prefix->version = 0x00020001;
+ prefix->flags = 0;
+
+ if (dataLength < offsetof(sfntHeader, tables))
+ return false;
+
+ const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data);
+
+ if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(TableDirectoryEntry))
+ return false;
+
+ bool haveOS2 = false;
+ bool haveHead = false;
+ bool haveName = false;
+
+ const BigEndianUShort* familyName = 0;
+ unsigned short familyNameLength = 0;
+ const BigEndianUShort* subfamilyName = 0;
+ unsigned short subfamilyNameLength = 0;
+ const BigEndianUShort* fullName = 0;
+ unsigned short fullNameLength = 0;
+ const BigEndianUShort* versionString = 0;
+ unsigned short versionStringLength = 0;
+
+ for (unsigned i = 0; i < sfnt->numTables; i++) {
+ unsigned tableOffset = sfnt->tables[i].offset;
+ unsigned tableLength = sfnt->tables[i].length;
+
+ if (dataLength < tableOffset || dataLength < tableLength || dataLength < tableOffset + tableLength)
+ return false;
+
+ unsigned tableTag = sfnt->tables[i].tag;
+ switch (tableTag) {
+ case 'OS/2':
+ {
+ if (dataLength < tableOffset + sizeof(OS2Table))
+ return false;
+
+ haveOS2 = true;
+ const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data + tableOffset);
+ for (unsigned j = 0; j < 10; j++)
+ prefix->fontPANOSE[j] = OS2->panose[j];
+ prefix->italic = OS2->fsSelection & 0x01;
+ prefix->weight = OS2->weightClass;
+ // FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
+ // Since ATS does not enforce this on Mac OS X, we do not enforce it either.
+ prefix->fsType = 0;
+ for (unsigned j = 0; j < 4; j++)
+ prefix->unicodeRange[j] = OS2->unicodeRange[j];
+ for (unsigned j = 0; j < 2; j++)
+ prefix->codePageRange[j] = OS2->codePageRange[j];
+ break;
+ }
+ case 'head':
+ {
+ if (dataLength < tableOffset + sizeof(headTable))
+ return false;
+
+ haveHead = true;
+ const headTable* head = reinterpret_cast<const headTable*>(data + tableOffset);
+ prefix->checkSumAdjustment = head->checkSumAdjustment;
+ break;
+ }
+ case 'name':
+ {
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords))
+ return false;
+
+ haveName = true;
+ const nameTable* name = reinterpret_cast<const nameTable*>(data + tableOffset);
+ for (int j = 0; j < name->count; j++) {
+ if (dataLength < tableOffset + offsetof(nameTable, nameRecords) + (j + 1) * sizeof(nameRecord))
+ return false;
+ if (name->nameRecords[j].platformID == 3 && name->nameRecords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) {
+ if (dataLength < tableOffset + name->stringOffset + name->nameRecords[j].offset + name->nameRecords[j].length)
+ return false;
+
+ unsigned short nameLength = name->nameRecords[j].length;
+ const BigEndianUShort* nameString = reinterpret_cast<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRecords[j].offset);
+
+ switch (name->nameRecords[j].nameID) {
+ case 1:
+ familyNameLength = nameLength;
+ familyName = nameString;
+ break;
+ case 2:
+ subfamilyNameLength = nameLength;
+ subfamilyName = nameString;
+ break;
+ case 4:
+ fullNameLength = nameLength;
+ fullName = nameString;
+ break;
+ case 5:
+ versionStringLength = nameLength;
+ versionString = nameString;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (haveOS2 && haveHead && haveName)
+ break;
+ }
+
+ prefix->charset = DEFAULT_CHARSET;
+ prefix->magicNumber = 0x504c;
+ prefix->reserved[0] = 0;
+ prefix->reserved[1] = 0;
+ prefix->reserved[2] = 0;
+ prefix->reserved[3] = 0;
+ prefix->padding1 = 0;
+
+ appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength);
+ appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLength);
+ appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLength);
+
+ // If possible, ensure that the family name is a prefix of the full name.
+ if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) {
+ overlaySrc = reinterpret_cast<const char*>(fullName) - data;
+ overlayDst = reinterpret_cast<const char*>(familyName) - data;
+ overlayLength = familyNameLength;
+ }
+
+ appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength);
+
+ unsigned short padding = 0;
+ eotHeader.append(reinterpret_cast<UInt8*>(&padding), sizeof(padding));
+
+ prefix->eotSize = eotHeader.size() + fontData->size();
+
+ return true;
+}
+
+HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName)
+{
+ size_t originalDataSize = fontData->size();
+ const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data());
+
+ unsigned t;
+ for (t = 0; t < sfnt->numTables; ++t) {
+ if (sfnt->tables[t].tag == 'name')
+ break;
+ }
+ if (t == sfnt->numTables)
+ return 0;
+
+ const int nameRecordCount = 5;
+
+ // Rounded up to a multiple of 4 to simplify the checksum calculation.
+ size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4;
+
+ Vector<char> rewrittenFontData(fontData->size() + nameTableSize);
+ char* data = rewrittenFontData.data();
+ memcpy(data, fontData->data(), originalDataSize);
+
+ // Make the table directory entry point to the new 'name' table.
+ sfntHeader* rewrittenSfnt = reinterpret_cast<sfntHeader*>(data);
+ rewrittenSfnt->tables[t].length = nameTableSize;
+ rewrittenSfnt->tables[t].offset = originalDataSize;
+
+ // Write the new 'name' table after the original font data.
+ nameTable* name = reinterpret_cast<nameTable*>(data + originalDataSize);
+ name->format = 0;
+ name->count = nameRecordCount;
+ name->stringOffset = offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord);
+ for (unsigned i = 0; i < nameRecordCount; ++i) {
+ name->nameRecords[i].platformID = 3;
+ name->nameRecords[i].encodingID = 1;
+ name->nameRecords[i].languageID = 0x0409;
+ name->nameRecords[i].offset = 0;
+ name->nameRecords[i].length = fontName.length() * sizeof(UChar);
+ }
+
+ // The required 'name' record types: Family, Style, Unique, Full and PostScript.
+ name->nameRecords[0].nameID = 1;
+ name->nameRecords[1].nameID = 2;
+ name->nameRecords[2].nameID = 3;
+ name->nameRecords[3].nameID = 4;
+ name->nameRecords[4].nameID = 6;
+
+ for (unsigned i = 0; i < fontName.length(); ++i)
+ reinterpret_cast<BigEndianUShort*>(data + originalDataSize + name->stringOffset)[i] = fontName[i];
+
+ // Update the table checksum in the directory entry.
+ rewrittenSfnt->tables[t].checkSum = 0;
+ for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i)
+ rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum + reinterpret_cast<BigEndianULong*>(name)[i];
+
+ DWORD numFonts = 0;
+ HANDLE fontHandle = AddFontMemResourceEx(data, originalDataSize + nameTableSize, 0, &numFonts);
+
+ if (fontHandle && numFonts != 1) {
+ RemoveFontMemResourceEx(fontHandle);
+ return 0;
+ }
+
+ return fontHandle;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/OpenTypeUtilities.h b/WebCore/platform/graphics/win/OpenTypeUtilities.h
new file mode 100644
index 0000000..ab35551
--- /dev/null
+++ b/WebCore/platform/graphics/win/OpenTypeUtilities.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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OpenTypeUtilities_h
+#define OpenTypeUtilities_h
+
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+
+bool getEOTHeader(SharedBuffer* fontData, Vector<UInt8, 512>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength);
+HANDLE renameAndActivateFont(SharedBuffer*, const String&);
+
+} // namespace WebCore
+
+#endif // OpenTypeUtilities_h
diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp
new file mode 100644
index 0000000..8eee41b
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2007 Apple Computer, 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 <windows.h>
+
+#include "QTMovieWin.h"
+
+// Put Movies.h first so build failures here point clearly to QuickTime
+#include <Movies.h>
+#include <QuickTimeComponents.h>
+#include <GXMath.h>
+#include <QTML.h>
+
+#include "QTMovieWinTimer.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+static const long minimumQuickTimeVersion = 0x07300000; // 7.3
+
+// Resizing GWorlds is slow, give them a minimum size so size of small
+// videos can be animated smoothly
+static const int cGWorldMinWidth = 640;
+static const int cGWorldMinHeight = 360;
+
+static const float cNonContinuousTimeChange = 0.2f;
+
+union UppParam {
+ long longValue;
+ void* ptr;
+};
+
+static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0;
+static HashSet<QTMovieWinPrivate*>* gTaskList;
+static Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
+
+static void updateTaskTimer(int maxInterval = 1000)
+{
+ if (!gTaskList->size()) {
+ stopSharedTimer();
+ return;
+ }
+
+ long intervalInMS;
+ QTGetTimeUntilNextTask(&intervalInMS, 1000);
+ if (intervalInMS > maxInterval)
+ intervalInMS = maxInterval;
+ setSharedTimerFireDelay(static_cast<float>(intervalInMS) / 1000);
+}
+
+class QTMovieWinPrivate : Noncopyable {
+public:
+ QTMovieWinPrivate();
+ ~QTMovieWinPrivate();
+ void task();
+ void startTask();
+ void endTask();
+
+ void createMovieController();
+ void registerDrawingCallback();
+ void drawingComplete();
+ void updateGWorld();
+ void createGWorld();
+ void deleteGWorld();
+ void clearGWorld();
+
+ void setSize(int, int);
+
+ QTMovieWin* m_movieWin;
+ Movie m_movie;
+ MovieController m_movieController;
+ bool m_tasking;
+ QTMovieWinClient* m_client;
+ long m_loadState;
+ bool m_ended;
+ bool m_seeking;
+ float m_lastMediaTime;
+ double m_lastLoadStateCheckTime;
+ int m_width;
+ int m_height;
+ bool m_visible;
+ GWorldPtr m_gWorld;
+ int m_gWorldWidth;
+ int m_gWorldHeight;
+ GWorldPtr m_savedGWorld;
+ long m_loadError;
+};
+
+QTMovieWinPrivate::QTMovieWinPrivate()
+ : m_movieWin(0)
+ , m_movie(0)
+ , m_movieController(0)
+ , m_tasking(false)
+ , m_client(0)
+ , m_loadState(0)
+ , m_ended(false)
+ , m_seeking(false)
+ , m_lastMediaTime(0)
+ , m_lastLoadStateCheckTime(0)
+ , m_width(0)
+ , m_height(0)
+ , m_visible(false)
+ , m_gWorld(0)
+ , m_gWorldWidth(0)
+ , m_gWorldHeight(0)
+ , m_savedGWorld(0)
+ , m_loadError(0)
+{
+}
+
+QTMovieWinPrivate::~QTMovieWinPrivate()
+{
+ endTask();
+ if (m_gWorld)
+ deleteGWorld();
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
+ if (m_movie)
+ DisposeMovie(m_movie);
+}
+
+static void taskTimerFired()
+{
+ // The hash content might change during task()
+ Vector<QTMovieWinPrivate*> tasks;
+ copyToVector(*gTaskList, tasks);
+ size_t count = tasks.size();
+ for (unsigned n = 0; n < count; ++n)
+ tasks[n]->task();
+
+ updateTaskTimer();
+}
+
+void QTMovieWinPrivate::startTask()
+{
+ if (m_tasking)
+ return;
+ if (!gTaskList)
+ gTaskList = new HashSet<QTMovieWinPrivate*>;
+ gTaskList->add(this);
+ m_tasking = true;
+ updateTaskTimer();
+}
+
+void QTMovieWinPrivate::endTask()
+{
+ if (!m_tasking)
+ return;
+ gTaskList->remove(this);
+ m_tasking = false;
+ updateTaskTimer();
+}
+
+void QTMovieWinPrivate::task()
+{
+ ASSERT(m_tasking);
+
+ if (!m_loadError) {
+ if (m_movieController)
+ MCIdle(m_movieController);
+ else
+ MoviesTask(m_movie, 0);
+ }
+
+ // GetMovieLoadState documentation says that you should not call it more often than every quarter of a second.
+ if (systemTime() >= m_lastLoadStateCheckTime + 0.25 || m_loadError) {
+ // If load fails QT's load state is kMovieLoadStateComplete.
+ // This is different from QTKit API and seems strange.
+ long loadState = m_loadError ? kMovieLoadStateError : GetMovieLoadState(m_movie);
+ if (loadState != m_loadState) {
+
+ // we only need to erase the movie gworld when the load state changes to loaded while it
+ // is visible as the gworld is destroyed/created when visibility changes
+ if (loadState >= QTMovieLoadStateLoaded && m_loadState < QTMovieLoadStateLoaded && m_visible)
+ clearGWorld();
+
+ m_loadState = loadState;
+ if (!m_movieController && m_loadState >= kMovieLoadStateLoaded)
+ createMovieController();
+ m_client->movieLoadStateChanged(m_movieWin);
+ }
+ m_lastLoadStateCheckTime = systemTime();
+ }
+
+ bool ended = !!IsMovieDone(m_movie);
+ if (ended != m_ended) {
+ m_ended = ended;
+ if (m_client && ended)
+ m_client->movieEnded(m_movieWin);
+ }
+
+ float time = m_movieWin->currentTime();
+ if (time < m_lastMediaTime || time >= m_lastMediaTime + cNonContinuousTimeChange || m_seeking) {
+ m_seeking = false;
+ if (m_client)
+ m_client->movieTimeChanged(m_movieWin);
+ }
+ m_lastMediaTime = time;
+
+ if (m_loadError)
+ endTask();
+}
+
+void QTMovieWinPrivate::createMovieController()
+{
+ Rect bounds;
+ long flags;
+
+ if (!m_movie)
+ return;
+
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
+
+ GetMovieBox(m_movie, &bounds);
+ flags = mcTopLeftMovie | mcNotVisible;
+ m_movieController = NewMovieController(m_movie, &bounds, flags);
+ if (!m_movieController)
+ return;
+
+ MCSetControllerPort(m_movieController, m_gWorld);
+ MCSetControllerAttached(m_movieController, false);
+}
+
+void QTMovieWinPrivate::registerDrawingCallback()
+{
+ UppParam param;
+ param.ptr = this;
+ SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, gMovieDrawingCompleteUPP, param.longValue);
+}
+
+void QTMovieWinPrivate::drawingComplete()
+{
+ if (!m_gWorld || m_loadState < kMovieLoadStateLoaded)
+ return;
+ m_client->movieNewImageAvailable(m_movieWin);
+}
+
+void QTMovieWinPrivate::updateGWorld()
+{
+ bool shouldBeVisible = m_visible;
+ if (!m_height || !m_width)
+ shouldBeVisible = false;
+
+ if (shouldBeVisible && !m_gWorld)
+ createGWorld();
+ else if (!shouldBeVisible && m_gWorld)
+ deleteGWorld();
+ else if (m_gWorld && (m_width > m_gWorldWidth || m_height > m_gWorldHeight)) {
+ // need a bigger, better gWorld
+ deleteGWorld();
+ createGWorld();
+ }
+}
+
+void QTMovieWinPrivate::createGWorld()
+{
+ ASSERT(!m_gWorld);
+ if (!m_movie)
+ return;
+
+ m_gWorldWidth = max(cGWorldMinWidth, m_width);
+ m_gWorldHeight = max(cGWorldMinHeight, m_height);
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_gWorldWidth;
+ bounds.bottom = m_gWorldHeight;
+ OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, NULL, NULL, NULL);
+ if (err)
+ return;
+ GetMovieGWorld(m_movie, &m_savedGWorld, 0);
+ if (m_movieController)
+ MCSetControllerPort(m_movieController, m_gWorld);
+ SetMovieGWorld(m_movie, m_gWorld, 0);
+ bounds.right = m_width;
+ bounds.bottom = m_height;
+ if (m_movieController)
+ MCSetControllerBoundsRect(m_movieController, &bounds);
+ SetMovieBox(m_movie, &bounds);
+}
+
+void QTMovieWinPrivate::clearGWorld()
+{
+ if (!m_movie||!m_gWorld)
+ return;
+
+ GrafPtr savePort;
+ GetPort(&savePort);
+ MacSetPort((GrafPtr)m_gWorld);
+
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = m_gWorldWidth;
+ bounds.bottom = m_gWorldHeight;
+ EraseRect(&bounds);
+
+ MacSetPort(savePort);
+}
+
+
+void QTMovieWinPrivate::setSize(int width, int height)
+{
+ if (m_width == width && m_height == height)
+ return;
+ m_width = width;
+ m_height = height;
+ if (!m_movie)
+ return;
+ Rect bounds;
+ bounds.top = 0;
+ bounds.left = 0;
+ bounds.right = width;
+ bounds.bottom = height;
+ if (m_movieController)
+ MCSetControllerBoundsRect(m_movieController, &bounds);
+ SetMovieBox(m_movie, &bounds);
+ updateGWorld();
+}
+
+void QTMovieWinPrivate::deleteGWorld()
+{
+ ASSERT(m_gWorld);
+ if (m_movieController)
+ MCSetControllerPort(m_movieController, m_savedGWorld);
+ if (m_movie)
+ SetMovieGWorld(m_movie, m_savedGWorld, 0);
+ m_savedGWorld = 0;
+ DisposeGWorld(m_gWorld);
+ m_gWorld = 0;
+ m_gWorldWidth = 0;
+ m_gWorldHeight = 0;
+}
+
+
+QTMovieWin::QTMovieWin(QTMovieWinClient* client)
+ : m_private(new QTMovieWinPrivate())
+{
+ m_private->m_movieWin = this;
+ m_private->m_client = client;
+ initializeQuickTime();
+}
+
+QTMovieWin::~QTMovieWin()
+{
+ delete m_private;
+}
+
+void QTMovieWin::play()
+{
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)GetMoviePreferredRate(m_private->m_movie));
+ else
+ StartMovie(m_private->m_movie);
+ m_private->startTask();
+}
+
+void QTMovieWin::pause()
+{
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPlay, 0);
+ else
+ StopMovie(m_private->m_movie);
+ updateTaskTimer();
+}
+
+float QTMovieWin::rate() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ return FixedToFloat(GetMovieRate(m_private->m_movie));
+}
+
+void QTMovieWin::setRate(float rate)
+{
+ if (!m_private->m_movie)
+ return;
+ if (m_private->m_movieController)
+ MCDoAction(m_private->m_movieController, mcActionPrerollAndPlay, (void *)FloatToFixed(rate));
+ else
+ SetMovieRate(m_private->m_movie, FloatToFixed(rate));
+ updateTaskTimer();
+}
+
+float QTMovieWin::duration() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val = GetMovieDuration(m_private->m_movie);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+float QTMovieWin::currentTime() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val = GetMovieTime(m_private->m_movie, 0);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+void QTMovieWin::setCurrentTime(float time) const
+{
+ if (!m_private->m_movie)
+ return;
+ m_private->m_seeking = true;
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ if (m_private->m_movieController){
+ QTRestartAtTimeRecord restart = { time * scale , 0 };
+ MCDoAction(m_private->m_movieController, mcActionRestartAtTime, (void *)&restart);
+ } else
+ SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale));
+ updateTaskTimer();
+}
+
+void QTMovieWin::setVolume(float volume)
+{
+ if (!m_private->m_movie)
+ return;
+ SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256));
+}
+
+unsigned QTMovieWin::dataSize() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));
+}
+
+float QTMovieWin::maxTimeLoaded() const
+{
+ if (!m_private->m_movie)
+ return 0;
+ TimeValue val;
+ GetMaxLoadedTimeInMovie(m_private->m_movie, &val);
+ TimeScale scale = GetMovieTimeScale(m_private->m_movie);
+ return static_cast<float>(val) / scale;
+}
+
+long QTMovieWin::loadState() const
+{
+ return m_private->m_loadState;
+}
+
+void QTMovieWin::getNaturalSize(int& width, int& height)
+{
+ Rect rect = { 0, };
+
+ if (m_private->m_movie)
+ GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
+ width = rect.right;
+ height = rect.bottom;
+}
+
+void QTMovieWin::setSize(int width, int height)
+{
+ m_private->setSize(width, height);
+ updateTaskTimer(0);
+}
+
+void QTMovieWin::setVisible(bool b)
+{
+ m_private->m_visible = b;
+ m_private->updateGWorld();
+}
+
+void QTMovieWin::paint(HDC hdc, int x, int y)
+{
+ if (!m_private->m_gWorld)
+ return;
+
+ HDC hdcSrc = static_cast<HDC>(GetPortHDC(reinterpret_cast<GrafPtr>(m_private->m_gWorld)));
+ if (!hdcSrc)
+ return;
+
+ // FIXME: If we could determine the movie has no alpha, we could use BitBlt for those cases, which might be faster.
+ BLENDFUNCTION blendFunction;
+ blendFunction.BlendOp = AC_SRC_OVER;
+ blendFunction.BlendFlags = 0;
+ blendFunction.SourceConstantAlpha = 255;
+ blendFunction.AlphaFormat = AC_SRC_ALPHA;
+ AlphaBlend(hdc, x, y, m_private->m_width, m_private->m_height, hdcSrc,
+ 0, 0, m_private->m_width, m_private->m_height, blendFunction);
+}
+
+void QTMovieWin::load(const UChar* url, int len)
+{
+ if (m_private->m_movie) {
+ m_private->endTask();
+ if (m_private->m_gWorld)
+ m_private->deleteGWorld();
+ if (m_private->m_movieController)
+ DisposeMovieController(m_private->m_movieController);
+ m_private->m_movieController = 0;
+ DisposeMovie(m_private->m_movie);
+ m_private->m_movie = 0;
+ }
+
+ // Define a property array for NewMovieFromProperties. 8 should be enough for our needs.
+ QTNewMoviePropertyElement movieProps[8];
+ ItemCount moviePropCount = 0;
+
+ bool boolTrue = true;
+
+ // Create a URL data reference of type CFURL
+ CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len);
+
+ // Disable streaming support for now.
+ if (CFStringHasPrefix(urlStringRef, CFSTR("rtsp:"))) {
+ m_private->m_loadError = noMovieFound;
+ goto end;
+ }
+
+ CFURLRef urlRef = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0);
+
+ // Add the movie data location to the property array
+ movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation;
+ movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL;
+ movieProps[moviePropCount].propValueSize = sizeof(urlRef);
+ movieProps[moviePropCount].propValueAddress = &urlRef;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_AsyncOK;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
+ movieProps[moviePropCount].propID = kQTNewMoviePropertyID_Active;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty;
+ movieProps[moviePropCount].propID = kQTNewMoviePropertyID_DontInteractWithUser;
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = '!url';
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation;
+ movieProps[moviePropCount].propID = 'site';
+ movieProps[moviePropCount].propValueSize = sizeof(boolTrue);
+ movieProps[moviePropCount].propValueAddress = &boolTrue;
+ movieProps[moviePropCount].propStatus = 0;
+ moviePropCount++;
+
+ m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie);
+
+ CFRelease(urlRef);
+end:
+ m_private->startTask();
+ // get the load fail callback quickly
+ if (m_private->m_loadError)
+ updateTaskTimer(0);
+ else
+ m_private->registerDrawingCallback();
+
+ CFRelease(urlStringRef);
+}
+
+void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount)
+{
+ if (!m_private->m_movie) {
+ enabledTrackCount = 0;
+ return;
+ }
+
+ static HashSet<OSType>* allowedTrackTypes = 0;
+ if (!allowedTrackTypes) {
+ allowedTrackTypes = new HashSet<OSType>;
+ allowedTrackTypes->add(VideoMediaType);
+ allowedTrackTypes->add(SoundMediaType);
+ allowedTrackTypes->add(TextMediaType);
+ allowedTrackTypes->add(BaseMediaType);
+ allowedTrackTypes->add('clcp'); // Closed caption
+ allowedTrackTypes->add('sbtl'); // Subtitle
+ }
+
+ long trackCount = GetMovieTrackCount(m_private->m_movie);
+ enabledTrackCount = trackCount;
+
+ // Track indexes are 1-based. yuck. These things must descend from old-
+ // school mac resources or something.
+ for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) {
+ // Grab the track at the current index. If there isn't one there, then
+ // we can move onto the next one.
+ Track currentTrack = GetMovieIndTrack(m_private->m_movie, trackIndex);
+ if (!currentTrack)
+ continue;
+
+ // Check to see if the track is disabled already, we should move along.
+ // We don't need to re-disable it.
+ if (!GetTrackEnabled(currentTrack))
+ continue;
+
+ // Grab the track's media. We're going to check to see if we need to
+ // disable the tracks. They could be unsupported.
+ Media trackMedia = GetTrackMedia(currentTrack);
+ if (!trackMedia)
+ continue;
+
+ // Grab the media type for this track. Make sure that we don't
+ // get an error in doing so. If we do, then something really funky is
+ // wrong.
+ OSType mediaType;
+ GetMediaHandlerDescription(trackMedia, &mediaType, nil, nil);
+ OSErr mediaErr = GetMoviesError();
+ if (mediaErr != noErr)
+ continue;
+
+ if (!allowedTrackTypes->contains(mediaType)) {
+ SetTrackEnabled(currentTrack, false);
+ --enabledTrackCount;
+ }
+
+ // Grab the track reference count for chapters. This will tell us if it
+ // has chapter tracks in it. If there aren't any references, then we
+ // can move on the next track.
+ long referenceCount = GetTrackReferenceCount(currentTrack, kTrackReferenceChapterList);
+ if (referenceCount <= 0)
+ continue;
+
+ long referenceIndex = 0;
+ while (1) {
+ // If we get nothing here, we've overstepped our bounds and can stop
+ // looking. Chapter indices here are 1-based as well - hence, the
+ // pre-increment.
+ referenceIndex++;
+ Track chapterTrack = GetTrackReference(currentTrack, kTrackReferenceChapterList, referenceIndex);
+ if (!chapterTrack)
+ break;
+
+ // Try to grab the media for the track.
+ Media chapterMedia = GetTrackMedia(chapterTrack);
+ if (!chapterMedia)
+ continue;
+
+ // Grab the media type for this track. Make sure that we don't
+ // get an error in doing so. If we do, then something really
+ // funky is wrong.
+ OSType mediaType;
+ GetMediaHandlerDescription(chapterMedia, &mediaType, nil, nil);
+ OSErr mediaErr = GetMoviesError();
+ if (mediaErr != noErr)
+ continue;
+
+ // Check to see if the track is a video track. We don't care about
+ // other non-video tracks.
+ if (mediaType != VideoMediaType)
+ continue;
+
+ // Check to see if the track is already disabled. If it is, we
+ // should move along.
+ if (!GetTrackEnabled(chapterTrack))
+ continue;
+
+ // Disabled the evil, evil track.
+ SetTrackEnabled(chapterTrack, false);
+ --enabledTrackCount;
+ }
+ }
+}
+
+pascal OSErr movieDrawingCompleteProc(Movie movie, long data)
+{
+ UppParam param;
+ param.longValue = data;
+ QTMovieWinPrivate* mp = static_cast<QTMovieWinPrivate*>(param.ptr);
+ if (mp)
+ mp->drawingComplete();
+ return 0;
+}
+
+static void initializeSupportedTypes()
+{
+ if (gSupportedTypes)
+ return;
+
+ gSupportedTypes = new Vector<CFStringRef>;
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Returning empty list of supported media MIME types.", quickTimeVersion, minimumQuickTimeVersion);
+ return;
+ }
+
+ // QuickTime doesn't have an importer for video/quicktime. Add it manually.
+ gSupportedTypes->append(CFSTR("video/quicktime"));
+
+ for (int index = 0; index < 2; index++) {
+ ComponentDescription findCD;
+
+ // look at all movie importers that can import in place and are installed.
+ findCD.componentType = MovieImportType;
+ findCD.componentSubType = 0;
+ findCD.componentManufacturer = 0;
+ findCD.componentFlagsMask = cmpIsMissing | movieImportSubTypeIsFileExtension | canMovieImportInPlace | dontAutoFileMovieImport;
+
+ // look at those registered by HFS file types the first time through, by file extension the second time
+ findCD.componentFlags = canMovieImportInPlace | (index ? movieImportSubTypeIsFileExtension : 0);
+
+ long componentCount = CountComponents(&findCD);
+ if (!componentCount)
+ continue;
+
+ Component comp = 0;
+ while (comp = FindNextComponent(comp, &findCD)) {
+ // Does this component have a MIME type container?
+ ComponentDescription infoCD;
+ OSErr err = GetComponentInfo(comp, &infoCD, nil /*name*/, nil /*info*/, nil /*icon*/);
+ if (err)
+ continue;
+ if (!(infoCD.componentFlags & hasMovieImportMIMEList))
+ continue;
+ QTAtomContainer mimeList = NULL;
+ err = MovieImportGetMIMETypeList((ComponentInstance)comp, &mimeList);
+ if (err || !mimeList)
+ continue;
+
+ // Grab every type from the container.
+ QTLockContainer(mimeList);
+ int typeCount = QTCountChildrenOfType(mimeList, kParentAtomIsContainer, kMimeInfoMimeTypeTag);
+ for (int typeIndex = 1; typeIndex <= typeCount; typeIndex++) {
+ QTAtom mimeTag = QTFindChildByIndex(mimeList, 0, kMimeInfoMimeTypeTag, typeIndex, NULL);
+ if (!mimeTag)
+ continue;
+ char* atomData;
+ long typeLength;
+ if (noErr != QTGetAtomDataPtr(mimeList, mimeTag, &typeLength, &atomData))
+ continue;
+
+ char typeBuffer[256];
+ if (typeLength >= sizeof(typeBuffer))
+ continue;
+ memcpy(typeBuffer, atomData, typeLength);
+ typeBuffer[typeLength] = 0;
+
+ // Only add "audio/..." and "video/..." types.
+ if (strncmp(typeBuffer, "audio/", 6) && strncmp(typeBuffer, "video/", 6))
+ continue;
+
+ CFStringRef cfMimeType = CFStringCreateWithCString(NULL, typeBuffer, kCFStringEncodingUTF8);
+ if (!cfMimeType)
+ continue;
+
+ // Only add each type once.
+ bool alreadyAdded = false;
+ for (int addedIndex = 0; addedIndex < gSupportedTypes->size(); addedIndex++) {
+ CFStringRef type = gSupportedTypes->at(addedIndex);
+ if (kCFCompareEqualTo == CFStringCompare(cfMimeType, type, kCFCompareCaseInsensitive)) {
+ alreadyAdded = true;
+ break;
+ }
+ }
+ if (!alreadyAdded)
+ gSupportedTypes->append(cfMimeType);
+ else
+ CFRelease(cfMimeType);
+ }
+ DisposeHandle(mimeList);
+ }
+ }
+}
+
+unsigned QTMovieWin::countSupportedTypes()
+{
+ initializeSupportedTypes();
+ return static_cast<unsigned>(gSupportedTypes->size());
+}
+
+void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& len)
+{
+ initializeSupportedTypes();
+ ASSERT(index < gSupportedTypes->size());
+
+ // Allocate sufficient buffer to hold any MIME type
+ static UniChar* staticBuffer = 0;
+ if (!staticBuffer)
+ staticBuffer = new UniChar[32];
+
+ CFStringRef cfstr = gSupportedTypes->at(index);
+ len = CFStringGetLength(cfstr);
+ CFRange range = { 0, len };
+ CFStringGetCharacters(cfstr, range, staticBuffer);
+ str = reinterpret_cast<const UChar*>(staticBuffer);
+
+}
+
+bool QTMovieWin::initializeQuickTime()
+{
+ static bool initialized = false;
+ static bool initializationSucceeded = false;
+ if (!initialized) {
+ initialized = true;
+ // Initialize and check QuickTime version
+ OSErr result = InitializeQTML(0);
+ if (result == noErr)
+ result = Gestalt(gestaltQuickTime, &quickTimeVersion);
+ if (result != noErr) {
+ LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
+ return false;
+ }
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", quickTimeVersion, minimumQuickTimeVersion);
+ return false;
+ }
+ EnterMovies();
+ setSharedTimerFiredFunction(taskTimerFired);
+ gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc);
+ initializationSucceeded = true;
+ }
+ return initializationSucceeded;
+}
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ setSharedTimerInstanceHandle(hinstDLL);
+ return TRUE;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ return FALSE;
+ }
+ ASSERT_NOT_REACHED();
+ return FALSE;
+}
diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h
new file mode 100644
index 0000000..e31780a
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWin.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef QTMovieWin_h
+#define QTMovieWin_h
+
+#include <Unicode.h>
+
+#ifdef QTMOVIEWIN_EXPORTS
+#define QTMOVIEWIN_API __declspec(dllexport)
+#else
+#define QTMOVIEWIN_API __declspec(dllimport)
+#endif
+
+class QTMovieWin;
+class QTMovieWinPrivate;
+
+class QTMovieWinClient {
+public:
+ virtual void movieEnded(QTMovieWin*) = 0;
+ virtual void movieLoadStateChanged(QTMovieWin*) = 0;
+ virtual void movieTimeChanged(QTMovieWin*) = 0;
+ virtual void movieNewImageAvailable(QTMovieWin*) = 0;
+};
+
+enum {
+ QTMovieLoadStateError = -1L,
+ QTMovieLoadStateLoaded = 2000L,
+ QTMovieLoadStatePlayable = 10000L,
+ QTMovieLoadStatePlaythroughOK = 20000L,
+ QTMovieLoadStateComplete = 100000L
+};
+
+class QTMOVIEWIN_API QTMovieWin {
+public:
+ static bool initializeQuickTime();
+
+ QTMovieWin(QTMovieWinClient*);
+ ~QTMovieWin();
+
+ void load(const UChar* url, int len);
+ long loadState() const;
+ float maxTimeLoaded() const;
+
+ void play();
+ void pause();
+
+ float rate() const;
+ void setRate(float);
+
+ float duration() const;
+ float currentTime() const;
+ void setCurrentTime(float) const;
+
+ void setVolume(float);
+
+ unsigned dataSize() const;
+
+ void getNaturalSize(int& width, int& height);
+ void setSize(int width, int height);
+
+ void setVisible(bool);
+ void paint(HDC, int x, int y);
+
+ void disableUnsupportedTracks(unsigned& enabledTrackCount);
+
+ static unsigned countSupportedTypes();
+ static void getSupportedType(unsigned index, const UChar*& str, unsigned& len);
+
+private:
+ QTMovieWinPrivate* m_private;
+ friend class QTMovieWinPrivate;
+};
+
+#endif
diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.cpp b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
new file mode 100644
index 0000000..d0aa3e6
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, 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 <windows.h>
+
+#include "QTMovieWinTimer.h"
+
+#include <wtf/Assertions.h>
+
+// This file is used by the QuickTime access DLL. It copies some WebCore code
+// which can't be used directly due to dependency issues.
+
+// FIXME: Find a way to do timers that can manage <10ms resolution properly too.
+
+static UINT_PTR timerID;
+static void (*sharedTimerFiredFunction)();
+
+static HINSTANCE instanceHandle = 0;
+
+static HWND timerWindowHandle = 0;
+static UINT timerFiredMessage = 0;
+static const LPCWSTR kTimerWindowClassName = L"TimerWindowClass";
+static bool processingCustomTimerMessage = false;
+
+static LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == timerFiredMessage) {
+ processingCustomTimerMessage = true;
+ sharedTimerFiredFunction();
+ processingCustomTimerMessage = false;
+ } else
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ return 0;
+}
+
+static void initializeOffScreenTimerWindow()
+{
+ if (timerWindowHandle)
+ return;
+
+ WNDCLASSEX wcex;
+ memset(&wcex, 0, sizeof(WNDCLASSEX));
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = TimerWindowWndProc;
+ wcex.hInstance = instanceHandle;
+ wcex.lpszClassName = kTimerWindowClassName;
+ RegisterClassEx(&wcex);
+
+ timerWindowHandle = CreateWindow(kTimerWindowClassName, 0, 0,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, instanceHandle, 0);
+ timerFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.TimerFired");
+}
+
+void setSharedTimerFiredFunction(void (*f)())
+{
+ sharedTimerFiredFunction = f;
+}
+
+static void CALLBACK timerFired(HWND, UINT, UINT_PTR, DWORD)
+{
+ sharedTimerFiredFunction();
+}
+
+void setSharedTimerFireDelay(double interval)
+{
+ ASSERT(sharedTimerFiredFunction);
+
+ unsigned intervalInMS;
+ if (interval < 0)
+ intervalInMS = 0;
+ else {
+ interval *= 1000;
+ if (interval > USER_TIMER_MAXIMUM)
+ intervalInMS = USER_TIMER_MAXIMUM;
+ else
+ intervalInMS = (unsigned)interval;
+ }
+
+ if (timerID) {
+ KillTimer(0, timerID);
+ timerID = 0;
+ }
+
+ // We don't allow nested PostMessages, since the custom messages will effectively starve
+ // painting and user input. (Win32 has a tri-level queue with application messages >
+ // user input > WM_PAINT/WM_TIMER.)
+ // In addition, if the queue contains input events that have been there since the last call to
+ // GetQueueStatus, PeekMessage or GetMessage we favor timers.
+ if (intervalInMS < USER_TIMER_MINIMUM && processingCustomTimerMessage &&
+ !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
+ // Windows SetTimer does not allow timeouts smaller than 10ms (USER_TIMER_MINIMUM)
+ initializeOffScreenTimerWindow();
+ PostMessage(timerWindowHandle, timerFiredMessage, 0, 0);
+ } else
+ timerID = SetTimer(0, 0, intervalInMS, timerFired);
+}
+
+void stopSharedTimer()
+{
+ if (timerID) {
+ KillTimer(0, timerID);
+ timerID = 0;
+ }
+}
+
+void setSharedTimerInstanceHandle(HINSTANCE handle)
+{
+ instanceHandle = handle;
+}
+
+double systemTime()
+{
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+ ULARGE_INTEGER t;
+ memcpy(&t, &ft, sizeof(t));
+ return t.QuadPart * 0.0000001 - 11644473600.0;
+}
diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.h b/WebCore/platform/graphics/win/QTMovieWinTimer.h
new file mode 100644
index 0000000..3e3c2bc
--- /dev/null
+++ b/WebCore/platform/graphics/win/QTMovieWinTimer.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef QTMovieViewTimer_h
+#define QTMovieViewTimer_h
+
+// This header should not be included from WebCore.
+// It is used by the QuickTime access DLL. It copies some WebCore code
+// which can't be used directly due to dependency issues.
+
+void setSharedTimerFiredFunction(void (*)());
+void setSharedTimerFireDelay(double delay);
+void stopSharedTimer();
+void setSharedTimerInstanceHandle(HINSTANCE handle);
+double systemTime();
+
+#endif
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
new file mode 100644
index 0000000..8b5ab87
--- /dev/null
+++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006, 2007, 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 "SimpleFontData.h"
+
+#include <winsock2.h>
+#include "Font.h"
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include "PlatformString.h"
+#include <wtf/MathExtras.h>
+#include <wtf/RetainPtr.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#include <mlang.h>
+#include <tchar.h>
+
+namespace WebCore {
+
+using std::max;
+
+static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x; }
+
+void SimpleFontData::platformInit()
+{
+ m_syntheticBoldOffset = m_font.syntheticBold() ? 1.0f : 0.f;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+
+ if (m_font.useGDI())
+ return initGDIFont();
+
+ CGFontRef font = m_font.cgFont();
+ int iAscent = CGFontGetAscent(font);
+ int iDescent = CGFontGetDescent(font);
+ int iLineGap = CGFontGetLeading(font);
+ m_unitsPerEm = CGFontGetUnitsPerEm(font);
+ float pointSize = m_font.size();
+ float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize;
+ float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize;
+ float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize;
+
+ if (!isCustomFont()) {
+ HDC dc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dc, m_font.hfont());
+ int faceLength = GetTextFace(dc, 0, 0);
+ Vector<TCHAR> faceName(faceLength);
+ GetTextFace(dc, faceLength, faceName.data());
+ m_isSystemFont = !_tcscmp(faceName.data(), _T("Lucida Grande"));
+ SelectObject(dc, oldFont);
+ ReleaseDC(0, dc);
+
+ if (shouldApplyMacAscentHack()) {
+ // This code comes from FontDataMac.mm. We only ever do this when running regression tests so that our metrics will match Mac.
+
+ // We need to adjust Times, Helvetica, and Courier to closely match the
+ // vertical metrics of their Microsoft counterparts that are the de facto
+ // web standard. The AppKit adjustment of 20% is too big and is
+ // incorrectly added to line spacing, so we use a 15% adjustment instead
+ // and add it to the ascent.
+ if (!_tcscmp(faceName.data(), _T("Times")) || !_tcscmp(faceName.data(), _T("Helvetica")) || !_tcscmp(faceName.data(), _T("Courier")))
+ fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f);
+ }
+ }
+
+ m_ascent = lroundf(fAscent);
+ m_descent = lroundf(fDescent);
+ m_lineGap = lroundf(fLineGap);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
+ // Unfortunately, NSFont will round this for us so we don't quite get the right value.
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
+ Glyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
+ if (xGlyph) {
+ CGRect xBox;
+ CGFontGetGlyphBBoxes(font, &xGlyph, 1, &xBox);
+ // Use the maximum of either width or height because "x" is nearly square
+ // and web pages that foolishly use this metric for width will be laid out
+ // poorly if we return an accurate height. Classic case is Times 13 point,
+ // which has an "x" that is 7x6 pixels.
+ m_xHeight = scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), m_unitsPerEm) * pointSize;
+ } else {
+ int iXHeight = CGFontGetXHeight(font);
+ m_xHeight = scaleEmToUnits(iXHeight, m_unitsPerEm) * pointSize;
+ }
+}
+
+void SimpleFontData::platformDestroy()
+{
+ platformCommonDestroy();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_font.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ CGFontRef font = m_font.cgFont();
+ float pointSize = m_font.size();
+ CGSize advance;
+ CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
+
+ // FIXME: Need to add real support for printer fonts.
+ bool isPrinterFont = false;
+ wkGetGlyphAdvances(font, m, m_isSystemFont, isPrinterFont, glyph, advance);
+
+ return advance.width + m_syntheticBoldOffset;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
new file mode 100644
index 0000000..07d5305
--- /dev/null
+++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 "SimpleFontData.h"
+
+#include <windows.h>
+
+#include "Font.h"
+#include "FontCache.h"
+#include "FontDescription.h"
+#include "MathExtras.h"
+#include "NotImplemented.h"
+#include <cairo.h>
+#include <cairo-win32.h>
+#include <mlang.h>
+#include <tchar.h>
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+ m_isSystemFont = false;
+ m_syntheticBoldOffset = 0;
+
+ if (m_font.useGDI())
+ return initGDIFont();
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_font.scaledFont();
+ const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size();
+
+ cairo_win32_scaled_font_select_font(scaledFont, hdc);
+
+ TEXTMETRIC textMetrics;
+ GetTextMetrics(hdc, &textMetrics);
+ m_ascent = lroundf(textMetrics.tmAscent * metricsMultiplier);
+ m_descent = lroundf(textMetrics.tmDescent * metricsMultiplier);
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.
+ m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier);
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+
+ OUTLINETEXTMETRIC metrics;
+ if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) {
+ // This is a TrueType font. We might be able to get an accurate xHeight
+ GLYPHMETRICS gm;
+ MAT2 mat = { 1, 0, 0, 1 };
+ DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
+ if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
+ m_xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier;
+ }
+
+ cairo_win32_scaled_font_done_font(scaledFont);
+
+ m_isSystemFont = false;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+}
+
+void SimpleFontData::platformDestroy()
+{
+ cairo_font_face_destroy(m_font.fontFace());
+ cairo_scaled_font_destroy(m_font.scaledFont());
+
+ DeleteObject(m_font.hfont());
+
+ platformCommonDestroy();
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ if (m_font.useGDI())
+ return widthForGDIGlyph(glyph);
+
+ HDC hdc = GetDC(0);
+ SaveDC(hdc);
+
+ cairo_scaled_font_t* scaledFont = m_font.scaledFont();
+ cairo_win32_scaled_font_select_font(scaledFont, hdc);
+
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+
+ cairo_win32_scaled_font_done_font(scaledFont);
+
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
+
+ const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size();
+ return width * metricsMultiplier;
+}
+
+void SimpleFontData::setFont(cairo_t* cr) const
+{
+ ASSERT(cr);
+ m_font.setFont(cr);
+}
+
+}
diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
new file mode 100644
index 0000000..0e9f9fb
--- /dev/null
+++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2006, 2007, 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 "SimpleFontData.h"
+
+#include <winsock2.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 <ApplicationServices/ApplicationServices.h>
+#include <mlang.h>
+#include <tchar.h>
+#include <WebKitSystemInterface/WebKitSystemInterface.h>
+
+namespace WebCore {
+
+using std::max;
+
+const float cSmallCapsFontSizeMultiplier = 0.7f;
+
+static bool g_shouldApplyMacAscentHack;
+
+void SimpleFontData::setShouldApplyMacAscentHack(bool b)
+{
+ g_shouldApplyMacAscentHack = b;
+}
+
+bool SimpleFontData::shouldApplyMacAscentHack()
+{
+ return g_shouldApplyMacAscentHack;
+}
+
+void SimpleFontData::initGDIFont()
+{
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ OUTLINETEXTMETRIC metrics;
+ GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
+ TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
+ m_ascent = textMetrics.tmAscent;
+ m_descent = textMetrics.tmDescent;
+ m_lineGap = textMetrics.tmExternalLeading;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
+
+ GLYPHMETRICS gm;
+ MAT2 mat = { 1, 0, 0, 1 };
+ DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
+ if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
+ m_xHeight = gm.gmptGlyphOrigin.y;
+
+ m_unitsPerEm = metrics.otmEMSquare;
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return;
+}
+
+void SimpleFontData::platformCommonDestroy()
+{
+ // We don't hash this on Win32, so it's effectively owned by us.
+ delete m_smallCapsFontData;
+
+ ScriptFreeCache(&m_scriptCache);
+ delete m_scriptFontProperties;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_font.size();
+ if (isCustomFont()) {
+ FontPlatformData smallCapsFontData(m_font);
+ smallCapsFontData.setSize(smallCapsHeight);
+ m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false);
+ } else {
+ LOGFONT winfont;
+ GetObject(m_font.hfont(), sizeof(LOGFONT), &winfont);
+ winfont.lfHeight = -lroundf(smallCapsHeight * (m_font.useGDI() ? 1 : 32));
+ HFONT hfont = CreateFontIndirect(&winfont);
+ m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_font.syntheticBold(), m_font.syntheticOblique(), m_font.useGDI()));
+ }
+ }
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // FIXME: Support custom fonts.
+ if (isCustomFont())
+ return false;
+
+ // 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();
+ if (!langFontLink)
+ return false;
+
+ HDC dc = GetDC(0);
+
+ DWORD acpCodePages;
+ langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
+
+ DWORD fontCodePages;
+ langFontLink->GetFontCodePages(dc, m_font.hfont(), &fontCodePages);
+
+ DWORD actualCodePages;
+ long numCharactersProcessed;
+ long offset = 0;
+ while (offset < length) {
+ langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed);
+ if ((actualCodePages & fontCodePages) == 0)
+ return false;
+ offset += numCharactersProcessed;
+ }
+
+ ReleaseDC(0, dc);
+
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (isCustomFont()) {
+ m_treatAsFixedPitch = false;
+ return;
+ }
+
+ // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
+ HDC dc = GetDC(0);
+ SaveDC(dc);
+ 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 tm;
+ GetTextMetrics(dc, &tm);
+ m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
+
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+}
+
+float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
+{
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ return width + m_syntheticBoldOffset;
+}
+
+SCRIPT_FONTPROPERTIES* SimpleFontData::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);
+ SaveDC(dc);
+ SelectObject(dc, m_font.hfont());
+ ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties);
+ RestoreDC(dc, -1);
+ ReleaseDC(0, dc);
+ }
+ }
+ return m_scriptFontProperties;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp
new file mode 100644
index 0000000..371bc51
--- /dev/null
+++ b/WebCore/platform/graphics/win/UniscribeController.cpp
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "UniscribeController.h"
+#include "Font.h"
+#include "SimpleFontData.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+// FIXME: Rearchitect this to be more like WidthIterator in Font.cpp. Have an advance() method
+// that does stuff in that method instead of doing everything in the constructor. Have advance()
+// take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when
+// measuring.
+UniscribeController::UniscribeController(const Font* font, const TextRun& run)
+: m_font(*font)
+, m_run(run)
+, m_end(run.length())
+, m_currentCharacter(0)
+, m_runWidthSoFar(0)
+, m_computingOffsetPosition(false)
+, m_includePartialGlyphs(false)
+, m_offsetX(0)
+, m_offsetPosition(0)
+{
+ m_padding = m_run.padding();
+ if (!m_padding)
+ m_padPerSpace = 0;
+ else {
+ float numSpaces = 0;
+ for (int s = 0; s < m_run.length(); s++)
+ if (Font::treatAsSpace(m_run[s]))
+ numSpaces++;
+
+ if (numSpaces == 0)
+ m_padPerSpace = 0;
+ else
+ m_padPerSpace = ceilf(m_run.padding() / numSpaces);
+ }
+
+ // Null out our uniscribe structs
+ resetControlAndState();
+}
+
+int UniscribeController::offsetForPosition(int x, bool includePartialGlyphs)
+{
+ m_computingOffsetPosition = true;
+ m_includePartialGlyphs = includePartialGlyphs;
+ m_offsetX = x;
+ m_offsetPosition = 0;
+ advance(m_run.length());
+ if (m_computingOffsetPosition) {
+ // The point is to the left or to the right of the entire run.
+ if (m_offsetX >= m_runWidthSoFar && m_run.ltr() || m_offsetX < 0 && m_run.rtl())
+ m_offsetPosition = m_end;
+ }
+ m_computingOffsetPosition = false;
+ return m_offsetPosition;
+}
+
+void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
+{
+ // FIXME: We really want to be using a newer version of Uniscribe that supports the new OpenType
+ // functions. Those functions would allow us to turn off kerning and ligatures. Without being able
+ // to do that, we will have buggy line breaking and metrics when simple and complex text are close
+ // together (the complex code path will narrow the text because of kerning and ligatures and then
+ // when bidi processing splits into multiple runs, the simple portions will get wider and cause us to
+ // spill off the edge of a line).
+ if (static_cast<int>(offset) > m_end)
+ offset = m_end;
+
+ // Itemize the string.
+ const UChar* cp = m_run.data(m_currentCharacter);
+ int length = offset - m_currentCharacter;
+ if (length <= 0)
+ return;
+
+ unsigned baseCharacter = m_currentCharacter;
+
+ // We break up itemization of the string by fontData and (if needed) the use of small caps.
+
+ // FIXME: It's inconsistent that we use logical order when itemizing, since this
+ // does not match normal RTL.
+
+ // FIXME: This function should decode surrogate pairs. Currently it makes little difference that
+ // it does not because the font cache on Windows does not support non-BMP characters.
+ Vector<UChar, 256> smallCapsBuffer;
+ if (m_font.isSmallCaps())
+ smallCapsBuffer.resize(length);
+
+ unsigned indexOfFontTransition = m_run.rtl() ? length - 1 : 0;
+ const UChar* curr = m_run.rtl() ? cp + length - 1 : cp;
+ const UChar* end = m_run.rtl() ? cp - 1 : cp + length;
+
+ const SimpleFontData* fontData;
+ const SimpleFontData* nextFontData = m_font.glyphDataForCharacter(*curr, false).fontData;
+
+ UChar newC = 0;
+
+ bool isSmallCaps;
+ bool nextIsSmallCaps = m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr;
+
+ if (nextIsSmallCaps)
+ smallCapsBuffer[curr - cp] = newC;
+
+ while (true) {
+ curr = m_run.rtl() ? curr - 1 : curr + 1;
+ if (curr == end)
+ break;
+
+ fontData = nextFontData;
+ isSmallCaps = nextIsSmallCaps;
+ int index = curr - cp;
+ UChar c = *curr;
+
+ bool forceSmallCaps = isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK);
+ nextFontData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps).fontData;
+ if (m_font.isSmallCaps()) {
+ nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c;
+ if (nextIsSmallCaps)
+ smallCapsBuffer[index] = forceSmallCaps ? c : newC;
+ }
+
+ if (nextFontData != fontData || nextIsSmallCaps != isSmallCaps) {
+ int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition;
+ int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition;
+ m_currentCharacter = baseCharacter + itemStart;
+ itemizeShapeAndPlace((isSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, fontData, glyphBuffer);
+ indexOfFontTransition = index;
+ }
+ }
+
+ int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : length - indexOfFontTransition;
+ if (itemLength) {
+ int itemStart = m_run.rtl() ? 0 : indexOfFontTransition;
+ m_currentCharacter = baseCharacter + itemStart;
+ itemizeShapeAndPlace((nextIsSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, nextFontData, glyphBuffer);
+ }
+
+ m_currentCharacter = baseCharacter + length;
+}
+
+void UniscribeController::itemizeShapeAndPlace(const UChar* cp, unsigned length, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer)
+{
+ // ScriptItemize (in Windows XP versions prior to SP2) can overflow by 1. This is why there is an extra empty item
+ // hanging out at the end of the array
+ m_items.resize(6);
+ int numItems = 0;
+ while (ScriptItemize(cp, length, m_items.size() - 1, &m_control, &m_state, m_items.data(), &numItems) == E_OUTOFMEMORY) {
+ m_items.resize(m_items.size() * 2);
+ resetControlAndState();
+ }
+ m_items.resize(numItems + 1);
+
+ if (m_run.rtl()) {
+ for (int i = m_items.size() - 2; i >= 0; i--) {
+ if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer))
+ return;
+ }
+ } else {
+ for (unsigned i = 0; i < m_items.size() - 1; i++) {
+ if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer))
+ return;
+ }
+ }
+}
+
+void UniscribeController::resetControlAndState()
+{
+ memset(&m_control, 0, sizeof(SCRIPT_CONTROL));
+ memset(&m_state, 0, sizeof(SCRIPT_STATE));
+
+ // Set up the correct direction for the run.
+ m_state.uBidiLevel = m_run.rtl();
+
+ // Lock the correct directional override.
+ m_state.fOverrideDirection = m_run.directionalOverride();
+}
+
+bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer)
+{
+ // Determine the string for this item.
+ const UChar* str = cp + m_items[i].iCharPos;
+ int len = m_items[i+1].iCharPos - m_items[i].iCharPos;
+ SCRIPT_ITEM item = m_items[i];
+
+ // Set up buffers to hold the results of shaping the item.
+ Vector<WORD> glyphs;
+ Vector<WORD> clusters;
+ Vector<SCRIPT_VISATTR> visualAttributes;
+ clusters.resize(len);
+
+ // Shape the item.
+ // The recommended size for the glyph buffer is 1.5 * the character length + 16 in the uniscribe docs.
+ // Apparently this is a good size to avoid having to make repeated calls to ScriptShape.
+ glyphs.resize(1.5 * len + 16);
+ visualAttributes.resize(glyphs.size());
+
+ if (!shape(str, len, item, fontData, glyphs, clusters, visualAttributes))
+ return true;
+
+ // We now have a collection of glyphs.
+ Vector<GOFFSET> offsets;
+ Vector<int> advances;
+ offsets.resize(glyphs.size());
+ advances.resize(glyphs.size());
+ int glyphCount = 0;
+ HRESULT placeResult = ScriptPlace(0, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(),
+ &item.a, advances.data(), offsets.data(), 0);
+ if (placeResult == E_PENDING) {
+ // The script cache isn't primed with enough info yet. We need to select our HFONT into
+ // a DC and pass the DC in to ScriptPlace.
+ HDC hdc = GetDC(0);
+ HFONT hfont = fontData->platformData().hfont();
+ HFONT oldFont = (HFONT)SelectObject(hdc, hfont);
+ placeResult = ScriptPlace(hdc, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(),
+ &item.a, advances.data(), offsets.data(), 0);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ }
+
+ if (FAILED(placeResult) || glyphs.isEmpty())
+ return true;
+
+ // Convert all chars that should be treated as spaces to use the space glyph.
+ // We also create a map that allows us to quickly go from space glyphs or rounding
+ // hack glyphs back to their corresponding characters.
+ Vector<int> spaceCharacters(glyphs.size());
+ spaceCharacters.fill(-1);
+ Vector<int> roundingHackCharacters(glyphs.size());
+ roundingHackCharacters.fill(-1);
+ Vector<int> roundingHackWordBoundaries(glyphs.size());
+ roundingHackWordBoundaries.fill(-1);
+
+ const float cLogicalScale = fontData->m_font.useGDI() ? 1.0f : 32.0f;
+ unsigned logicalSpaceWidth = fontData->m_spaceWidth * cLogicalScale;
+ float roundedSpaceWidth = roundf(fontData->m_spaceWidth);
+
+ for (int k = 0; k < len; k++) {
+ UChar ch = *(str + k);
+ if (Font::treatAsSpace(ch)) {
+ // Substitute in the space glyph at the appropriate place in the glyphs
+ // array.
+ glyphs[clusters[k]] = fontData->m_spaceGlyph;
+ advances[clusters[k]] = logicalSpaceWidth;
+ spaceCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos;
+ }
+
+ if (Font::isRoundingHackCharacter(ch))
+ roundingHackCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos;
+
+ int boundary = k + m_currentCharacter + item.iCharPos;
+ if (boundary < m_run.length() &&
+ Font::isRoundingHackCharacter(*(str + k + 1)))
+ roundingHackWordBoundaries[clusters[k]] = boundary;
+ }
+
+ // Populate our glyph buffer with this information.
+ bool hasExtraSpacing = m_font.letterSpacing() || m_font.wordSpacing() || m_padding;
+
+ float leftEdge = m_runWidthSoFar;
+
+ for (unsigned k = 0; k < glyphs.size(); k++) {
+ Glyph glyph = glyphs[k];
+ float advance = advances[k] / cLogicalScale;
+ float offsetX = offsets[k].du / cLogicalScale;
+ float offsetY = offsets[k].dv / cLogicalScale;
+
+ // Match AppKit's rules for the integer vs. non-integer rendering modes.
+ float roundedAdvance = roundf(advance);
+ if (!m_font.isPrinterFont() && !fontData->isSystemFont()) {
+ advance = roundedAdvance;
+ offsetX = roundf(offsetX);
+ offsetY = roundf(offsetY);
+ }
+
+ advance += fontData->m_syntheticBoldOffset;
+
+ // We special case spaces in two ways when applying word rounding.
+ // First, we round spaces to an adjusted width in all fonts.
+ // Second, in fixed-pitch fonts we ensure that all glyphs that
+ // match the width of the space glyph have the same width as the space glyph.
+ if (roundedAdvance == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) &&
+ m_run.applyWordRounding())
+ advance = fontData->m_adjustedSpaceWidth;
+
+ if (hasExtraSpacing) {
+ // If we're a glyph with an advance, go ahead and add in letter-spacing.
+ // That way we weed out zero width lurkers. This behavior matches the fast text code path.
+ if (advance && m_font.letterSpacing())
+ advance += m_font.letterSpacing();
+
+ // Handle justification and word-spacing.
+ if (glyph == fontData->m_spaceGlyph) {
+ // Account for padding. WebCore uses space padding to justify text.
+ // We distribute the specified padding over the available spaces in the run.
+ if (m_padding) {
+ // Use leftover padding if not evenly divisible by number of spaces.
+ if (m_padding < m_padPerSpace) {
+ advance += m_padding;
+ m_padding = 0;
+ } else {
+ advance += m_padPerSpace;
+ m_padding -= m_padPerSpace;
+ }
+ }
+
+ // Account for word-spacing.
+ int characterIndex = spaceCharacters[k];
+ if (characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing())
+ advance += m_font.wordSpacing();
+ }
+ }
+
+ // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters
+ // followed by a character defined by isRoundingHackCharacter()) are always an integer width.
+ // We adjust the width of the last character of a "word" to ensure an integer width.
+ // Force characters that are used to determine word boundaries for the rounding hack
+ // to be integer width, so the following words will start on an integer boundary.
+ int roundingHackIndex = roundingHackCharacters[k];
+ if (m_run.applyWordRounding() && roundingHackIndex != -1)
+ advance = ceilf(advance);
+
+ // Check to see if the next character is a "rounding hack character", if so, adjust the
+ // width so that the total run width will be on an integer boundary.
+ int position = m_currentCharacter + len;
+ bool lastGlyph = (k == glyphs.size() - 1) && (m_run.rtl() ? i == 0 : i == m_items.size() - 2) && (position >= m_end);
+ if ((m_run.applyWordRounding() && roundingHackWordBoundaries[k] != -1) ||
+ (m_run.applyRunRounding() && lastGlyph)) {
+ float totalWidth = m_runWidthSoFar + advance;
+ advance += ceilf(totalWidth) - totalWidth;
+ }
+
+ m_runWidthSoFar += advance;
+
+ // FIXME: We need to take the GOFFSETS for combining glyphs and store them in the glyph buffer
+ // as well, so that when the time comes to draw those glyphs, we can apply the appropriate
+ // translation.
+ if (glyphBuffer) {
+ FloatSize size(offsetX, -offsetY);
+ glyphBuffer->add(glyph, fontData, advance, &size);
+ }
+
+ // Mutate the glyph array to contain our altered advances.
+ if (m_computingOffsetPosition)
+ advances[k] = advance;
+ }
+
+ while (m_computingOffsetPosition && m_offsetX >= leftEdge && m_offsetX < m_runWidthSoFar) {
+ // The position is somewhere inside this run.
+ int trailing = 0;
+ ScriptXtoCP(m_offsetX - leftEdge, clusters.size(), glyphs.size(), clusters.data(), visualAttributes.data(),
+ advances.data(), &item.a, &m_offsetPosition, &trailing);
+ if (trailing && m_includePartialGlyphs && m_offsetPosition < len - 1) {
+ m_offsetPosition += m_currentCharacter + m_items[i].iCharPos;
+ m_offsetX += m_run.rtl() ? -trailing : trailing;
+ } else {
+ m_computingOffsetPosition = false;
+ m_offsetPosition += m_currentCharacter + m_items[i].iCharPos;
+ if (trailing && m_includePartialGlyphs)
+ m_offsetPosition++;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData,
+ Vector<WORD>& glyphs, Vector<WORD>& clusters,
+ Vector<SCRIPT_VISATTR>& visualAttributes)
+{
+ HDC hdc = 0;
+ HFONT oldFont = 0;
+ HRESULT shapeResult = E_PENDING;
+ int glyphCount = 0;
+ do {
+ shapeResult = ScriptShape(hdc, fontData->scriptCache(), str, len, glyphs.size(), &item.a,
+ glyphs.data(), clusters.data(), visualAttributes.data(), &glyphCount);
+ if (shapeResult == E_PENDING) {
+ // The script cache isn't primed with enough info yet. We need to select our HFONT into
+ // a DC and pass the DC in to ScriptShape.
+ ASSERT(!hdc);
+ hdc = GetDC(0);
+ HFONT hfont = fontData->platformData().hfont();
+ oldFont = (HFONT)SelectObject(hdc, hfont);
+ } else if (shapeResult == E_OUTOFMEMORY) {
+ // Need to resize our buffers.
+ glyphs.resize(glyphs.size() * 2);
+ visualAttributes.resize(glyphs.size());
+ }
+ } while (shapeResult == E_PENDING || shapeResult == E_OUTOFMEMORY);
+
+ if (hdc) {
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ }
+
+ if (FAILED(shapeResult))
+ return false;
+
+ glyphs.shrink(glyphCount);
+ visualAttributes.shrink(glyphCount);
+
+ return true;
+}
+
+}
diff --git a/WebCore/platform/graphics/win/UniscribeController.h b/WebCore/platform/graphics/win/UniscribeController.h
new file mode 100644
index 0000000..6ea45e1
--- /dev/null
+++ b/WebCore/platform/graphics/win/UniscribeController.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UniscribeController_h
+#define UniscribeController_h
+
+#include <usp10.h>
+#include "Font.h"
+#include "GlyphBuffer.h"
+#include "Vector.h"
+
+namespace WebCore {
+
+class UniscribeController {
+public:
+ UniscribeController(const Font*, const TextRun&);
+
+ // Advance and measure/place up to the specified character.
+ void advance(unsigned to, GlyphBuffer* = 0);
+
+ // Compute the character offset for a given x coordinate.
+ int offsetForPosition(int x, bool includePartialGlyphs);
+
+ // Returns the width of everything we've consumed so far.
+ float runWidthSoFar() const { return m_runWidthSoFar; }
+
+private:
+ void resetControlAndState();
+
+ void itemizeShapeAndPlace(const UChar*, unsigned length, const SimpleFontData*, GlyphBuffer*);
+ bool shapeAndPlaceItem(const UChar*, unsigned index, const SimpleFontData*, GlyphBuffer*);
+ bool shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData,
+ Vector<WORD>& glyphs, Vector<WORD>& clusters,
+ Vector<SCRIPT_VISATTR>& visualAttributes);
+
+ const Font& m_font;
+ const TextRun& m_run;
+
+ SCRIPT_CONTROL m_control;
+ SCRIPT_STATE m_state;
+ Vector<SCRIPT_ITEM> m_items;
+
+ unsigned m_currentCharacter;
+ int m_end;
+
+ float m_runWidthSoFar;
+ float m_padding;
+ float m_padPerSpace;
+
+ bool m_computingOffsetPosition;
+ bool m_includePartialGlyphs;
+ float m_offsetX;
+ int m_offsetPosition;
+};
+
+}
+#endif
diff --git a/WebCore/platform/graphics/wx/AffineTransformWx.cpp b/WebCore/platform/graphics/wx/AffineTransformWx.cpp
new file mode 100644
index 0000000..12485ae
--- /dev/null
+++ b/WebCore/platform/graphics/wx/AffineTransformWx.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier 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 "AffineTransform.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+
+#include <stdio.h>
+#include <wx/defs.h>
+#include <wx/graphics.h>
+
+namespace WebCore {
+
+#if USE(WXGC)
+AffineTransform::AffineTransform(const PlatformAffineTransform& matrix)
+{
+ m_transform = matrix;
+}
+#endif
+
+AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
+{
+#if USE(WXGC)
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ m_transform = renderer->CreateMatrix();
+#endif
+ setMatrix(a, b, c, d, e, f);
+}
+
+AffineTransform::AffineTransform()
+{
+ // 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();
+ m_transform = renderer->CreateMatrix();
+#endif
+}
+
+AffineTransform AffineTransform::inverse() const
+{
+ notImplemented();
+ return *this;
+}
+
+void AffineTransform::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
+{
+ notImplemented();
+}
+
+IntRect AffineTransform::mapRect(const IntRect &rect) const
+{
+ notImplemented();
+ return IntRect();
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+{
+ notImplemented();
+ return FloatRect();
+}
+
+
+AffineTransform& AffineTransform::scale(double sx, double sy)
+{
+#if USE(WXGC)
+ m_transform.Scale((wxDouble)sx, (wxDouble)sy);
+#endif
+ return *this;
+}
+
+void AffineTransform::reset()
+{
+ notImplemented();
+}
+
+AffineTransform& AffineTransform::rotate(double d)
+{
+#if USE(WXGC)
+ m_transform.Rotate((wxDouble)d);
+#endif
+ return *this;
+}
+
+AffineTransform& AffineTransform::translate(double tx, double ty)
+{
+#if USE(WXGC)
+ m_transform.Translate((wxDouble)tx, (wxDouble)ty);
+#endif
+ return *this;
+}
+
+AffineTransform& AffineTransform::shear(double sx, double sy)
+{
+ notImplemented();
+ return *this;
+}
+
+AffineTransform& AffineTransform::operator*=(const AffineTransform& other)
+{
+ notImplemented();
+ return *this;
+}
+
+bool AffineTransform::operator== (const AffineTransform &other) const
+{
+#if USE(WXGC)
+ return m_transform.IsEqual((wxGraphicsMatrix)other);
+#else
+ notImplemented();
+ return true;
+#endif
+}
+
+AffineTransform AffineTransform::operator* (const AffineTransform &other)
+{
+ notImplemented();
+ return *this; //m_transform * other.m_transform;
+}
+
+double AffineTransform::det() const
+{
+ notImplemented();
+ return 0;
+}
+
+#if USE(WXGC)
+AffineTransform::operator wxGraphicsMatrix() const
+{
+ return m_transform;
+}
+#endif
+
+double AffineTransform::a() const
+{
+ double a = 0;
+#if USE(WXGC)
+ m_transform.Get(&a);
+#endif
+ return a;
+}
+
+void AffineTransform::setA(double a)
+{
+ setMatrix(a, b(), c(), d(), e(), f());
+}
+
+double AffineTransform::b() const
+{
+ double b = 0;
+#if USE(WXGC)
+ m_transform.Get(&b);
+#endif
+ return b;
+}
+
+void AffineTransform::setB(double b)
+{
+ setMatrix(a(), b, c(), d(), e(), f());
+}
+
+double AffineTransform::c() const
+{
+ double c = 0;
+#if USE(WXGC)
+ m_transform.Get(&c);
+#endif
+ return c;
+}
+
+void AffineTransform::setC(double c)
+{
+ setMatrix(a(), b(), c, d(), e(), f());
+}
+
+double AffineTransform::d() const
+{
+ double d = 0;
+#if USE(WXGC)
+ m_transform.Get(&d);
+#endif
+ return d;
+}
+
+void AffineTransform::setD(double d)
+{
+ setMatrix(a(), b(), c(), d, e(), f());
+}
+
+double AffineTransform::e() const
+{
+ double e = 0;
+#if USE(WXGC)
+ m_transform.Get(&e);
+#endif
+ return e;
+}
+
+void AffineTransform::setE(double e)
+{
+ setMatrix(a(), b(), c(), d(), e, f());
+}
+
+double AffineTransform::f() const
+{
+ double f = 0;
+#if USE(WXGC)
+ m_transform.Get(&f);
+#endif
+ return f;
+}
+
+void AffineTransform::setF(double f)
+{
+ setMatrix(a(), b(), c(), d(), e(), f);
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/ColorWx.cpp b/WebCore/platform/graphics/wx/ColorWx.cpp
new file mode 100644
index 0000000..0381c59
--- /dev/null
+++ b/WebCore/platform/graphics/wx/ColorWx.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006, 2007 Kevin Ollivier. 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"
+
+#include <wx/defs.h>
+#include <wx/colour.h>
+
+namespace WebCore {
+
+Color::Color(const wxColour& color)
+{
+ m_color = makeRGBA((int)color.Red(), (int)color.Green(), (int)color.Blue(), (int)color.Alpha());
+}
+
+Color::operator wxColour() const
+{
+ return wxColour(red(), green(), blue(), alpha());
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/FloatRectWx.cpp b/WebCore/platform/graphics/wx/FloatRectWx.cpp
new file mode 100644
index 0000000..bb460e5
--- /dev/null
+++ b/WebCore/platform/graphics/wx/FloatRectWx.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier. 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 "FloatRect.h"
+
+#include <wx/defs.h>
+#include <wx/graphics.h>
+
+namespace WebCore {
+
+#if USE(WXGC)
+FloatRect::FloatRect(const wxRect2DDouble& r)
+ : m_location(FloatPoint(r.m_x, r.m_y))
+ , m_size(FloatSize(r.m_width, r.m_height))
+{
+}
+
+FloatRect::operator wxRect2DDouble() const
+{
+ return wxRect2DDouble(x(), y(), width(), height());
+}
+#endif
+
+}
diff --git a/WebCore/platform/graphics/wx/FontCacheWx.cpp b/WebCore/platform/graphics/wx/FontCacheWx.cpp
new file mode 100755
index 0000000..db107e4
--- /dev/null
+++ b/WebCore/platform/graphics/wx/FontCacheWx.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "FontCache.h"
+#include "Font.h"
+#include "FontPlatformData.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ SimpleFontData* fontData = 0;
+ fontData = new SimpleFontData(FontPlatformData(font.fontDescription(), font.family().family()));
+ return fontData;
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return new FontPlatformData(font.fontDescription(), font.family().family());
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ // 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("systemfont");
+ return getCachedFontPlatformData(fontDescription, timesStr);
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ return new FontPlatformData(fontDescription,family);
+}
+
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ notImplemented();
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h
new file mode 100644
index 0000000..e3a3cce
--- /dev/null
+++ b/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2006 Kevin Ollivier 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 FontPlatformData_H
+#define FontPlatformData_H
+
+#include "FontDescription.h"
+#include "CString.h"
+#include "AtomicString.h"
+#include "StringImpl.h"
+
+#include <wx/defs.h>
+#include <wx/font.h>
+
+namespace WebCore {
+
+class FontPlatformData {
+public:
+ enum FontState { UNINITIALIZED, DELETED, VALID };
+
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_fontState(DELETED)
+ { }
+
+ ~FontPlatformData();
+
+ FontPlatformData(wxFont f)
+ : m_font(f)
+ , m_fontState(VALID)
+ {
+ m_fontHash = computeHash();
+ }
+
+ FontPlatformData(const FontDescription&, const AtomicString&);
+
+ FontPlatformData()
+ : m_fontState(UNINITIALIZED)
+ {
+ }
+
+ wxFont font() const {
+ return m_font;
+ }
+
+ unsigned hash() const {
+ switch (m_fontState) {
+ case DELETED:
+ return -1;
+ case UNINITIALIZED:
+ return 0;
+ case VALID:
+ return computeHash();
+ }
+ }
+
+ 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);
+ else
+ return m_fontState == other.m_fontState;
+ }
+
+ bool isHashTableDeletedValue() const { return m_fontState == DELETED; }
+
+ unsigned computeHash() const {
+ ASSERT(m_font.Ok());
+
+ // 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
+ uintptr_t hashCodes[6] = { m_font.GetPointSize(), m_font.GetFamily(), m_font.GetStyle(),
+ m_font.GetWeight(), m_font.GetUnderlined(),
+ StringImpl::computeHash(m_font.GetFaceName().mb_str(wxConvUTF8)) };
+
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
+ }
+
+private:
+ wxFont m_font;
+ FontState m_fontState;
+ unsigned m_fontHash;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
new file mode 100755
index 0000000..7162eab
--- /dev/null
+++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "FontPlatformData.h"
+
+#include "FontDescription.h"
+
+#include <wx/defs.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+
+namespace WebCore {
+
+static wxFontFamily fontFamilyToWxFontFamily(const int family)
+{
+ switch (family) {
+ case FontDescription::StandardFamily:
+ return wxFONTFAMILY_DEFAULT;
+ case FontDescription::SerifFamily:
+ return wxFONTFAMILY_ROMAN;
+ case FontDescription::SansSerifFamily:
+ return wxFONTFAMILY_MODERN;
+ case FontDescription::MonospaceFamily:
+ return wxFONTFAMILY_TELETYPE; // TODO: Check these are equivalent
+ case FontDescription::CursiveFamily:
+ return wxFONTFAMILY_SCRIPT;
+ case FontDescription::FantasyFamily:
+ return wxFONTFAMILY_DECORATIVE;
+ default:
+ return wxFONTFAMILY_DEFAULT;
+ }
+}
+
+static wxFontWeight fontWeightToWxFontWeight(FontWeight weight)
+{
+ if (weight >= FontWeight600)
+ return wxFONTWEIGHT_BOLD;
+
+ return wxFONTWEIGHT_NORMAL;
+}
+
+static int italicToWxFontStyle(bool isItalic)
+{
+ if (isItalic)
+ return wxFONTSTYLE_ITALIC;
+
+ return wxFONTSTYLE_NORMAL;
+}
+
+FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicString& family)
+{
+// NB: The Windows wxFont constructor has two forms, one taking a wxSize (with pixels)
+// and one taking an int (points). When points are used, Windows calculates
+// a pixel size using an algorithm which causes the size to be way off. However,
+// this is a moot issue on Linux and Mac as they only accept the point argument. So,
+// we use the pixel size constructor on Windows, but we use point size on Linux and Mac.
+#if __WXMSW__
+ m_font = wxFont( wxSize(0, -desc.computedPixelSize()),
+ fontFamilyToWxFontFamily(desc.genericFamily()),
+ italicToWxFontStyle(desc.italic()),
+ fontWeightToWxFontWeight(desc.weight()),
+ false,
+ family.string()
+ );
+#else
+ m_font = wxFont( desc.computedPixelSize(),
+ fontFamilyToWxFontFamily(desc.genericFamily()),
+ italicToWxFontStyle(desc.italic()),
+ fontWeightToWxFontWeight(desc.weight()),
+ false,
+ family.string()
+ );
+#endif
+ m_fontState = VALID;
+ m_fontHash = computeHash();
+
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ m_fontState = UNINITIALIZED;
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp
new file mode 100644
index 0000000..07223e9
--- /dev/null
+++ b/WebCore/platform/graphics/wx/FontWx.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier. 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 "Font.h"
+
+#include "FontFallbackList.h"
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+#include <wx/dcclient.h>
+#include "fontprops.h"
+#include "non-kerned-drawing.h"
+
+namespace WebCore {
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ // prepare DC
+ Color color = graphicsContext->fillColor();
+
+ // We can't use wx drawing methods on Win/Linux because they automatically kern text
+ // so we've created a function with platform dependent drawing implementations that
+ // will hopefully be folded into wx once the API has solidified.
+ // see platform/wx/wxcode/<platform> for the implementations.
+ drawTextWithSpacing(graphicsContext, font, color, glyphBuffer, from, numGlyphs, point);
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
+{
+ notImplemented();
+ return FloatRect();
+}
+
+void Font::drawComplexText(GraphicsContext* graphicsContext, 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;
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/GlyphMapWx.cpp b/WebCore/platform/graphics/wx/GlyphMapWx.cpp
new file mode 100755
index 0000000..ebf86e4
--- /dev/null
+++ b/WebCore/platform/graphics/wx/GlyphMapWx.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "GlyphPageTreeNode.h"
+
+#include "SimpleFontData.h"
+#include <unicode/utf16.h>
+
+namespace WebCore
+{
+
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
+{
+ bool isUtf16 = bufferLength != length;
+
+ for (unsigned i = 0; i < length; i++) {
+ UChar32 character;
+
+ if(isUtf16) {
+ UChar lead = buffer[i * 2];
+ UChar trail = buffer[i * 2 + 1];
+ character = U16_GET_SUPPLEMENTARY(lead, trail);
+ } else {
+ character = buffer[i];
+ }
+
+ setGlyphDataForIndex(offset + i, character, fontData);
+ }
+
+ return true;
+}
+
+} \ No newline at end of file
diff --git a/WebCore/platform/graphics/wx/GradientWx.cpp b/WebCore/platform/graphics/wx/GradientWx.cpp
new file mode 100644
index 0000000..fc4661e
--- /dev/null
+++ b/WebCore/platform/graphics/wx/GradientWx.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> 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 "Gradient.h"
+
+#include "CSSParser.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ notImplemented();
+}
+
+PlatformGradient Gradient::platformGradient()
+{
+ notImplemented();
+ return 0;
+}
+
+void Gradient::fill(GraphicsContext*, const FloatRect&)
+{
+ notImplemented();
+}
+
+} //namespace
diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
new file mode 100644
index 0000000..435e7ce
--- /dev/null
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "GraphicsContext.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "Font.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "Pen.h"
+#include <wtf/MathExtras.h>
+
+#include <math.h>
+#include <stdio.h>
+
+#include <wx/defs.h>
+#include <wx/window.h>
+#include <wx/dcclient.h>
+#include <wx/dcgraph.h>
+#include <wx/graphics.h>
+
+#if __WXMAC__
+#include <Carbon/Carbon.h>
+#elif __WXMSW__
+#include <windows.h>
+#endif
+
+namespace WebCore {
+
+int getWxCompositingOperation(CompositeOperator op, bool hasAlpha)
+{
+ // FIXME: Add support for more operators.
+ if (op == CompositeSourceOver && !hasAlpha)
+ op = CompositeCopy;
+
+ int function;
+ switch (op) {
+ case CompositeClear:
+ function = wxCLEAR;
+ case CompositeCopy:
+ function = wxCOPY;
+ break;
+ default:
+ function = wxCOPY;
+ }
+ return function;
+}
+
+static int strokeStyleToWxPenStyle(int p)
+{
+ if (p == SolidStroke)
+ return wxSOLID;
+ if (p == DottedStroke)
+ return wxDOT;
+ if (p == DashedStroke)
+ return wxLONG_DASH;
+ if (p == NoStroke)
+ return wxTRANSPARENT;
+
+ return wxSOLID;
+}
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContextPlatformPrivate();
+ ~GraphicsContextPlatformPrivate();
+
+#if USE(WXGC)
+ wxGCDC* context;
+#else
+ wxWindowDC* context;
+#endif
+ int mswDCStateID;
+ wxRegion gtkCurrentClipRgn;
+ wxRegion gtkPaintClipRgn;
+};
+
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() :
+ context(0),
+ mswDCStateID(0),
+ gtkCurrentClipRgn(wxRegion()),
+ gtkPaintClipRgn(wxRegion())
+{
+}
+
+GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
+{
+}
+
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext* context)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate)
+{
+ setPaintingDisabled(!context);
+ if (context) {
+ // Make sure the context starts in sync with our state.
+ setPlatformFillColor(fillColor());
+ setPlatformStrokeColor(strokeColor());
+ }
+#if USE(WXGC)
+ m_data->context = (wxGCDC*)context;
+#else
+ m_data->context = (wxWindowDC*)context;
+#endif
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ destroyGraphicsContextPrivate(m_common);
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ return (PlatformGraphicsContext*)m_data->context;
+}
+
+void GraphicsContext::savePlatformState()
+{
+ if (m_data->context)
+ {
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->PushState();
+#else
+ // when everything is working with USE_WXGC, we can remove this
+ #if __WXMAC__
+ CGContextRef context;
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc)
+ context = (CGContextRef)gc->GetNativeContext();
+ if (context)
+ CGContextSaveGState(context);
+ #elif __WXMSW__
+ HDC dc = (HDC)m_data->context->GetHDC();
+ m_data->mswDCStateID = ::SaveDC(dc);
+ #elif __WXGTK__
+ m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion;
+ m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion;
+ #endif
+#endif // __WXMAC__
+ }
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (m_data->context)
+ {
+#if USE(WXGC)
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->PopState();
+#else
+ #if __WXMAC__
+ CGContextRef context;
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ if (gc)
+ context = (CGContextRef)gc->GetNativeContext();
+ if (context)
+ CGContextRestoreGState(context);
+ #elif __WXMSW__
+ HDC dc = (HDC)m_data->context->GetHDC();
+ ::RestoreDC(dc, m_data->mswDCStateID);
+ #elif __WXGTK__
+ m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn;
+ m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn;
+ #endif
+
+#endif // USE_WXGC
+ }
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y());
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, angleSpan);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ wxPoint* polygon = new wxPoint[npoints];
+ for (size_t i = 0; i < npoints; i++)
+ polygon[i] = wxPoint(points[i].x(), points[i].y());
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->DrawPolygon((int)npoints, polygon);
+ delete [] polygon;
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->context->SetPen(*wxTRANSPARENT_PEN);
+ m_data->context->SetBrush(wxBrush(color));
+ m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+void GraphicsContext::clip(const FloatRect& r)
+{
+ wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
+ wxPoint pos(0, 0);
+
+ if (windc) {
+#ifndef __WXGTK__
+ wxWindow* window = windc->GetWindow();
+#else
+ wxWindow* window = windc->m_owner;
+#endif
+ if (window) {
+ wxWindow* parent = window->GetParent();
+ // we need to convert from WebView "global" to WebFrame "local" coords.
+ // FIXME: We only want to go to the top WebView.
+ while (parent) {
+ pos += window->GetPosition();
+ parent = parent->GetParent();
+ }
+ }
+ }
+
+ m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y);
+}
+
+void GraphicsContext::clipOut(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipOut(const IntRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint endPoint = origin + IntSize(width, 0);
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
+ m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
+}
+
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar)
+{
+ if (grammar)
+ m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH));
+ else
+ m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH));
+
+ m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y());
+}
+
+void GraphicsContext::clip(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
+{
+ notImplemented();
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ notImplemented();
+ return AffineTransform();
+}
+
+void GraphicsContext::translate(float tx, float ty)
+{
+#if USE(WXGC)
+ if (m_data->context) {
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->Translate(tx, ty);
+ }
+#endif
+}
+
+void GraphicsContext::rotate(float angle)
+{
+#if USE(WXGC)
+ if (m_data->context) {
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->Rotate(angle);
+ }
+#endif
+}
+
+void GraphicsContext::scale(const FloatSize& scale)
+{
+#if USE(WXGC)
+ if (m_data->context) {
+ wxGraphicsContext* gc = m_data->context->GetGraphicsContext();
+ gc->Scale(scale.width(), scale.height());
+ }
+#endif
+}
+
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ FloatRect result;
+
+ wxCoord x = (wxCoord)frect.x();
+ wxCoord y = (wxCoord)frect.y();
+
+ x = m_data->context->LogicalToDeviceX(x);
+ y = m_data->context->LogicalToDeviceY(y);
+ result.setX((float)x);
+ result.setY((float)y);
+ x = (wxCoord)frect.width();
+ y = (wxCoord)frect.height();
+ x = m_data->context->LogicalToDeviceXRel(x);
+ y = m_data->context->LogicalToDeviceYRel(y);
+ result.setWidth((float)x);
+ result.setHeight((float)y);
+ return result;
+}
+
+void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ if (m_data->context)
+ m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
+}
+
+void GraphicsContext::beginPath()
+{
+ notImplemented();
+}
+
+void GraphicsContext::addPath(const Path& path)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->context)
+ m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->context)
+ m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle())));
+
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (m_data->context)
+ m_data->context->SetBrush(wxBrush(color));
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+ return;
+}
+
+void GraphicsContext::setUseAntialiasing(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ notImplemented();
+}
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
+{
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return InterpolationDefault;
+}
+
+void GraphicsContext::fillPath()
+{
+}
+
+void GraphicsContext::strokePath()
+{
+}
+
+void GraphicsContext::drawPath()
+{
+ fillPath();
+ strokePath();
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/ImageBufferData.h b/WebCore/platform/graphics/wx/ImageBufferData.h
new file mode 100644
index 0000000..d4a6114
--- /dev/null
+++ b/WebCore/platform/graphics/wx/ImageBufferData.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 Kevin Ollivier. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+
+#include "OwnPtr.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp
new file mode 100644
index 0000000..ea3dfe8
--- /dev/null
+++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize&)
+{
+}
+
+ImageBuffer::ImageBuffer(const IntSize&, bool grayScale, bool& success) :
+ m_data(IntSize())
+{
+ notImplemented();
+ success = false;
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ notImplemented();
+ return 0;
+}
+
+PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const
+{
+ notImplemented();
+ return 0;
+}
+
+void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&)
+{
+ notImplemented();
+}
+
+String ImageBuffer::toDataURL(const String&) const
+{
+ notImplemented();
+ return String();
+}
+
+Image* ImageBuffer::image() const
+{
+ notImplemented();
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
new file mode 100644
index 0000000..3ce4f2a
--- /dev/null
+++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Computer, Kevin Ollivier. 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 "ImageSource.h"
+
+#include "BMPImageDecoder.h"
+#include "GIFImageDecoder.h"
+#include "ICOImageDecoder.h"
+#include "JPEGImageDecoder.h"
+#include "PNGImageDecoder.h"
+#include "SharedBuffer.h"
+#include "XBMImageDecoder.h"
+
+#include <wx/defs.h>
+#include <wx/bitmap.h>
+#include <wx/image.h>
+#include <wx/rawbmp.h>
+
+namespace WebCore {
+
+ImageDecoder* createDecoder(const SharedBuffer& data)
+{
+ // 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();
+
+ // 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()
+{
+ delete m_decoder;
+}
+
+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.
+ m_decoder = createDecoder(*data);
+ if (!m_decoder)
+ 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
+{
+ return size();
+}
+
+int ImageSource::repetitionCount()
+{
+ if (!m_decoder)
+ return cAnimationNone;
+
+ return m_decoder->repetitionCount();
+}
+
+size_t ImageSource::frameCount() const
+{
+ return m_decoder ? m_decoder->frameCount() : 0;
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ // FIXME: should we be testing the RGBA32Buffer's status as well?
+ return (m_decoder && m_decoder->frameBufferAtIndex(index) != 0);
+}
+
+void ImageSource::clear()
+{
+ delete m_decoder;
+ m_decoder = 0;
+}
+
+NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
+{
+ if (!m_decoder)
+ return 0;
+
+ RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
+ return 0;
+
+ IntRect imageRect = buffer->rect();
+ unsigned char* bytes = (unsigned char*)buffer->bytes().data();
+ long colorSize = buffer->bytes().size();
+
+ typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> PixelData;
+
+ int width = size().width();
+ int height = size().height();
+
+ wxBitmap* bmp = new wxBitmap(width, height, 32);
+ PixelData data(*bmp);
+
+ int rowCounter = 0;
+ long pixelCounter = 0;
+
+ PixelData::Iterator p(data);
+
+ PixelData::Iterator rowStart = p;
+
+ // NB: It appears that the data is in BGRA format instead of RGBA format.
+ // This code works properly on both ppc and intel, meaning the issue is
+ // likely not an issue of byte order getting mixed up on different archs.
+ for (long i = 0; i < buffer->bytes().size()*4; i+=4) {
+ p.Red() = bytes[i+2];
+ p.Green() = bytes[i+1];
+ p.Blue() = bytes[i+0];
+ p.Alpha() = bytes[i+3];
+
+ p++;
+
+ pixelCounter++;
+ if ( (pixelCounter % width ) == 0 ) {
+ rowCounter++;
+ p = rowStart;
+ p.MoveTo(data, 0, rowCounter);
+ }
+
+ }
+
+ bmp->UseAlpha();
+ ASSERT(bmp->IsOk());
+ return bmp;
+}
+
+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;
+
+ float duration = buffer->duration() / 1000.0f;
+
+ // Follow other ports (and WinIE's) behavior to slow annoying ads that
+ // specify a 0 duration.
+ if (duration < 0.051f)
+ return 0.100f;
+ return 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();
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp
new file mode 100644
index 0000000..a05a31f
--- /dev/null
+++ b/WebCore/platform/graphics/wx/ImageWx.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2007 Apple Computer, Kevin Ollivier. 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 "Image.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+
+#include <math.h>
+#include <stdio.h>
+
+#include <wx/defs.h>
+#include <wx/bitmap.h>
+#include <wx/dc.h>
+#include <wx/dcmemory.h>
+#include <wx/dcgraph.h>
+#include <wx/graphics.h>
+#include <wx/image.h>
+#include <wx/thread.h>
+
+// This function loads resources from WebKit
+Vector<char> loadResourceIntoArray(const char*);
+
+namespace WebCore {
+
+// this is in GraphicsContextWx.cpp
+int getWxCompositingOperation(CompositeOperator op, bool hasAlpha);
+
+void FrameData::clear()
+{
+ 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.
+ }
+}
+
+// ================================================
+// Image Class
+// ================================================
+
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
+{
+ Vector<char> arr = loadResourceIntoArray(name);
+ RefPtr<Image> img = BitmapImage::create();
+ RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size());
+ img->setData(buffer, true);
+ return img.release();
+}
+
+void BitmapImage::initPlatformData()
+{
+ // FIXME: NYI
+}
+
+// Drawing Routines
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op)
+{
+ if (!m_source.initialized())
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, dst, solidColor(), op);
+ return;
+ }
+
+#if USE(WXGC)
+ wxGCDC* context = (wxGCDC*)ctxt->platformContext();
+#else
+ wxWindowDC* context = ctxt->platformContext();
+#endif
+
+ startAnimation();
+
+ wxBitmap* bitmap = frameAtIndex(m_currentFrame);
+ if (!bitmap) // If it's too early we won't have an image yet.
+ return;
+
+ // If we're drawing a sub portion of the image or scaling then create
+ // a pattern transformation on the image and draw the transformed pattern.
+ // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ // FIXME: NYI
+
+ ctxt->save();
+
+ // Set the compositing operation.
+ ctxt->setCompositeOperation(op);
+
+ IntRect srcIntRect(src);
+ IntRect dstIntRect(dst);
+ bool rescaling = false;
+ if ((dstIntRect.width() != srcIntRect.width()) || (dstIntRect.height() != srcIntRect.height()))
+ {
+ rescaling = true;
+ wxImage img = bitmap->ConvertToImage();
+ img.Rescale(dstIntRect.width(), dstIntRect.height());
+ bitmap = new wxBitmap(img);
+ }
+ wxMemoryDC mydc;
+ ASSERT(bitmap->GetRefData());
+ mydc.SelectObject(*bitmap);
+
+ context->Blit((wxCoord)dstIntRect.x(),(wxCoord)dstIntRect.y(), (wxCoord)dstIntRect.width(), (wxCoord)dstIntRect.height(), &mydc,
+ (wxCoord)srcIntRect.x(), (wxCoord)srcIntRect.y(), wxCOPY, true);
+ mydc.SelectObject(wxNullBitmap);
+
+ // 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
+ // suddenly becomes invalid after returning. It's possible these errors deal
+ // with reentrancy and threding problems.
+ //delete bitmap;
+ if (rescaling)
+ {
+ delete bitmap;
+ bitmap = NULL;
+ }
+ ctxt->restore();
+}
+
+void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect)
+{
+ if (!m_source.initialized())
+ return;
+
+#if USE(WXGC)
+ wxGCDC* context = (wxGCDC*)ctxt->platformContext();
+#else
+ wxWindowDC* context = ctxt->platformContext();
+#endif
+
+ ctxt->save();
+ ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height()));
+ wxBitmap* bitmap = frameAtIndex(m_currentFrame);
+ if (!bitmap) // If it's too early we won't have an image yet.
+ return;
+
+ float currentW = 0;
+ float currentH = 0;
+
+#if USE(WXGC)
+ wxGraphicsContext* gc = context->GetGraphicsContext();
+ gc->ConcatTransform(patternTransform);
+#endif
+
+ wxMemoryDC mydc;
+ mydc.SelectObject(*bitmap);
+
+ while ( currentW < dstRect.width() ) {
+ while ( currentH < dstRect.height() ) {
+ 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);
+ currentH += srcRect.height();
+ }
+ currentW += srcRect.width();
+ currentH = 0;
+ }
+ ctxt->restore();
+ mydc.SelectObject(wxNullBitmap);
+
+ // 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
+ // suddenly becomes invalid after returning. It's possible these errors deal
+ // with reentrancy and threding problems.
+ //delete bitmap;
+
+ startAnimation();
+
+}
+
+void BitmapImage::checkForSolidColor()
+{
+
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/IntPointWx.cpp b/WebCore/platform/graphics/wx/IntPointWx.cpp
new file mode 100644
index 0000000..389ac9f
--- /dev/null
+++ b/WebCore/platform/graphics/wx/IntPointWx.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006, 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "IntPoint.h"
+
+#include <wx/defs.h>
+#include <wx/gdicmn.h>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const wxPoint& p)
+ : m_x(p.x)
+ , m_y(p.y)
+{
+}
+
+IntPoint::operator wxPoint() const
+{
+ return wxPoint(m_x, m_y);
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/IntRectWx.cpp b/WebCore/platform/graphics/wx/IntRectWx.cpp
new file mode 100644
index 0000000..10c1b55
--- /dev/null
+++ b/WebCore/platform/graphics/wx/IntRectWx.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006, 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "IntRect.h"
+
+#include <wx/defs.h>
+#include <wx/gdicmn.h>
+
+namespace WebCore {
+
+IntRect::IntRect(const wxRect& r)
+ : m_location(IntPoint(r.x, r.y))
+ , m_size(IntSize(r.width, r.height))
+{
+}
+
+IntRect::operator wxRect() const
+{
+ return wxRect(x(), y(), width(), height());
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp
new file mode 100644
index 0000000..5ff9914
--- /dev/null
+++ b/WebCore/platform/graphics/wx/PathWx.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier 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 "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "NotImplemented.h"
+
+#include <stdio.h>
+
+#include <wx/defs.h>
+#include <wx/graphics.h>
+
+namespace WebCore {
+
+int getWxWindRuleForWindRule(WindRule rule)
+{
+ if (rule == RULE_EVENODD)
+ return wxODDEVEN_RULE;
+
+ return wxWINDING_RULE;
+}
+
+Path::Path()
+{
+ m_path = 0;
+ // NB: This only supports the 'default' renderer as determined by wx on
+ // each platform. If an app uses a non-default renderer (e.g. Cairo on Win),
+ // there will be problems, but there's no way we can determine which
+ // renderer an app is using right now with wx API, so we will just handle
+ // the common case.
+#if USE(WXGC)
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ if (renderer) {
+ wxGraphicsPath path = renderer->CreatePath();
+ m_path = new wxGraphicsPath(path);
+ }
+#endif
+}
+
+Path::~Path()
+{
+}
+
+Path::Path(const Path& path)
+{
+ m_path = (PlatformPath*)&path.m_path;
+}
+
+bool Path::contains(const FloatPoint& point, const WindRule rule) const
+{
+ return false;
+}
+
+void Path::translate(const FloatSize&)
+{
+ notImplemented();
+}
+
+FloatRect Path::boundingRect() const
+{
+#if USE(WXGC)
+ if (m_path) {
+ return m_path->GetBox();
+ }
+#endif
+
+ return FloatRect();
+}
+
+Path& Path::operator=(const Path&)
+{
+ notImplemented();
+ return*this;
+}
+
+void Path::clear()
+{
+ if (m_path)
+ delete m_path;
+
+#if USE(WXGC)
+ wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
+ if (renderer) {
+ wxGraphicsPath path = renderer->CreatePath();
+ m_path = new wxGraphicsPath(path);
+ }
+#endif
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+#if USE(WXGC)
+ if (m_path)
+ m_path->MoveToPoint(point.x(), point.y());
+#endif
+}
+
+void Path::addLineTo(const FloatPoint&)
+{
+ notImplemented();
+}
+
+void Path::addQuadCurveTo(const FloatPoint&, const FloatPoint&)
+{
+ notImplemented();
+}
+
+void Path::addBezierCurveTo(const FloatPoint&, const FloatPoint&, const FloatPoint&)
+{
+ notImplemented();
+}
+
+void Path::addArcTo(const FloatPoint&, const FloatPoint&, float)
+{
+ notImplemented();
+}
+
+void Path::closeSubpath()
+{
+ notImplemented();
+}
+
+void Path::addArc(const FloatPoint&, float, float, float, bool)
+{
+ notImplemented();
+}
+
+void Path::addRect(const FloatRect&)
+{
+ notImplemented();
+}
+
+void Path::addEllipse(const FloatRect&)
+{
+ notImplemented();
+}
+
+void Path::transform(const AffineTransform&)
+{
+ notImplemented();
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ notImplemented();
+}
+
+bool Path::isEmpty() const
+{
+ notImplemented();
+ return false;
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/PenWx.cpp b/WebCore/platform/graphics/wx/PenWx.cpp
new file mode 100644
index 0000000..5a131e3
--- /dev/null
+++ b/WebCore/platform/graphics/wx/PenWx.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 "Pen.h"
+
+#include <wx/defs.h>
+#include <wx/pen.h>
+#include <wx/colour.h>
+
+namespace WebCore {
+
+// Pen style conversion functions
+static int penStyleToWxPenStyle(int p)
+{
+ if (p == Pen::SolidLine)
+ return wxSOLID;
+ if (p == Pen::DotLine)
+ return wxDOT;
+ if (p == Pen::DashLine)
+ return wxLONG_DASH;
+ if (p == Pen::NoPen)
+ return wxTRANSPARENT;
+
+ return wxSOLID;
+}
+
+static Pen::PenStyle wxPenStyleToPenStyle(int p)
+{
+ if (p == wxSOLID)
+ return Pen::SolidLine;
+ if (p == wxDOT)
+ return Pen::DotLine;
+ if (p == wxLONG_DASH || p == wxSHORT_DASH || p == wxDOT_DASH || p == wxUSER_DASH)
+ return Pen::DashLine;
+ if (p == wxTRANSPARENT)
+ return Pen::NoPen;
+
+ return Pen::SolidLine;
+}
+
+Pen::Pen(const wxPen& p)
+{
+ wxColour color = p.GetColour();
+ setColor(Color(color.Red(), color.Green(), color.Blue()));
+ setWidth(p.GetWidth());
+ setStyle(wxPenStyleToPenStyle(p.GetStyle()));
+}
+
+Pen::operator wxPen() const
+{
+ return wxPen(wxColour(m_color.red(), m_color.blue(), m_color.green()), width(), penStyleToWxPenStyle(style()));
+}
+
+}
diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
new file mode 100755
index 0000000..a509933
--- /dev/null
+++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 "SimpleFontData.h"
+
+#include "FontCache.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+#include <wtf/MathExtras.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+
+#include <wx/defs.h>
+#include <wx/dcscreen.h>
+#include "fontprops.h"
+
+namespace WebCore
+{
+
+void SimpleFontData::platformInit()
+{
+ wxFont font = m_font.font();
+ wxFontProperties props = wxFontProperties(&font);
+ m_ascent = props.GetAscent();
+ m_descent = props.GetDescent();
+ m_lineSpacing = props.GetLineSpacing();
+ m_xHeight = props.GetXHeight();
+ m_unitsPerEm = 1; // FIXME!
+ m_lineGap = props.GetLineGap();
+}
+
+void SimpleFontData::platformDestroy()
+{
+ delete m_smallCapsFontData;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData){
+ FontDescription desc = FontDescription(fontDescription);
+ desc.setSpecifiedSize(0.70f*fontDescription.computedSize());
+ const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family());
+ m_smallCapsFontData = new SimpleFontData(*pdata);
+ }
+ return m_smallCapsFontData;
+}
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ // FIXME: We will need to implement this to load non-ASCII encoding sites
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ if (m_font.font().Ok())
+ m_treatAsFixedPitch = m_font.font().IsFixedWidth();
+ else
+ m_treatAsFixedPitch = false;
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ // TODO: fix this! Make GetTextExtents a method of wxFont in 2.9
+ int width = 10;
+ GetTextExtent(m_font.font(), (wxChar)glyph, &width, NULL);
+ return width;
+}
+
+}