summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/AffineTransform.cpp91
-rw-r--r--WebCore/platform/graphics/AffineTransform.h57
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp236
-rw-r--r--WebCore/platform/graphics/BitmapImage.h90
-rw-r--r--WebCore/platform/graphics/Color.cpp77
-rw-r--r--WebCore/platform/graphics/Color.h11
-rw-r--r--WebCore/platform/graphics/DashArray.h39
-rw-r--r--WebCore/platform/graphics/FloatPoint.h14
-rw-r--r--WebCore/platform/graphics/FloatRect.cpp13
-rw-r--r--WebCore/platform/graphics/FloatRect.h11
-rw-r--r--WebCore/platform/graphics/Font.cpp311
-rw-r--r--WebCore/platform/graphics/Font.h120
-rw-r--r--WebCore/platform/graphics/FontCache.cpp212
-rw-r--r--WebCore/platform/graphics/FontCache.h20
-rw-r--r--WebCore/platform/graphics/FontData.h11
-rw-r--r--WebCore/platform/graphics/FontDescription.cpp101
-rw-r--r--WebCore/platform/graphics/FontDescription.h54
-rw-r--r--WebCore/platform/graphics/FontFallbackList.cpp35
-rw-r--r--WebCore/platform/graphics/FontFallbackList.h11
-rw-r--r--WebCore/platform/graphics/FontFamily.cpp22
-rw-r--r--WebCore/platform/graphics/FontFamily.h49
-rw-r--r--WebCore/platform/graphics/FontRenderingMode.h37
-rw-r--r--WebCore/platform/graphics/FontSelector.h8
-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.h62
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.cpp97
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.h28
-rw-r--r--WebCore/platform/graphics/Gradient.cpp149
-rw-r--r--WebCore/platform/graphics/Gradient.h121
-rw-r--r--WebCore/platform/graphics/GraphicsContext.cpp167
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h230
-rw-r--r--WebCore/platform/graphics/GraphicsContextPrivate.h112
-rw-r--r--WebCore/platform/graphics/GraphicsTypes.cpp70
-rw-r--r--WebCore/platform/graphics/GraphicsTypes.h12
-rw-r--r--WebCore/platform/graphics/Icon.h24
-rw-r--r--WebCore/platform/graphics/Image.cpp13
-rw-r--r--WebCore/platform/graphics/Image.h35
-rw-r--r--WebCore/platform/graphics/ImageBuffer.h82
-rw-r--r--WebCore/platform/graphics/ImageSource.h14
-rw-r--r--WebCore/platform/graphics/IntPoint.h30
-rw-r--r--WebCore/platform/graphics/IntRect.h13
-rw-r--r--WebCore/platform/graphics/IntSize.h3
-rw-r--r--WebCore/platform/graphics/IntSizeHash.h7
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp40
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h14
-rw-r--r--WebCore/platform/graphics/Path.h14
-rw-r--r--WebCore/platform/graphics/Pattern.cpp46
-rw-r--r--WebCore/platform/graphics/Pattern.h82
-rw-r--r--WebCore/platform/graphics/SimpleFontData.cpp10
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h36
-rw-r--r--WebCore/platform/graphics/StringTruncator.cpp1
-rw-r--r--WebCore/platform/graphics/TextRun.h126
-rw-r--r--WebCore/platform/graphics/UnitBezier.h123
-rw-r--r--WebCore/platform/graphics/WidthIterator.cpp258
-rw-r--r--WebCore/platform/graphics/WidthIterator.h60
-rw-r--r--WebCore/platform/graphics/android/AffineTransformAndroid.cpp44
-rw-r--r--WebCore/platform/graphics/android/FontAndroid.cpp92
-rw-r--r--WebCore/platform/graphics/android/FontCacheAndroid.cpp47
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.cpp3
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.h3
-rw-r--r--WebCore/platform/graphics/android/FontPlatformData.h61
-rw-r--r--WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp42
-rw-r--r--WebCore/platform/graphics/android/GradientAndroid.cpp107
-rw-r--r--WebCore/platform/graphics/android/GraphicsContextAndroid.cpp667
-rw-r--r--WebCore/platform/graphics/android/ImageAndroid.cpp182
-rw-r--r--WebCore/platform/graphics/android/ImageBufferAndroid.cpp177
-rw-r--r--WebCore/platform/graphics/android/ImageBufferData.h31
-rw-r--r--WebCore/platform/graphics/android/ImageSourceAndroid.cpp21
-rw-r--r--WebCore/platform/graphics/android/PathAndroid.cpp61
-rw-r--r--WebCore/platform/graphics/android/PatternAndroid.cpp46
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphics.h25
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.cpp40
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.h83
-rw-r--r--WebCore/platform/graphics/android/android_graphics.cpp11
-rw-r--r--WebCore/platform/graphics/android/android_graphics.h7
-rw-r--r--WebCore/platform/graphics/cairo/AffineTransformCairo.cpp14
-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.cpp324
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h22
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp186
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferData.h44
-rw-r--r--WebCore/platform/graphics/cairo/ImageCairo.cpp52
-rw-r--r--WebCore/platform/graphics/cairo/ImageSourceCairo.cpp27
-rw-r--r--WebCore/platform/graphics/cairo/PathCairo.cpp15
-rw-r--r--WebCore/platform/graphics/cairo/PatternCairo.cpp50
-rw-r--r--WebCore/platform/graphics/cg/AffineTransformCG.cpp8
-rw-r--r--WebCore/platform/graphics/cg/GradientCG.cpp82
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp309
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h8
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferCG.cpp244
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferData.h42
-rw-r--r--WebCore/platform/graphics/cg/ImageCG.cpp147
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp48
-rw-r--r--WebCore/platform/graphics/cg/PDFDocumentImage.h15
-rw-r--r--WebCore/platform/graphics/cg/PathCG.cpp12
-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/FontCacheGtk.cpp67
-rw-r--r--WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp2
-rw-r--r--WebCore/platform/graphics/gtk/FontCustomPlatformData.h3
-rw-r--r--WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp49
-rw-r--r--WebCore/platform/graphics/gtk/FontGtk.cpp206
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformData.h64
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp82
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp229
-rw-r--r--WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp98
-rw-r--r--WebCore/platform/graphics/gtk/IconGtk.cpp20
-rw-r--r--WebCore/platform/graphics/gtk/ImageGtk.cpp11
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp13
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp26
-rw-r--r--WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp142
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp12
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm32
-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/FontCacheMac.mm160
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.cpp2
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.h3
-rw-r--r--WebCore/platform/graphics/mac/FontMac.mm591
-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.h64
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformDataMac.mm47
-rw-r--r--WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp17
-rw-r--r--WebCore/platform/graphics/mac/IconMac.mm26
-rw-r--r--WebCore/platform/graphics/mac/ImageMac.mm24
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h17
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm246
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm122
-rw-r--r--WebCore/platform/graphics/qt/AffineTransformQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/FontCacheQt.cpp18
-rw-r--r--WebCore/platform/graphics/qt/FontCustomPlatformData.cpp4
-rw-r--r--WebCore/platform/graphics/qt/FontCustomPlatformData.h5
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformData.h2
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp85
-rw-r--r--WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/GradientQt.cpp77
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp390
-rw-r--r--WebCore/platform/graphics/qt/IconQt.cpp13
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferData.h48
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp77
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp4
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.h2
-rw-r--r--WebCore/platform/graphics/qt/ImageQt.cpp83
-rw-r--r--WebCore/platform/graphics/qt/ImageSourceQt.cpp73
-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.cpp8
-rw-r--r--WebCore/platform/graphics/qt/PatternQt.cpp46
-rw-r--r--WebCore/platform/graphics/qt/SimpleFontDataQt.cpp8
-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.cpp5
-rw-r--r--WebCore/platform/graphics/win/FontCGWin.cpp314
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp289
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.cpp173
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.h20
-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/FontPlatformData.h111
-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.cpp170
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp (renamed from WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp)6
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp72
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp114
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp38
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp77
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp34
-rw-r--r--WebCore/platform/graphics/win/ImageWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp61
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h9
-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.cpp214
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp53
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp97
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataWin.cpp49
-rw-r--r--WebCore/platform/graphics/win/UniscribeController.cpp26
-rw-r--r--WebCore/platform/graphics/wx/AffineTransformWx.cpp98
-rwxr-xr-xWebCore/platform/graphics/wx/FontCacheWx.cpp3
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformData.h20
-rwxr-xr-xWebCore/platform/graphics/wx/FontPlatformDataWx.cpp12
-rw-r--r--WebCore/platform/graphics/wx/FontWx.cpp36
-rw-r--r--WebCore/platform/graphics/wx/GradientWx.cpp (renamed from WebCore/platform/graphics/win/FontCairoWin.cpp)22
-rw-r--r--WebCore/platform/graphics/wx/GraphicsContextWx.cpp60
-rw-r--r--WebCore/platform/graphics/wx/ImageBufferData.h43
-rw-r--r--WebCore/platform/graphics/wx/ImageBufferWx.cpp37
-rw-r--r--WebCore/platform/graphics/wx/ImageSourceWx.cpp13
-rw-r--r--WebCore/platform/graphics/wx/ImageWx.cpp52
-rw-r--r--WebCore/platform/graphics/wx/PathWx.cpp6
202 files changed, 13276 insertions, 3615 deletions
diff --git a/WebCore/platform/graphics/AffineTransform.cpp b/WebCore/platform/graphics/AffineTransform.cpp
index 664bf28..fdeba44 100644
--- a/WebCore/platform/graphics/AffineTransform.cpp
+++ b/WebCore/platform/graphics/AffineTransform.cpp
@@ -33,6 +33,58 @@
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;
@@ -83,6 +135,14 @@ 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;
@@ -100,4 +160,35 @@ FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
}
+void AffineTransform::blend(const AffineTransform& from, double progress)
+{
+ 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
index c0dc72f..37c6033 100644
--- a/WebCore/platform/graphics/AffineTransform.h
+++ b/WebCore/platform/graphics/AffineTransform.h
@@ -28,15 +28,23 @@
#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 {
@@ -50,25 +58,26 @@ class AffineTransform {
public:
AffineTransform();
AffineTransform(double a, double b, double c, double d, double e, double f);
-#if PLATFORM(CG)
- AffineTransform(CGAffineTransform transform);
-#elif PLATFORM(QT)
- AffineTransform(const QMatrix &matrix);
-#elif PLATFORM(CAIRO)
- AffineTransform(const cairo_matrix_t &matrix);
-#elif PLATFORM(WX) && USE(WXGC)
- AffineTransform(const wxGraphicsMatrix &matrix);
+#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);
@@ -107,16 +116,10 @@ public:
bool isInvertible() const;
AffineTransform inverse() const;
-#if PLATFORM(CG)
- operator CGAffineTransform() const;
-#elif PLATFORM(QT)
- operator QMatrix() const;
-#elif PLATFORM(CAIRO)
- operator cairo_matrix_t() const;
-#elif PLATFORM(SGL)
- operator SkMatrix() const;
-#elif PLATFORM(WX) && USE(WXGC)
- operator wxGraphicsMatrix() const;
+ void blend(const AffineTransform& from, double progress);
+
+#if !PLATFORM(WX) || USE(WXGC)
+ operator PlatformAffineTransform() const;
#endif
bool operator==(const AffineTransform&) const;
@@ -125,19 +128,13 @@ public:
AffineTransform operator*(const AffineTransform&);
private:
-#if PLATFORM(CG)
- CGAffineTransform m_transform;
-#elif PLATFORM(QT)
- QMatrix m_transform;
-#elif PLATFORM(CAIRO)
- cairo_matrix_t m_transform;
-#elif PLATFORM(SGL)
- SkMatrix m_transform;
-#elif PLATFORM(WX) && USE(WXGC)
- wxGraphicsMatrix m_transform;
+#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
index e731ed6..4b21de0 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -31,6 +31,7 @@
#include "ImageObserver.h"
#include "IntRect.h"
#include "PlatformString.h"
+#include "SystemTime.h"
#include "Timer.h"
#include <wtf/Vector.h>
#include "MIMETypeRegistry.h"
@@ -41,20 +42,29 @@ namespace WebCore {
// 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(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
, m_repetitionsComplete(0)
+ , m_desiredFrameStartTime(0)
, m_isSolidColor(false)
- , m_animatingImageType(true)
, 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();
}
@@ -65,14 +75,15 @@ BitmapImage::~BitmapImage()
stopAnimation();
}
-void BitmapImage::destroyDecodedData(bool incremental)
+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) {
+ if (m_frames[i].m_frame && (!preserveNearbyFrames || (i != m_currentFrame && i != nextFrame))) {
sizeChange -= frameSize;
m_frames[i].clear();
}
@@ -105,13 +116,6 @@ void BitmapImage::cacheFrame(size_t index)
size_t numFrames = frameCount();
ASSERT(m_decodedSize == 0 || numFrames > 1);
- if (!m_frames.size() && shouldAnimate()) {
- // Snag the repetition count.
- m_repetitionCount = m_source.repetitionCount();
- if (m_repetitionCount == cAnimationNone)
- m_animatingImageType = false;
- }
-
if (m_frames.size() < numFrames)
m_frames.grow(numFrames);
@@ -119,11 +123,21 @@ void BitmapImage::cacheFrame(size_t index)
if (numFrames == 1 && m_frames[index].m_frame)
checkForSolidColor();
- if (shouldAnimate())
+ 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 = m_frames[index].m_frame ? m_size.width() * m_size.height() * 4 : 0;
+
+ 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())
@@ -140,6 +154,13 @@ IntSize BitmapImage::size() const
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);
@@ -148,6 +169,11 @@ bool BitmapImage::dataChanged(bool allDataReceived)
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();
@@ -155,7 +181,11 @@ bool BitmapImage::dataChanged(bool allDataReceived)
size_t BitmapImage::frameCount()
{
- return m_source.frameCount();
+ if (!m_haveFrameCount) {
+ m_haveFrameCount = true;
+ m_frameCount = m_source.frameCount();
+ }
+ return m_frameCount;
}
bool BitmapImage::isSizeAvailable()
@@ -179,12 +209,23 @@ NativeImagePtr BitmapImage::frameAtIndex(size_t 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_frame)
+ if (index >= m_frames.size() || !m_frames[index].m_haveMetadata)
cacheFrame(index);
return m_frames[index].m_duration;
@@ -193,30 +234,124 @@ float BitmapImage::frameDurationAtIndex(size_t index)
bool BitmapImage::frameHasAlphaAtIndex(size_t index)
{
if (index >= frameCount())
- return 0;
+ return true;
- if (index >= m_frames.size() || !m_frames[index].m_frame)
+ 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 (m_animatingImageType && !m_animationFinished && imageObserver());
+ return (repetitionCount(false) != cAnimationNone && !m_animationFinished && imageObserver());
}
-void BitmapImage::startAnimation()
+void BitmapImage::startAnimation(bool catchUpIfNecessary)
{
if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
return;
- // Don't advance the animation until the current frame has completely loaded.
- if (!m_source.frameIsCompleteAtIndex(m_currentFrame))
+ // 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;
- m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation);
- m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame));
+ // 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()
@@ -232,6 +367,7 @@ 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;
@@ -242,43 +378,61 @@ void BitmapImage::resetAnimation()
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 (imageObserver()->shouldPauseAnimation(this))
- return;
+ if (!skippingFrames && imageObserver()->shouldPauseAnimation(this))
+ return false;
m_currentFrame++;
if (m_currentFrame >= frameCount()) {
- m_repetitionsComplete += 1;
- if (m_repetitionCount && m_repetitionsComplete >= m_repetitionCount) {
+ ++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--;
- return;
+ 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.
+ // 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.
- destroyDecodedData();
-
- // Go ahead and decode the next frame.
- frameAtIndex(m_currentFrame);
+ // Destroy all of our frames and just redecode every time. We save the
+ // current frame since we'll need it in draw() anyway.
+ destroyDecodedData(false, true);
}
-
- // We do not advance the animation explicitly. We rely on a subsequent draw of the image
- // to force a request for the next frame via startAnimation(). This allows images that move offscreen while
- // scrolling to stop animating (thus saving memory from additional decoded frames and
- // CPU time spent doing the decoding).
}
}
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
index 154d829..c5f2a72 100644
--- a/WebCore/platform/graphics/BitmapImage.h
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -45,7 +45,8 @@ typedef struct HBITMAP__ *HBITMAP;
#endif
#if PLATFORM(SGL)
- class SkBitmapRef;
+class SkBitmap;
+class SkBitmapRef;
#endif
namespace WebCore {
@@ -70,6 +71,8 @@ template <typename T> class Timer;
struct FrameData : Noncopyable {
FrameData()
: m_frame(0)
+ , m_haveMetadata(false)
+ , m_isComplete(false)
, m_duration(0)
, m_hasAlpha(true)
{
@@ -83,6 +86,8 @@ struct FrameData : Noncopyable {
void clear();
NativeImagePtr m_frame;
+ bool m_haveMetadata;
+ bool m_isComplete;
float m_duration;
bool m_hasAlpha;
};
@@ -92,15 +97,25 @@ struct FrameData : Noncopyable {
// =================================================
class BitmapImage : public Image {
+ friend class GeneratedImage;
friend class GraphicsContext;
public:
-#if PLATFORM(QT)
- BitmapImage(const QPixmap &pixmap, ImageObserver* = 0);
-#endif
- BitmapImage(ImageObserver* = 0);
+ 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);
@@ -122,23 +137,28 @@ public:
virtual CGImageRef getCGImageRef();
#endif
-#if PLATFORM(QT)
- virtual QPixmap* getPixmap() const;
-#endif
-
#if PLATFORM(WIN)
virtual bool getHBITMAP(HBITMAP);
virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE);
#endif
#if PLATFORM(SGL)
- virtual SkBitmapRef* getBitmap();
+// virtual SkBitmapRef* getBitmap();
virtual void setURL(const String& str);
#endif
virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); }
-private:
+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
@@ -150,24 +170,45 @@ private:
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.
- virtual void destroyDecodedData(bool incremental = false);
+ // 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();
+ 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();
@@ -185,34 +226,31 @@ private:
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.
+ 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
-#if PLATFORM(SGL)
- SkBitmapRef* m_bitmapRef;
-#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_animatingImageType; // Whether or not we're an image type that is capable of animating (GIF).
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.
- unsigned m_decodedSize; // The current size of all decoded frames.
+ mutable bool m_hasUniformFrameSize;
-#if PLATFORM(QT)
- QPixmap *m_pixmap;
-#endif
+ unsigned m_decodedSize; // The current size of all decoded frames.
+ mutable bool m_haveFrameCount;
+ size_t m_frameCount;
};
}
diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp
index b0efff1..3ff589d 100644
--- a/WebCore/platform/graphics/Color.cpp
+++ b/WebCore/platform/graphics/Color.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -26,7 +26,6 @@
#include "config.h"
#include "Color.h"
-#include "DeprecatedString.h"
#include "PlatformString.h"
#include <math.h>
#include <wtf/Assertions.h>
@@ -35,6 +34,7 @@
#include "ColorData.c"
using namespace std;
+using namespace WTF;
namespace WebCore {
@@ -51,6 +51,24 @@ 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)
@@ -92,24 +110,26 @@ RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double
// originally moved here from the CSS parser
bool Color::parseHexColor(const String& name, RGBA32& rgb)
{
- int len = name.length();
- if (len == 3 || len == 6) {
- bool ok;
- int val = name.deprecatedString().toInt(&ok, 16);
- if (ok) {
- if (len == 6) {
- rgb = 0xFF000000 | val;
- return true;
- }
- // #abc converts to #aabbcc according to the specs
- rgb = 0xFF000000
- | (val & 0xF00) << 12 | (val & 0xF00) << 8
- | (val & 0xF0) << 8 | (val & 0xF0) << 4
- | (val & 0xF) << 4 | (val & 0xF);
- return true;
- }
+ 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]);
}
- return false;
+ 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)
@@ -147,10 +167,25 @@ String Color::name() const
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)
{
- DeprecatedString dname = name.deprecatedString();
- const NamedColor* foundColor = dname.isAllASCII() ? findColor(dname.latin1(), dname.length()) : 0;
+ const NamedColor* foundColor = findNamedColor(name);
m_color = foundColor ? foundColor->RGBValue : 0;
m_color |= 0xFF000000;
m_valid = foundColor;
diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h
index 7bbca18..61fc74c 100644
--- a/WebCore/platform/graphics/Color.h
+++ b/WebCore/platform/graphics/Color.h
@@ -33,7 +33,10 @@ typedef struct CGColor* CGColorRef;
#endif
#if PLATFORM(QT)
+#include <qglobal.h>
+QT_BEGIN_NAMESPACE
class QColor;
+QT_END_NAMESPACE
#endif
#if PLATFORM(GTK)
@@ -53,6 +56,9 @@ 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&);
@@ -63,6 +69,8 @@ public:
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*);
@@ -124,7 +132,7 @@ public:
private:
RGBA32 m_color;
- bool m_valid : 1;
+ bool m_valid;
};
inline bool operator==(const Color& a, const Color& b)
@@ -138,7 +146,6 @@ inline bool operator!=(const Color& a, const Color& b)
}
Color focusRingColor();
-void setFocusRingColorChangeFunction(void (*)());
#if PLATFORM(CG)
CGColorRef cgColor(const Color&);
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.h b/WebCore/platform/graphics/FloatPoint.h
index 7b8ba1d..6b3c769 100644
--- a/WebCore/platform/graphics/FloatPoint.h
+++ b/WebCore/platform/graphics/FloatPoint.h
@@ -43,13 +43,20 @@ typedef struct _NSPoint NSPoint;
#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;
@@ -87,7 +94,12 @@ public:
#if PLATFORM(SYMBIAN)
operator TPoint() const;
- FloatPoint(const TPoint& );
+ FloatPoint(const TPoint&);
+#endif
+
+#if PLATFORM(SKIA)
+ operator SkPoint() const;
+ FloatPoint(const SkPoint&);
#endif
FloatPoint matrixTransform(const AffineTransform&) const;
diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp
index bb604d1..ec7b3fa 100644
--- a/WebCore/platform/graphics/FloatRect.cpp
+++ b/WebCore/platform/graphics/FloatRect.cpp
@@ -30,6 +30,7 @@
#include "FloatConversion.h"
#include "IntRect.h"
#include <algorithm>
+#include <math.h>
using std::max;
using std::min;
@@ -111,14 +112,10 @@ void FloatRect::scale(float s)
IntRect enclosingIntRect(const FloatRect& rect)
{
- int l = static_cast<int>(rect.x());
- int t = static_cast<int>(rect.y());
- // FIXME: These two need to be a "ceiling" operation, not rounding.
- // We changed them to do "+ 0.5f" to compile on Win32 where there's
- // no ceilf, but they should be changed back to "ceiling" at some point
- // and we should provide an implementation of ceilf for Win32.
- int r = static_cast<int>(rect.right() + 0.5f);
- int b = static_cast<int>(rect.bottom() + 0.5f);
+ 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
index 867813d..11e3791 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -42,13 +42,19 @@ typedef struct _NSRect NSRect;
#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;
@@ -137,6 +143,11 @@ public:
operator wxRect2DDouble() const;
#endif
+#if PLATFORM(SKIA)
+ FloatRect(const SkRect&);
+ operator SkRect() const;
+#endif
+
private:
FloatPoint m_location;
FloatSize m_size;
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp
index 82bf3b1..a78d27b 100644
--- a/WebCore/platform/graphics/Font.cpp
+++ b/WebCore/platform/graphics/Font.cpp
@@ -1,10 +1,8 @@
-/**
- * This file is part of the html renderer for KDE.
- *
+/*
* 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.
+ * 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
@@ -32,21 +30,14 @@
#include "FontFallbackList.h"
#include "IntPoint.h"
#include "GlyphBuffer.h"
-#include <wtf/unicode/Unicode.h>
+#include "WidthIterator.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
-const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
-
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 /*?*/,
@@ -58,250 +49,7 @@ const uint8_t Font::gRoundingHackCharacterTable[256] = {
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::codePath = Auto;
-
-struct WidthIterator {
- WidthIterator(const Font* font, const TextRun& run);
-
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- bool
-#else
- void
-#endif
- advance(int to, GlyphBuffer* glyphBuffer = 0);
- bool advanceOneCharacter(float& width, GlyphBuffer* 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);
-};
-
-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);
- }
-}
-
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
-#define SIGNAL_ADJUSTED_WIDTHS() adjustedWidths = true
-bool WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
-#else
-#define SIGNAL_ADJUSTED_WIDTHS()
-void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
-#endif
-{
- 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;
-
- float runWidthSoFar = m_runWidthSoFar;
- float lastRoundingWidth = m_finalRoundingWidth;
-
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- bool adjustedWidths = false;
-#endif
-
- 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);
- SIGNAL_ADJUSTED_WIDTHS();
- } else {
- width = fontData->widthForGlyph(glyph);
-#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
- // 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;
- SIGNAL_ADJUSTED_WIDTHS();
- }
-#endif
- }
-
- if (hasExtraSpacing && !m_run.spacingDisabled()) {
- // Account for letter-spacing.
- if (width && m_font->letterSpacing()) {
- width += m_font->letterSpacing();
- SIGNAL_ADJUSTED_WIDTHS();
- }
-
- 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;
- }
- SIGNAL_ADJUSTED_WIDTHS();
- }
-
- // 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();
- SIGNAL_ADJUSTED_WIDTHS();
- }
- }
- }
-
- // 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;
-
-#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
- // 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);
- SIGNAL_ADJUSTED_WIDTHS();
- }
-
- // 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;
- SIGNAL_ADJUSTED_WIDTHS();
- }
-#endif
-
- runWidthSoFar += width;
-
- if (glyphBuffer)
- glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width));
-
- lastRoundingWidth = width - oldWidth;
- }
-
- m_currentCharacter = currentCharacter;
- m_runWidthSoFar = runWidthSoFar;
- m_finalRoundingWidth = lastRoundingWidth;
-
-#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
- return adjustedWidths;
-#endif
-}
-
-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;
-}
+Font::CodePath Font::s_codePath = Auto;
// ============================================================================================
// Font Implementation (Cross-Platform Portion)
@@ -327,7 +75,7 @@ Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
}
Font::Font(const FontPlatformData& fontData, bool isPrinterFont)
- : m_fontList(new FontFallbackList)
+ : m_fontList(FontFallbackList::create())
, m_pageZero(0)
, m_cachedPrimaryFont(0)
, m_letterSpacing(0)
@@ -381,7 +129,8 @@ bool Font::operator==(const Font& other) const
return first == second
&& m_fontDescription == other.m_fontDescription
&& m_letterSpacing == other.m_letterSpacing
- && m_wordSpacing == other.m_wordSpacing;
+ && 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
@@ -442,9 +191,12 @@ const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS
return data;
GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
- const GlyphData& data = smallCapsNode->page()->glyphDataForCharacter(c);
- if (data.fontData)
- return data;
+ 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.
@@ -534,7 +286,7 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const
// 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 = new FontFallbackList();
+ m_fontList = FontFallbackList::create();
m_fontList->invalidate(fontSelector);
m_cachedPrimaryFont = 0;
m_pageZero = 0;
@@ -561,6 +313,11 @@ int Font::lineSpacing() const
return primaryFont()->lineSpacing();
}
+int Font::lineGap() const
+{
+ return primaryFont()->lineGap();
+}
+
float Font::xHeight() const
{
return primaryFont()->xHeight();
@@ -584,12 +341,17 @@ bool Font::isFixedPitch() const
void Font::setCodePath(CodePath p)
{
- codePath = p;
+ s_codePath = p;
+}
+
+Font::CodePath Font::codePath()
+{
+ return s_codePath;
}
bool Font::canUseGlyphCache(const TextRun& run) const
{
- switch (codePath) {
+ switch (s_codePath) {
case Auto:
break;
case Simple:
@@ -753,6 +515,20 @@ float Font::floatWidth(const TextRun& run) const
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);
@@ -846,6 +622,13 @@ int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool include
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
index 84048ed..a99ce12 100644
--- a/WebCore/platform/graphics/Font.h
+++ b/WebCore/platform/graphics/Font.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the html renderer for KDE.
- *
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* (C) 2000 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
@@ -26,6 +24,7 @@
#ifndef Font_h
#define Font_h
+#include "TextRun.h"
#include "FontDescription.h"
#include <wtf/HashMap.h>
@@ -46,102 +45,11 @@ class GlyphBuffer;
class GlyphPageTreeNode;
class GraphicsContext;
class IntPoint;
-class RenderObject;
class SimpleFontData;
-class SVGPaintServer;
+class SVGFontElement;
struct GlyphData;
-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_allowTabs(allowTabs)
- , m_xpos(xpos)
- , m_padding(padding)
- , 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_allowTabs(allowTabs)
- , m_xpos(xpos)
- , m_padding(padding)
- , 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
- {
- }
-
- const 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;
-
- bool m_allowTabs;
- int m_xpos;
- int m_padding;
- 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
-};
-
class Font {
public:
Font();
@@ -170,6 +78,7 @@ public:
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;
@@ -194,8 +103,7 @@ public:
const FontFamily& family() const { return m_fontDescription.family(); }
bool italic() const { return m_fontDescription.italic(); }
- unsigned weight() const { return m_fontDescription.weight(); }
- bool bold() const { return m_fontDescription.bold(); }
+ FontWeight weight() const { return m_fontDescription.weight(); }
#if !PLATFORM(QT)
bool isPlatformFont() const { return m_isPlatformFont; }
@@ -211,6 +119,7 @@ public:
int descent() const;
int height() const { return ascent() + descent(); }
int lineSpacing() const;
+ int lineGap() const;
float xHeight() const;
unsigned unitsPerEm() const;
int spaceWidth() const;
@@ -234,6 +143,7 @@ private:
#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
@@ -250,12 +160,15 @@ private:
#endif
friend struct WidthIterator;
- // Useful for debugging the different font rendering code paths.
public:
-#if !PLATFORM(QT)
+#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 codePath();
+ static CodePath s_codePath;
static const uint8_t gRoundingHackCharacterTable[256];
static bool isRoundingHackCharacter(UChar32 c)
@@ -266,8 +179,13 @@ public:
FontSelector* fontSelector() const;
#endif
static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; }
-// ANDROID: extra parentheses around expressions to suppress warnings
- static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == 0x200e || c == 0x200f || (c >= 0x202a && c <= 0x202e); }
+ 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)
diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp
index 6abbb2e..1c5a987 100644
--- a/WebCore/platform/graphics/FontCache.cpp
+++ b/WebCore/platform/graphics/FontCache.cpp
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -35,34 +36,43 @@
#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, bool bold = false, bool italic = false,
+ 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_bold(bold)
+ , 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_bold == other.m_bold && m_italic == other.m_italic && m_printerFont == other.m_printerFont &&
+ 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;
- bool m_bold;
+ unsigned m_weight;
bool m_italic;
bool m_printerFont;
FontRenderingMode m_renderingMode;
+
+private:
+ static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; }
};
inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
@@ -70,10 +80,10 @@ inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
unsigned hashCodes[4] = {
CaseFoldingHash::hash(fontKey.m_family),
fontKey.m_size,
- static_cast<unsigned>(fontKey.m_bold) << 3 | static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 |
- static_cast<unsigned>(fontKey.m_renderingMode)
+ 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), 4 * sizeof(unsigned) / sizeof(UChar));
+ return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar));
}
struct FontPlatformDataCacheKeyHash {
@@ -92,16 +102,18 @@ struct FontPlatformDataCacheKeyHash {
struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> {
static const bool emptyValueIsZero = true;
- static const bool needsDestruction = false;
- static const FontPlatformDataCacheKey& deletedValue()
+ static const FontPlatformDataCacheKey& emptyValue()
{
- static FontPlatformDataCacheKey key(nullAtom, 0xFFFFFFFFU, false, false);
+ static FontPlatformDataCacheKey key(nullAtom);
return key;
}
- static const FontPlatformDataCacheKey& emptyValue()
+ static void constructDeletedValue(FontPlatformDataCacheKey& slot)
{
- static FontPlatformDataCacheKey key(nullAtom, 0, false, false);
- return key;
+ new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue);
+ }
+ static bool isDeletedValue(const FontPlatformDataCacheKey& value)
+ {
+ return value.isHashTableDeletedValue();
}
};
@@ -144,7 +156,7 @@ FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fo
platformInit();
}
- FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.bold(), fontDescription.italic(),
+ FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.weight(), fontDescription.italic(),
fontDescription.usePrinterFont(), fontDescription.renderingMode());
FontPlatformData* result = 0;
bool foundResult;
@@ -187,38 +199,123 @@ struct FontDataCacheKeyHash {
struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> {
static const bool emptyValueIsZero = true;
- static const bool needsDestruction = false;
- static const FontPlatformData& deletedValue()
- {
- static FontPlatformData key = FontPlatformData::Deleted();
- return key;
- }
+ 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, SimpleFontData*, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache;
+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)
+ if (!gFontDataCache) {
gFontDataCache = new FontDataCache;
+ gInactiveFontData = new ListHashSet<const SimpleFontData*>;
+ }
- SimpleFontData* result = gFontDataCache->get(*platformData);
- if (!result) {
- result = new SimpleFontData(*platformData);
- gFontDataCache->set(*platformData, result);
+ 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;
}
-
- return result;
+ 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)
@@ -270,4 +367,59 @@ const FontData* FontCache::getFontData(const Font& font, int& familyIndex, FontS
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
index e1a704b..816fe64 100644
--- a/WebCore/platform/graphics/FontCache.h
+++ b/WebCore/platform/graphics/FontCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -29,6 +29,8 @@
#ifndef FontCache_h
#define FontCache_h
+#include <limits.h>
+#include <wtf/Vector.h>
#include <wtf/unicode/Unicode.h>
#if PLATFORM(WIN)
@@ -50,8 +52,10 @@ 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.
@@ -61,12 +65,22 @@ public:
static IMLangFontLink2* getFontLinkInterface();
#endif
- static bool fontExists(const FontDescription&, const AtomicString& family);
+ 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&);
diff --git a/WebCore/platform/graphics/FontData.h b/WebCore/platform/graphics/FontData.h
index 352d965..cb79919 100644
--- a/WebCore/platform/graphics/FontData.h
+++ b/WebCore/platform/graphics/FontData.h
@@ -35,6 +35,11 @@ class SimpleFontData;
class FontData : Noncopyable {
public:
+ FontData()
+ : m_maxGlyphPageTreeLevel(0)
+ {
+ }
+
virtual ~FontData();
virtual const SimpleFontData* fontDataForCharacter(UChar32) const = 0;
@@ -42,6 +47,12 @@ public:
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
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
index 6bb232e..d13e86a 100644
--- a/WebCore/platform/graphics/FontDescription.h
+++ b/WebCore/platform/graphics/FontDescription.h
@@ -2,7 +2,8 @@
* 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-6 Apple Computer, Inc.
+ * 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
@@ -25,15 +26,24 @@
#define FontDescription_h
#include "FontFamily.h"
+#include "FontRenderingMode.h"
+#include "FontTraitsMask.h"
namespace WebCore {
-const unsigned cNormalWeight = 50;
-const unsigned cBoldWeight = 63;
-
-// 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 };
+enum FontWeight {
+ FontWeight100,
+ FontWeight200,
+ FontWeight300,
+ FontWeight400,
+ FontWeight500,
+ FontWeight600,
+ FontWeight700,
+ FontWeight800,
+ FontWeight900,
+ FontWeightNormal = FontWeight400,
+ FontWeightBold = FontWeight700
+};
class FontDescription {
public:
@@ -41,11 +51,19 @@ public:
MonospaceFamily, CursiveFamily, FantasyFamily };
FontDescription()
- : m_specifiedSize(0), m_computedSize(0),
- m_italic(false), m_smallCaps(false), m_isAbsoluteSize(false), m_weight(cNormalWeight),
- m_genericFamily(NoFamily), m_usePrinterFont(false), m_renderingMode(NormalRenderingMode), m_keywordSize(0)
- {}
-
+ : 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); }
@@ -54,24 +72,26 @@ public:
float specifiedSize() const { return m_specifiedSize; }
float computedSize() const { return m_computedSize; }
bool italic() const { return m_italic; }
- bool bold() const { return weight() == cBoldWeight; }
int computedPixelSize() const { return int(m_computedSize + 0.5f); }
bool smallCaps() const { return m_smallCaps; }
bool isAbsoluteSize() const { return m_isAbsoluteSize; }
- unsigned weight() const { return m_weight; }
+ 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 setBold(bool b) { m_weight = (b ? cBoldWeight : cNormalWeight); }
void setSmallCaps(bool c) { m_smallCaps = c; }
void setIsAbsoluteSize(bool s) { m_isAbsoluteSize = s; }
- void setWeight(unsigned w) { m_weight = w; }
+ 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; }
@@ -88,7 +108,7 @@ private:
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;
+ unsigned m_weight : 8; // FontWeight
unsigned m_genericFamily : 3; // GenericFamilyType
bool m_usePrinterFont : 1;
diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp
index 049cf7f..ef59c2f 100644
--- a/WebCore/platform/graphics/FontFallbackList.cpp
+++ b/WebCore/platform/graphics/FontFallbackList.cpp
@@ -36,20 +36,34 @@
namespace WebCore {
FontFallbackList::FontFallbackList()
-: m_familyIndex(0)
-, m_pitch(UnknownPitch)
-, m_loadingCustomFonts(false)
-, m_fontSelector(0)
+ : 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
@@ -70,7 +84,7 @@ void FontFallbackList::determinePitch(const Font* font) const
const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realizedFontIndex) const
{
if (realizedFontIndex < m_fontList.size())
- return m_fontList[realizedFontIndex]; // This fallback font is already in our list.
+ 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());
@@ -82,9 +96,10 @@ const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realized
// We are obtaining this font for the first time. We keep track of the families we've looked at before
// in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our
// |m_familyIndex| as it scans for the right font to make.
+ ASSERT(FontCache::generation() == m_generation);
const FontData* result = FontCache::getFontData(*font, m_familyIndex, m_fontSelector.get());
if (result) {
- m_fontList.append(result);
+ m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont()));
if (result->isLoading())
m_loadingCustomFonts = true;
}
@@ -100,8 +115,10 @@ const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const
while (fontData && !fontData->containsCharacters(characters, length))
fontData = fontDataAt(font, ++realizedFontIndex);
- if (!fontData)
+ if (!fontData) {
+ ASSERT(FontCache::generation() == m_generation);
fontData = FontCache::getFontDataForCharacters(*font, characters, length);
+ }
return fontData;
}
@@ -109,7 +126,9 @@ const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const
void FontFallbackList::setPlatformFont(const FontPlatformData& platformData)
{
m_familyIndex = cAllFamiliesScanned;
- m_fontList.append(FontCache::getCachedFontData(&platformData));
+ ASSERT(FontCache::generation() == m_generation);
+ const FontData* fontData = FontCache::getCachedFontData(&platformData);
+ m_fontList.append(pair<const FontData*, bool>(fontData, fontData->isCustomFont()));
}
}
diff --git a/WebCore/platform/graphics/FontFallbackList.h b/WebCore/platform/graphics/FontFallbackList.h
index 38128a2..a23b32c 100644
--- a/WebCore/platform/graphics/FontFallbackList.h
+++ b/WebCore/platform/graphics/FontFallbackList.h
@@ -41,8 +41,9 @@ const int cAllFamiliesScanned = -1;
class FontFallbackList : public RefCounted<FontFallbackList> {
public:
- FontFallbackList();
+ 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; };
@@ -51,19 +52,25 @@ public:
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&);
- mutable Vector<const FontData*, 1> m_fontList;
+ 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
index a185756..12b59a4 100644
--- a/WebCore/platform/graphics/FontFamily.cpp
+++ b/WebCore/platform/graphics/FontFamily.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -29,8 +29,7 @@
namespace WebCore {
FontFamily::FontFamily(const FontFamily& other)
- : RefCounted<FontFamily>()
- , m_family(other.m_family)
+ : m_family(other.m_family)
, m_next(other.m_next)
{
}
@@ -42,14 +41,19 @@ FontFamily& FontFamily::operator=(const FontFamily& other)
return *this;
}
-bool FontFamily::operator==(const FontFamily &compareFontFamily) const
+bool operator==(const FontFamily& a, const FontFamily& b)
{
- if ((!m_next && compareFontFamily.m_next) ||
- (m_next && !compareFontFamily.m_next) ||
- ((m_next && compareFontFamily.m_next) && (*m_next != *(compareFontFamily.m_next))))
+ if (a.family() != b.family())
return false;
-
- return m_family == compareFontFamily.m_family;
+ 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
index 65a64b4..126bd83 100644
--- a/WebCore/platform/graphics/FontFamily.h
+++ b/WebCore/platform/graphics/FontFamily.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -28,14 +28,15 @@
#include "AtomicString.h"
#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
+#include <wtf/ListRefPtr.h>
namespace WebCore {
-class FontFamily : public RefCounted<FontFamily> {
+class SharedFontFamily;
+
+class FontFamily {
public:
FontFamily() { }
-
FontFamily(const FontFamily&);
FontFamily& operator=(const FontFamily&);
@@ -43,19 +44,45 @@ public:
const AtomicString& family() const { return m_family; }
bool familyIsEmpty() const { return m_family.isEmpty(); }
- FontFamily* next() { return m_next.get(); }
- const FontFamily* next() const { return m_next.get(); }
+ const FontFamily* next() const;
- void appendFamily(PassRefPtr<FontFamily> family) { m_next = family; }
+ void appendFamily(PassRefPtr<SharedFontFamily>);
+ PassRefPtr<SharedFontFamily> releaseNext();
- bool operator==(const FontFamily&) const;
- bool operator!=(const FontFamily& x) const { return !(*this == x); }
-
private:
AtomicString m_family;
- RefPtr<FontFamily> m_next;
+ 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
index c5b3651..9b520b9 100644
--- a/WebCore/platform/graphics/FontSelector.h
+++ b/WebCore/platform/graphics/FontSelector.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * 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
@@ -36,8 +36,10 @@ class FontDescription;
class FontSelector : public RefCounted<FontSelector> {
public:
- virtual ~FontSelector() {};
- virtual FontData* getFontData(const FontDescription& fontDescription, const AtomicString& familyName) = 0;
+ virtual ~FontSelector() { }
+ virtual FontData* getFontData(const FontDescription&, const AtomicString& familyName) = 0;
+
+ virtual void fontCacheInvalidated() { }
};
} // namespace WebCore
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
index c8e308c..110b3c2 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -44,20 +44,18 @@ namespace WebCore {
typedef unsigned short Glyph;
class SimpleFontData;
-#if PLATFORM(CG)
-typedef Glyph GlyphBufferGlyph;
-typedef CGSize GlyphBufferAdvance;
-#elif PLATFORM(CAIRO)
+#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;
-typedef FloatSize GlyphBufferAdvance;
-#elif PLATFORM(WX)
-typedef Glyph GlyphBufferGlyph;
-typedef FloatSize GlyphBufferAdvance;
-#elif PLATFORM(SGL)
+#else
typedef Glyph GlyphBufferGlyph;
-typedef FloatSize GlyphBufferAdvance;
-#elif PLATFORM(QT)
-typedef unsigned short 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
@@ -110,10 +108,10 @@ public:
Glyph glyphAt(int index) const
{
-#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(WX) || PLATFORM(SGL)
- return m_glyphs[index];
-#elif PLATFORM(CAIRO)
+#if PLATFORM(CAIRO)
return m_glyphs[index].index;
+#else
+ return m_glyphs[index];
#endif
}
@@ -121,7 +119,7 @@ public:
{
#if PLATFORM(CG)
return m_advances[index].width;
-#elif PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) || PLATFORM(SGL)
+#else
return m_advances[index].width();
#endif
}
@@ -138,21 +136,21 @@ public:
void add(Glyph glyph, const SimpleFontData* font, float width, const FloatSize* offset = 0)
{
m_fontData.append(font);
-#if PLATFORM(CG)
- m_glyphs.append(glyph);
- CGSize advance;
- advance.width = width;
- advance.height = 0;
- m_advances.append(advance);
-#elif PLATFORM(CAIRO)
+#if PLATFORM(CAIRO)
cairo_glyph_t cairoGlyph;
cairoGlyph.index = glyph;
m_glyphs.append(cairoGlyph);
- m_advances.append(FloatSize(width, 0));
-#elif PLATFORM(QT) || PLATFORM(WX) || PLATFORM(SGL)
+#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);
@@ -173,6 +171,20 @@ public:
bool hasAdjustedWidths() const { return m_hasAdjustedWidths; }
#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;
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
index 53c94b8..6b9d23d 100644
--- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp
@@ -65,6 +65,31 @@ GlyphPageTreeNode* GlyphPageTreeNode::getRoot(unsigned pageNumber)
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.
@@ -78,6 +103,18 @@ void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData)
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);
@@ -146,7 +183,7 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu
}
}
- m_page = new GlyphPage(this);
+ 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
@@ -160,19 +197,32 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu
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++)
- m_page->setGlyphDataForIndex(i, 0, 0);
+ pageToFill->setGlyphDataForIndex(i, 0, 0);
}
zeroFilled = true;
}
- haveGlyphs |= m_page->fill(from, to - from, buffer + from * (start < 0x10000 ? 1 : 2), (to - from) * (start < 0x10000 ? 1 : 2), range.fontData());
+ 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
@@ -208,7 +258,7 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu
m_page = parentPage;
} else {
// Combine the parent's glyphs and ours to form a new more complete page.
- m_page = new GlyphPage(this);
+ m_page = GlyphPage::create(this);
// Overlay the parent page on the fallback page. Check if the fallback font
// has added anything.
@@ -231,7 +281,7 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu
}
}
} else {
- m_page = new GlyphPage(this);
+ 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
@@ -264,9 +314,10 @@ GlyphPageTreeNode* GlyphPageTreeNode::getChild(const FontData* fontData, unsigne
#ifndef NDEBUG
child->m_pageNumber = m_pageNumber;
#endif
- if (fontData)
+ if (fontData) {
m_children.set(fontData, child);
- else {
+ fontData->setMaxGlyphPageTreeLevel(max(fontData->maxGlyphPageTreeLevel(), child->m_level));
+ } else {
m_systemFallbackChild = child;
child->m_isSystemFallback = true;
}
@@ -298,4 +349,36 @@ void GlyphPageTreeNode::pruneCustomFontData(const FontData* fontData)
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
index 2619888..240b492 100644
--- a/WebCore/platform/graphics/GlyphPageTreeNode.h
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -29,9 +29,10 @@
#ifndef GlyphPageTreeNode_h
#define GlyphPageTreeNode_h
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/unicode/Unicode.h>
-#include <wtf/HashMap.h>
namespace WebCore {
@@ -57,14 +58,9 @@ struct GlyphData {
// 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> {
- GlyphPage()
- : m_owner(0)
- {
- }
-
- GlyphPage(GlyphPageTreeNode* owner)
- : m_owner(owner)
+ static PassRefPtr<GlyphPage> create(GlyphPageTreeNode* owner)
{
+ return adoptRef(new GlyphPage(owner));
}
static const size_t size = 256; // Covers Latin-1 in a single page.
@@ -83,8 +79,15 @@ struct GlyphPage : public RefCounted<GlyphPage> {
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* fontData);
+ 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)
@@ -132,8 +135,10 @@ public:
}
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);
@@ -147,6 +152,9 @@ public:
// 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);
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
index 2f2f97e..9cd2969 100644
--- a/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/WebCore/platform/graphics/GraphicsContext.cpp
@@ -27,7 +27,10 @@
#include "GraphicsContext.h"
#include "BidiResolver.h"
+#include "Generator.h"
+#include "GraphicsContextPrivate.h"
#include "Font.h"
+#include "NotImplemented.h"
using namespace std;
@@ -54,7 +57,7 @@ public:
}
unsigned offset() const { return m_offset; }
- void increment(BidiResolver<TextRunIterator, BidiCharacterRun>&) { 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()); }
@@ -71,44 +74,6 @@ private:
int m_offset;
};
-struct GraphicsContextState {
- GraphicsContextState()
- : strokeStyle(SolidStroke)
- , strokeThickness(0)
- , strokeColor(Color::black)
- , fillColor(Color::black)
- , textDrawingMode(cTextFill)
- , paintingDisabled(false)
- {}
-
- Font font;
- StrokeStyle strokeStyle;
- float strokeThickness;
- Color strokeColor;
- Color fillColor;
- int textDrawingMode;
- bool paintingDisabled;
-};
-
-class GraphicsContextPrivate {
-public:
- GraphicsContextPrivate();
-
- GraphicsContextState state;
- Vector<GraphicsContextState> stack;
- Vector<IntRect> m_focusRingRects;
- int m_focusRingWidth;
- int m_focusRingOffset;
- bool m_updatingControlTints;
-};
-
-GraphicsContextPrivate::GraphicsContextPrivate()
- : m_focusRingWidth(0)
- , m_focusRingOffset(0)
- , m_updatingControlTints(false)
-{
-}
-
GraphicsContextPrivate* GraphicsContext::createGraphicsContextPrivate()
{
return new GraphicsContextPrivate;
@@ -169,10 +134,36 @@ void GraphicsContext::setStrokeStyle(const StrokeStyle& 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;
@@ -188,8 +179,29 @@ 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);
}
@@ -199,6 +211,50 @@ 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;
@@ -248,7 +304,7 @@ void GraphicsContext::drawText(const TextRun& run, const IntPoint& point, int fr
font().drawText(this, run, point, from, to);
}
-void GraphicsContext::drawBidiText(const TextRun& run, const IntPoint& point)
+void GraphicsContext::drawBidiText(const TextRun& run, const FloatPoint& point)
{
if (paintingDisabled())
return;
@@ -258,7 +314,8 @@ void GraphicsContext::drawBidiText(const TextRun& run, const IntPoint& point)
bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride())));
- bidiResolver.createBidiRunsForLine(TextRunIterator(&run, 0), TextRunIterator(&run, run.length()));
+ bidiResolver.setPosition(TextRunIterator(&run, 0));
+ bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()));
if (!bidiResolver.runCount())
return;
@@ -340,11 +397,9 @@ const Vector<IntRect>& GraphicsContext::focusRingRects() const
return m_common->m_focusRingRects;
}
-static const int cInterpolationCutoff = 800 * 800;
-
void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale)
{
- if (paintingDisabled())
+ if (paintingDisabled() || !image)
return;
float tsw = src.width();
@@ -362,19 +417,18 @@ void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const Float
if (th == -1)
th = image->height();
- bool shouldUseLowQualityInterpolation = useLowQualityScale && (tsw != tw || tsh != th) && tsw * tsh > cInterpolationCutoff;
- if (shouldUseLowQualityInterpolation) {
+ if (useLowQualityScale) {
save();
- setUseLowQualityImageInterpolation(true);
+ setImageInterpolationQuality(InterpolationNone);
}
image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op);
- if (shouldUseLowQualityInterpolation)
+ if (useLowQualityScale)
restore();
}
void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op)
{
- if (paintingDisabled())
+ if (paintingDisabled() || !image)
return;
image->drawTiled(this, rect, srcPoint, tileSize, op);
@@ -382,12 +436,12 @@ void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const In
void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op)
{
- if (paintingDisabled())
+ if (paintingDisabled() || !image)
return;
if (hRule == Image::StretchTile && vRule == Image::StretchTile)
// Just do a scale.
- return drawImage(image, dest, srcRect);
+ return drawImage(image, dest, srcRect, op);
image->drawTiled(this, dest, srcRect, hRule, vRule, op);
}
@@ -423,7 +477,14 @@ void GraphicsContext::setTextDrawingMode(int mode)
setPlatformTextDrawingMode(mode);
}
-#if !PLATFORM(CG)
+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)
@@ -431,7 +492,7 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode)
}
#endif
-#if !PLATFORM(QT) && !PLATFORM(CAIRO)
+#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA)
void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&)
{
}
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index f75c287..95bdc90 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -26,6 +26,7 @@
#ifndef GraphicsContext_h
#define GraphicsContext_h
+#include "DashArray.h"
#include "FloatRect.h"
#include "Image.h"
#include "IntRect.h"
@@ -34,21 +35,21 @@
#include <wtf/Noncopyable.h>
#include <wtf/Platform.h>
-#ifdef ANDROID_CANVAS_IMPL
- #include "PlatformGraphics.h"
-#endif
-
#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;
@@ -68,6 +69,8 @@ class wxWindowDC;
#else
typedef wxWindowDC PlatformGraphicsContext;
#endif
+#elif PLATFORM(SKIA)
+typedef class PlatformContextSkia PlatformGraphicsContext;
#else
typedef void PlatformGraphicsContext;
#endif
@@ -79,6 +82,14 @@ typedef struct _GdkEventExpose GdkEventExpose;
#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 {
@@ -89,10 +100,14 @@ namespace WebCore {
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.
@@ -108,6 +123,22 @@ namespace WebCore {
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*);
@@ -124,104 +155,67 @@ namespace WebCore {
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);
-#ifdef ANDROID_CANVAS_IMPL
- /** Fill the specified path using the optional gradient or pattern, using the following
- precedence. If/when gradients/patterns are added to the graphics context, these
- parameters can go away
- 1) use gradient if gradient != null
- 2) use pattern if pattern != null
- 3) use color in the graphics context
- */
- void fillPath(const Path&, PlatformGradient*, PlatformPattern*);
- /** Stroke the specified path using the optional gradient or pattern, using the following
- precedence. If/when gradients/patterns are added to the graphics context, these
- parameters can go away
- 1) use gradient if gradient != null
- 2) use pattern if pattern != null
- 3) use color in the graphics context
- */
- void strokePath(const Path&, PlatformGradient*, PlatformPattern*);
- /** Fill the specified rect using the optional gradient or pattern, using the following
- precedence. If/when gradients/patterns are added to the graphics context, these
- parameters can go away
- 1) use gradient if gradient != null
- 2) use pattern if pattern != null
- 3) use color in the graphics context
- */
- void fillRect(const FloatRect&, PlatformGradient*, PlatformPattern*);
- /** Stroke the specified rect using the optional gradient or pattern, using the following
- precedence. If/when gradients/patterns are added to the graphics context, these
- parameters can go away
- 1) use gradient if gradient != null
- 2) use pattern if pattern != null
- 3) use color in the graphics context
- */
- void strokeRect(const FloatRect&, float lineWidth, PlatformGradient*, PlatformPattern*);
-
- /** Return a platform specific linear-gradient. Use freePlatformGradient() when you are
- done with it.
- stopData is { stop, red, green, blue, alpha } per entry
- */
- static PlatformGradient* newPlatformLinearGradient(const FloatPoint& p0, const FloatPoint& p1,
- const float stopData[5], int count);
-
- /** Return a platform specific radial-gradient. Use freePlatformGradient() when you are
- done with it.
- stopData is { stop, red, green, blue, alpha } per entry
- */
- static PlatformGradient* newPlatformRadialGradient(const FloatPoint& p0, float r0,
- const FloatPoint& p1, float r1,
- const float stopData[5], int count);
- static void freePlatformGradient(PlatformGradient*);
-
- /** Return a platform specific pattern. Use freePlatformPattern() when you are
- done with it.
- */
- static PlatformPattern* newPlatformPattern(Image* image,
- Image::TileRule hRule, Image::TileRule vRule);
- static void freePlatformPattern(PlatformPattern*);
-
- /** 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);
- /** Called with a context returned by createOffscreenContext. Draw the underlying
- bitmap to the current context. Similar to drawImage(), but this hides how
- to extract the bitmap from ctx from the portable code.
- If srcRect is NULL, it is assumed that we want to draw the entire bitmap represented
- by the GraphicsContext.
- */
- void drawOffscreenContext(GraphicsContext* ctx, const WebCore::FloatRect* srcRect,
- const WebCore::FloatRect& dstRect);
-
- /** Return the clip bounds in local coordinates. It can be an approximation, as long as
- the returned bounds completely enclose the actual clip.
- */
- FloatRect getClipLocalBounds() const;
-#endif
+ 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 IntRect&, const Color&);
+
+ 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);
@@ -235,26 +229,23 @@ namespace WebCore {
void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect,
Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile,
CompositeOperator = CompositeSourceOver);
-#if PLATFORM(CG)
- void setUseLowQualityImageInterpolation(bool = true);
- bool useLowQualityImageInterpolation() const;
-#else
- void setUseLowQualityImageInterpolation(bool = true) {}
- bool useLowQualityImageInterpolation() const { return false; }
-#endif
- void clip(const IntRect&);
+ 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 IntPoint&);
+ 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&);
@@ -272,6 +263,7 @@ namespace WebCore {
void endTransparencyLayer();
void setShadow(const IntSize&, int blur, const Color&);
+ bool getShadow(IntSize&, int&, Color&) const;
void clearShadow();
void initFocusRing(int width, int offset);
@@ -281,10 +273,14 @@ namespace WebCore {
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);
@@ -307,14 +303,43 @@ namespace WebCore {
void setUseAntialiasing(bool = true);
#if PLATFORM(WIN)
- GraphicsContext(HDC); // FIXME: To be removed.
+ GraphicsContext(HDC, bool hasAlpha = false); // FIXME: To be removed.
bool inTransparencyLayer() const;
- HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
- void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true); // The passed in HDC should be the one handed back by getWindowsContext.
+ 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)
- void setFillRule(WindRule);
+ bool inTransparencyLayer() const;
PlatformPath* currentPath();
#endif
@@ -322,18 +347,23 @@ namespace WebCore {
void setGdkExposeEvent(GdkEventExpose*);
GdkDrawable* gdkDrawable() const;
GdkEventExpose* gdkExposeEvent() const;
- IntPoint translatePoint(const IntPoint&) 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 setPlatformFont(const Font& font);
+
+ void setPlatformShadow(const IntSize&, int blur, const Color&);
+ void clearPlatformShadow();
int focusRingWidth() const;
int focusRingOffset() const;
@@ -343,7 +373,7 @@ namespace WebCore {
static void destroyGraphicsContextPrivate(GraphicsContextPrivate*);
GraphicsContextPrivate* m_common;
- GraphicsContextPlatformPrivate* m_data;
+ GraphicsContextPlatformPrivate* m_data; // Deprecated; m_commmon can just be downcasted. To be removed.
};
} // namespace WebCore
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
index 736356f..761bf40 100644
--- a/WebCore/platform/graphics/GraphicsTypes.cpp
+++ b/WebCore/platform/graphics/GraphicsTypes.cpp
@@ -116,4 +116,74 @@ String lineJoinName(LineJoin join)
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
index b3ca99a..cdf5e31 100644
--- a/WebCore/platform/graphics/GraphicsTypes.h
+++ b/WebCore/platform/graphics/GraphicsTypes.h
@@ -56,6 +56,10 @@ namespace WebCore {
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&);
@@ -65,6 +69,12 @@ namespace WebCore {
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
index 310c25a..444c67c 100644
--- a/WebCore/platform/graphics/Icon.h
+++ b/WebCore/platform/graphics/Icon.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * 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
@@ -21,8 +21,10 @@
#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>
@@ -36,7 +38,9 @@ typedef struct HICON__* HICON;
#elif PLATFORM(QT)
#include <QIcon>
#elif PLATFORM(GTK)
-#include <gdk/gdk.h>
+typedef struct _GdkPixbuf GdkPixbuf;
+#elif PLATFORM(CHROMIUM)
+#include "PlatformIcon.h"
#endif
namespace WebCore {
@@ -47,29 +51,33 @@ class String;
class Icon : public RefCounted<Icon> {
public:
- Icon();
+ static PassRefPtr<Icon> createIconForFile(const String& filename);
+ static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames);
+
~Icon();
-
- static PassRefPtr<Icon> newIconForFile(const String& filename);
void paint(GraphicsContext*, const IntRect&);
#if PLATFORM(WIN)
- Icon(HICON);
+ static PassRefPtr<Icon> create(HICON hIcon) { return adoptRef(new Icon(hIcon)); }
#endif
private:
#if PLATFORM(MAC)
Icon(NSImage*);
-#endif
-#if PLATFORM(MAC)
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
};
diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp
index 8bf7c68..ca6954e 100644
--- a/WebCore/platform/graphics/Image.cpp
+++ b/WebCore/platform/graphics/Image.cpp
@@ -28,6 +28,7 @@
#include "Image.h"
#include "AffineTransform.h"
+#include "BitmapImage.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "MIMETypeRegistry.h"
@@ -49,6 +50,12 @@ Image::~Image()
{
}
+Image* Image::nullImage()
+{
+ static RefPtr<Image> nullImage = BitmapImage::create();
+ return nullImage.get();
+}
+
bool Image::supportsType(const String& type)
{
return MIMETypeRegistry::isSupportedImageResourceMIMEType(type);
@@ -118,9 +125,6 @@ static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const Fl
void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op)
{
- if (!nativeImageForCurrentFrame())
- return;
-
if (mayFillWithSolidColor()) {
fillWithSolidColor(ctxt, destRect, solidColor(), op);
return;
@@ -161,9 +165,6 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl
// 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 (!nativeImageForCurrentFrame())
- return;
-
if (mayFillWithSolidColor()) {
fillWithSolidColor(ctxt, dstRect, solidColor(), op);
return;
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
index 4ef5bf7..1419b2d 100644
--- a/WebCore/platform/graphics/Image.h
+++ b/WebCore/platform/graphics/Image.h
@@ -47,9 +47,15 @@ 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
@@ -73,15 +79,23 @@ class String;
// This class gets notified when an image creates or destroys decoded frames and when it advances animation frames.
class ImageObserver;
-class Image : Noncopyable {
+class Image : public RefCounted<Image> {
+ friend class GeneratedImage;
friend class GraphicsContext;
public:
- Image(ImageObserver* = 0);
virtual ~Image();
- static Image* loadPlatformResource(const char* name);
+ 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
@@ -97,11 +111,9 @@ public:
bool setData(PassRefPtr<SharedBuffer> data, bool allDataReceived);
virtual bool dataChanged(bool allDataReceived) { return false; }
-
- // FIXME: PDF/SVG will be underreporting decoded sizes and will be unable to prune because these functions are not
- // implemented yet for those image types.
- virtual void destroyDecodedData(bool incremental = false) {};
- virtual unsigned decodedSize() const { return 0; }
+
+ virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) = 0;
+ virtual unsigned decodedSize() const = 0;
SharedBuffer* data() { return m_data.get(); }
@@ -128,10 +140,6 @@ public:
virtual CGImageRef getCGImageRef() { return 0; }
#endif
-#if PLATFORM(QT)
- virtual QPixmap* getPixmap() const { return 0; }
-#endif
-
#if PLATFORM(WIN)
virtual bool getHBITMAP(HBITMAP) { return false; }
virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE) { return false; }
@@ -143,9 +151,10 @@ public:
#endif
protected:
+ Image(ImageObserver* = 0);
+
static void fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op);
-private:
#if PLATFORM(WIN)
virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator) { }
#endif
diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h
index c815c8d..7c68fc8 100644
--- a/WebCore/platform/graphics/ImageBuffer.h
+++ b/WebCore/platform/graphics/ImageBuffer.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * 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
@@ -27,69 +27,59 @@
#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>
-#if PLATFORM(CG)
-typedef struct CGImage* CGImageRef;
-#endif
-
-#if PLATFORM(QT)
-#include <QPixmap>
-class QPainter;
-#endif
-
-#if PLATFORM(SGL)
-#include <memory>
-#endif
-
-#if PLATFORM(CAIRO)
-typedef struct _cairo_surface cairo_surface_t;
-#endif
-
namespace WebCore {
class GraphicsContext;
- class RenderObject;
+ class ImageData;
+ class IntPoint;
+ class IntRect;
+ class String;
class ImageBuffer : Noncopyable {
public:
- static std::auto_ptr<ImageBuffer> create(const IntSize&, bool grayScale);
+ // 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();
- IntSize size() const { return m_size; }
+ const IntSize& size() const { return m_size; }
GraphicsContext* context() const;
-#if PLATFORM(CG)
- CGImageRef cgImage() const;
-#elif PLATFORM(QT)
- QPixmap* pixmap() const;
-#elif PLATFORM(CAIRO)
- cairo_surface_t* surface() const;
-#endif
+ 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:
- void* m_data;
- IntSize m_size;
+ ImageBufferData m_data;
+ IntSize m_size;
OwnPtr<GraphicsContext> m_context;
+ mutable RefPtr<Image> m_image;
-#if PLATFORM(CG)
- ImageBuffer(void* imageData, const IntSize&, std::auto_ptr<GraphicsContext>);
- mutable CGImageRef m_cgImage;
-#elif PLATFORM(QT)
- ImageBuffer(const QPixmap &px);
- mutable QPixmap m_pixmap;
- mutable QPainter* m_painter;
-#elif PLATFORM(CAIRO)
- ImageBuffer(cairo_surface_t* surface);
- mutable cairo_surface_t* m_surface;
-#endif
-#if PLATFORM(SGL)
- ImageBuffer(const IntSize&, std::auto_ptr<GraphicsContext>);
-#endif
+ // 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);
};
-}
-#endif
+} // namespace WebCore
+
+#endif // ImageBuffer_h
diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h
index c99b00f..a9f346d 100644
--- a/WebCore/platform/graphics/ImageSource.h
+++ b/WebCore/platform/graphics/ImageSource.h
@@ -36,7 +36,10 @@ 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;
@@ -44,6 +47,8 @@ typedef struct _cairo_surface cairo_surface_t;
#include "SkString.h"
class SkBitmapRef;
class PrivateAndroidImageSourceRec;
+#elif PLATFORM(SKIA)
+class NativeImageSkia;
#endif
namespace WebCore {
@@ -71,10 +76,14 @@ struct NativeImageSourcePtr {
};
typedef const Vector<char>* NativeBytePtr;
typedef SkBitmapRef* NativeImagePtr;
-#else
+#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;
@@ -93,7 +102,8 @@ public:
bool isSizeAvailable();
IntSize size() const;
-
+ IntSize frameSizeAtIndex(size_t) const;
+
int repetitionCount();
size_t frameCount() const;
diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h
index bd34d2a..cb24b4e 100644
--- a/WebCore/platform/graphics/IntPoint.h
+++ b/WebCore/platform/graphics/IntPoint.h
@@ -45,7 +45,9 @@ typedef struct _NSPoint NSPoint;
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
@@ -57,6 +59,11 @@ class TPoint;
class wxPoint;
#endif
+#if PLATFORM(SKIA)
+struct SkPoint;
+struct SkIPoint;
+#endif
+
namespace WebCore {
class IntPoint {
@@ -72,6 +79,23 @@ public:
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;
@@ -104,6 +128,12 @@ public:
operator wxPoint() const;
#endif
+#if PLATFORM(SKIA)
+ IntPoint(const SkIPoint&);
+ operator SkIPoint() const;
+ operator SkPoint() const;
+#endif
+
private:
int m_x, m_y;
};
diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h
index 84adf20..03784a3 100644
--- a/WebCore/platform/graphics/IntRect.h
+++ b/WebCore/platform/graphics/IntRect.h
@@ -44,7 +44,9 @@ typedef struct _NSRect NSRect;
#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
@@ -56,6 +58,11 @@ class TRect;
class wxRect;
#endif
+#if PLATFORM(SKIA)
+struct SkRect;
+struct SkIRect;
+#endif
+
namespace WebCore {
class FloatRect;
@@ -151,6 +158,12 @@ public:
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
diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h
index faf58c6..7245408 100644
--- a/WebCore/platform/graphics/IntSize.h
+++ b/WebCore/platform/graphics/IntSize.h
@@ -43,7 +43,10 @@ typedef struct _NSSize NSSize;
#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;
diff --git a/WebCore/platform/graphics/IntSizeHash.h b/WebCore/platform/graphics/IntSizeHash.h
index 142533e..ad6eac3 100644
--- a/WebCore/platform/graphics/IntSizeHash.h
+++ b/WebCore/platform/graphics/IntSizeHash.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * 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
@@ -31,7 +31,6 @@ 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; };
@@ -39,8 +38,8 @@ namespace WTF {
template<> struct HashTraits<IntSize> : GenericHashTraits<IntSize> {
static const bool emptyValueIsZero = true;
static const bool needsDestruction = false;
- static const bool needsRef = false;
- static IntSize deletedValue() { return IntSize(-1, -1); }
+ 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
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index 82e9950..21e31fc 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -30,6 +30,9 @@
#include "IntRect.h"
#include "MIMETypeRegistry.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "Document.h"
#if PLATFORM(MAC)
#include "MediaPlayerPrivateQTKit.h"
@@ -37,6 +40,10 @@
#include "MediaPlayerPrivateQuickTimeWin.h"
#elif PLATFORM(GTK)
#include "MediaPlayerPrivateGStreamer.h"
+#elif PLATFORM(QT)
+#include "MediaPlayerPrivatePhonon.h"
+#elif PLATFORM(CHROMIUM)
+#include "MediaPlayerPrivateChromium.h"
#endif
namespace WebCore {
@@ -44,10 +51,10 @@ namespace WebCore {
MediaPlayer::MediaPlayer(MediaPlayerClient* client)
: m_mediaPlayerClient(client)
, m_private(new MediaPlayerPrivate(this))
- , m_parentWidget(0)
+ , m_frameView(0)
, m_visible(false)
, m_rate(1.0f)
- , m_volume(0.5f)
+ , m_volume(1.0f)
{
}
@@ -56,7 +63,7 @@ MediaPlayer::~MediaPlayer()
delete m_private;
}
-void MediaPlayer::load(String url)
+void MediaPlayer::load(const String& url)
{
m_private->load(url);
}
@@ -111,6 +118,14 @@ 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();
@@ -128,10 +143,8 @@ float MediaPlayer::volume() const
void MediaPlayer::setVolume(float volume)
{
- if (volume != m_volume) {
- m_volume = volume;
- m_private->setVolume(volume);
- }
+ m_volume = volume;
+ m_private->setVolume(volume);
}
float MediaPlayer::rate() const
@@ -141,8 +154,6 @@ float MediaPlayer::rate() const
void MediaPlayer::setRate(float rate)
{
- if (rate == m_rate)
- return;
m_rate = rate;
m_private->setRate(rate);
}
@@ -184,8 +195,6 @@ unsigned MediaPlayer::totalBytes()
void MediaPlayer::setRect(const IntRect& r)
{
- if (m_rect == r)
- return;
m_rect = r;
m_private->setRect(r);
}
@@ -197,8 +206,6 @@ bool MediaPlayer::visible() const
void MediaPlayer::setVisible(bool b)
{
- if (m_visible == b)
- return;
m_visible = b;
m_private->setVisible(b);
}
@@ -208,6 +215,13 @@ 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);
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 2c78664..1beab95 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -35,15 +35,14 @@
namespace WebCore {
+class FrameView;
class GraphicsContext;
class IntSize;
class MediaPlayer;
class MediaPlayerPrivate;
class String;
-class Widget;
-class MediaPlayerClient
-{
+class MediaPlayerClient {
public:
virtual ~MediaPlayerClient() { }
virtual void mediaPlayerNetworkStateChanged(MediaPlayer*) { }
@@ -59,18 +58,19 @@ public:
virtual ~MediaPlayer();
static bool isAvailable();
+ static bool supportsType(const String&);
static void getSupportedTypes(HashSet<String>&);
IntSize naturalSize();
bool hasVideo();
- Widget* parentWidget() const { return m_parentWidget; }
- void setParentWidget(Widget* parent) { m_parentWidget = parent; }
+ void setFrameView(FrameView* frameView) { m_frameView = frameView; }
+ bool inMediaDocument();
IntRect rect() const { return m_rect; }
void setRect(const IntRect& r);
- void load(String url);
+ void load(const String& url);
void cancelLoad();
bool visible() const;
@@ -124,7 +124,7 @@ private:
MediaPlayerClient* m_mediaPlayerClient;
MediaPlayerPrivate* m_private;
- Widget* m_parentWidget;
+ FrameView* m_frameView;
IntRect m_rect;
bool m_visible;
float m_rate;
diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h
index d63ba0b..06e6ee4 100644
--- a/WebCore/platform/graphics/Path.h
+++ b/WebCore/platform/graphics/Path.h
@@ -30,7 +30,10 @@
#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;
@@ -43,6 +46,9 @@ namespace WebCore {
struct CairoPath;
}
typedef WebCore::CairoPath PlatformPath;
+#elif PLATFORM(SKIA)
+class SkPath;
+typedef SkPath PlatformPath;
#else
typedef void PlatformPath;
#endif
@@ -95,8 +101,8 @@ namespace WebCore {
void moveTo(const FloatPoint&);
void addLineTo(const FloatPoint&);
- void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point);
- void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint&);
+ void 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();
@@ -106,9 +112,6 @@ namespace WebCore {
void translate(const FloatSize&);
- void setWindingRule(WindRule rule) { m_rule = rule; }
- WindRule windingRule() const { return m_rule; }
-
String debugString() const;
PlatformPath* platformPath() const { return m_path; }
@@ -125,7 +128,6 @@ namespace WebCore {
private:
PlatformPath* m_path;
- WindRule m_rule;
};
}
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/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp
index 24812f7..372fcc8 100644
--- a/WebCore/platform/graphics/SimpleFontData.cpp
+++ b/WebCore/platform/graphics/SimpleFontData.cpp
@@ -30,6 +30,7 @@
#include "config.h"
#include "SimpleFontData.h"
+#include "FontCache.h"
#if ENABLE(SVG_FONTS)
#include "SVGFontData.h"
#include "SVGFontFaceElement.h"
@@ -115,13 +116,16 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool
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();
-
- // We only get deleted when the cache gets cleared. Since the smallCapsRenderer is also in that cache,
- // it will be deleted then, so we don't need to do anything here.
}
float SimpleFontData::widthForGlyph(Glyph glyph) const
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
index b2eec1f..5f26cbf 100644
--- a/WebCore/platform/graphics/SimpleFontData.h
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -1,7 +1,7 @@
/*
* This file is part of the internal font implementation.
*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * 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
@@ -29,7 +29,7 @@
#include "GlyphWidthMap.h"
#include <wtf/OwnPtr.h>
-#if PLATFORM(MAC)
+#if USE(ATSUI)
typedef struct OpaqueATSUStyle* ATSUStyle;
#endif
@@ -37,6 +37,10 @@ typedef struct OpaqueATSUStyle* ATSUStyle;
#include <usp10.h>
#endif
+#if PLATFORM(CAIRO)
+#include <cairo.h>
+#endif
+
namespace WebCore {
class FontDescription;
@@ -88,6 +92,14 @@ public:
#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
{
@@ -106,7 +118,7 @@ public:
static bool shouldApplyMacAscentHack();
#endif
-#if PLATFORM(GTK)
+#if PLATFORM(CAIRO)
void setFont(cairo_t*) const;
#endif
@@ -120,6 +132,12 @@ private:
void commonInit();
+#if PLATFORM(WIN)
+ void initGDIFont();
+ void platformCommonDestroy();
+ float widthForGDIGlyph(Glyph glyph) const;
+#endif
+
public:
int m_ascent;
int m_descent;
@@ -149,12 +167,17 @@ public:
mutable SimpleFontData* m_smallCapsFontData;
-#if PLATFORM(CG)
+#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;
@@ -162,6 +185,11 @@ public:
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;
diff --git a/WebCore/platform/graphics/StringTruncator.cpp b/WebCore/platform/graphics/StringTruncator.cpp
index 0490a9f..b6c86ce 100644
--- a/WebCore/platform/graphics/StringTruncator.cpp
+++ b/WebCore/platform/graphics/StringTruncator.cpp
@@ -31,7 +31,6 @@
#include "CharacterNames.h"
#include "Font.h"
-#include "FontPlatformData.h"
#include "TextBreakIterator.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.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..a66b234
--- /dev/null
+++ b/WebCore/platform/graphics/WidthIterator.cpp
@@ -0,0 +1,258 @@
+/*
+ * 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);
+ }
+}
+
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+#define SIGNAL_ADJUSTED_WIDTHS() adjustedWidths = true
+bool WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
+#else
+#define SIGNAL_ADJUSTED_WIDTHS()
+void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
+#endif
+{
+ 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;
+
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ bool adjustedWidths = false;
+#endif
+ 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);
+ SIGNAL_ADJUSTED_WIDTHS();
+ } else {
+ width = fontData->widthForGlyph(glyph);
+#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
+ // 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;
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
+#endif
+ }
+
+ if (hasExtraSpacing) {
+ // Account for letter-spacing.
+ if (width && m_font->letterSpacing()) {
+ width += m_font->letterSpacing();
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
+
+ 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;
+ }
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
+
+ // 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();
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
+ }
+ }
+
+ // 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;
+
+#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
+ // 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);
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
+
+ // 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;
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
+#endif
+
+ runWidthSoFar += width;
+
+ if (glyphBuffer)
+ glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width));
+
+ lastRoundingWidth = width - oldWidth;
+ }
+
+ m_currentCharacter = currentCharacter;
+ m_runWidthSoFar = runWidthSoFar;
+ m_finalRoundingWidth = lastRoundingWidth;
+
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ return adjustedWidths;
+#endif
+}
+
+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..a0eb26d
--- /dev/null
+++ b/WebCore/platform/graphics/WidthIterator.h
@@ -0,0 +1,60 @@
+/*
+ * 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&);
+
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ bool advance(int to, GlyphBuffer* = 0);
+#else
+ void advance(int to, GlyphBuffer* = 0);
+#endif
+ 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
index d00aa40..6c5abae 100644
--- a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
+++ b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
@@ -31,6 +31,8 @@ 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)
{
@@ -100,6 +102,48 @@ 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));
diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp
index 340d1c1..d53c3ea 100644
--- a/WebCore/platform/graphics/android/FontAndroid.cpp
+++ b/WebCore/platform/graphics/android/FontAndroid.cpp
@@ -34,6 +34,7 @@
#include "IntRect.h"
#include "SkCanvas.h"
+#include "SkLayerDrawLooper.h"
#include "SkPaint.h"
#include "SkTemplates.h"
#include "SkTypeface.h"
@@ -41,15 +42,78 @@
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 {
- SkCanvas* canvas = gc->platformContext()->mCanvas;
- SkPaint paint;
+ SkPaint paint;
- font->platformData().setupPaint(&paint);
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setColor(gc->fillColor().rgb());
+ if (!setupForText(&paint, gc, font)) {
+ return;
+ }
+
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
@@ -57,6 +121,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
SkScalar x = SkFloatToScalar(point.x());
SkScalar y = SkFloatToScalar(point.y());
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
if (glyphBuffer.hasAdjustedWidths()) {
const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
@@ -68,9 +133,9 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
y += SkFloatToScalar(adv[i].height());
}
canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
- } else {
+ } else
+#endif
canvas->drawText(glyphs, numGlyphs << 1, x, y, paint);
- }
}
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int, int) const
@@ -95,16 +160,9 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, FloatPoint c
SkCanvas* canvas = gc->platformContext()->mCanvas;
SkPaint paint;
- primaryFont()->platformData().setupPaint(&paint);
- paint.setColor(gc->fillColor().rgb());
-
-#if 0
- int n = run.to() - run.from();
-printf("------------- complex draw %d chars", n);
- for (int i = 0; i < n; i++)
- printf(" %04X", run.data(run.from())[i]);
- printf("\n");
-#endif
+ if (!setupForText(&paint, gc, primaryFont())) {
+ return;
+ }
canvas->drawText(run.characters(), run.length() << 1,
SkFloatToScalar(point.x()), SkFloatToScalar(point.y()),
diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
index 903159e..387e486 100644
--- a/WebCore/platform/graphics/android/FontCacheAndroid.cpp
+++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
@@ -30,7 +30,8 @@
#include "FontCache.h"
#include "FontPlatformData.h"
#include "Font.h"
-
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
#include "SkPaint.h"
#include "SkTypeface.h"
#include "SkUtils.h"
@@ -43,33 +44,9 @@ void FontCache::platformInit()
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
{
- return font.primaryFont(); // do I need to make a copy (i.e. does the caller delete what I return?
-
-#if 0
- // IMLangFontLink::MapFont Method does what we want.
- IMLangFontLink2* langFontLink = getFontLinkInterface();
- if (!langFontLink)
- return 0;
-
- FontData* fontData = 0;
- HDC hdc = GetDC(0);
- DWORD fontCodePages;
- langFontLink->GetFontCodePages(hdc, font.primaryFont()->m_font.hfont(), &fontCodePages);
-
- DWORD actualCodePages;
- long cchActual;
- langFontLink->GetStrCodePages(characters, length, fontCodePages, &actualCodePages, &cchActual);
- if (cchActual) {
- HFONT result;
- if (langFontLink->MapFont(hdc, actualCodePages, characters[0], &result) == S_OK) {
- fontData = new FontData(FontPlatformData(result, font.fontDescription().computedPixelSize()));
- fontData->setIsMLangFont();
- }
- }
-
- ReleaseDC(0, hdc);
- return fontData;
-#endif
+ // 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)
@@ -96,12 +73,6 @@ static char* AtomicStringToUTF8String(const AtomicString& utf16)
return utf8;
}
-bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
-{
- ASSERT(0); // FIXME HACK unimplemented
- return false;
-}
-
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
{
char* storage = 0;
@@ -136,7 +107,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
}
int style = SkTypeface::kNormal;
- if (fontDescription.weight() >= cBoldWeight)
+ if (fontDescription.weight() >= FontWeightBold)
style |= SkTypeface::kBold;
if (fontDescription.italic())
style |= SkTypeface::kItalic;
@@ -152,5 +123,11 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
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
index eea5e36..8519861 100644
--- a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
@@ -36,7 +36,8 @@ FontCustomPlatformData::~FontCustomPlatformData()
// the unref is enough to release the font data...
}
-FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic)
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic,
+ FontRenderingMode mode)
{
// turn bold/italic into fakeBold/fakeItalic
if (m_typeface != NULL) {
diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.h b/WebCore/platform/graphics/android/FontCustomPlatformData.h
index f072b6f..d31f623 100644
--- a/WebCore/platform/graphics/android/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.h
@@ -18,6 +18,7 @@
#define FontCustomPlatformData_h_
#include <wtf/Noncopyable.h>
+#include "FontRenderingMode.h"
class SkTypeface;
@@ -33,7 +34,7 @@ namespace WebCore {
SkTypeface* typeface() const { return m_typeface; }
- FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode );
private:
SkTypeface* m_typeface;
diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h
index d6933d9..d3f5923 100644
--- a/WebCore/platform/graphics/android/FontPlatformData.h
+++ b/WebCore/platform/graphics/android/FontPlatformData.h
@@ -24,16 +24,16 @@
#ifndef FontPlatformData_H
#define FontPlatformData_H
+#include "StringImpl.h"
+
class SkPaint;
class SkTypeface;
namespace WebCore {
-class FontPlatformData
-{
+class FontPlatformData {
public:
- static FontPlatformData Deleted()
- {
+ static FontPlatformData Deleted() {
return FontPlatformData(NULL, -1, false, false);
}
@@ -43,6 +43,12 @@ public:
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;
@@ -54,51 +60,12 @@ private:
float mTextSize;
bool mFakeBold;
bool mFakeItalic;
-};
-
-#if 0 // windows port
-class FontPlatformData
-{
-public:
- class Deleted {};
-
- // Used for deleted values in the font cache's hash tables.
- FontPlatformData(Deleted)
- : m_font((HFONT)-1), m_fontFace(0), m_scaledFont(0), m_size(0)
- {}
-
- FontPlatformData()
- : m_font(0), m_fontFace(0), m_scaledFont(0), m_size(0)
- {}
-
- FontPlatformData(HFONT, int size);
- ~FontPlatformData();
-
- HFONT hfont() const { return m_font; }
- cairo_font_face_t* fontFace() const { return m_fontFace; }
- cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
-
- int size() const { return m_size; }
-
- unsigned hash() const
- {
- return StringImpl::computeHash((UChar*)(&m_font), sizeof(HFONT) / sizeof(UChar));
- }
- bool operator==(const FontPlatformData& other) const
- {
- return m_font == other.m_font && m_fontFace == other.m_fontFace &&
- m_scaledFont == other.m_scaledFont && m_size == other.m_size;
+ static SkTypeface* hashTableDeletedFontValue() {
+ return reinterpret_cast<SkTypeface*>(-1);
}
-
-private:
- HFONT m_font;
- cairo_font_face_t* m_fontFace;
- cairo_scaled_font_t* m_scaledFont;
- int m_size;
};
-#endif
-
-}
+
+} /* namespace */
#endif
diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
index 4b4186a..247d8bc 100644
--- a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
+++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
@@ -66,7 +66,10 @@ FontPlatformData::FontPlatformData()
FontPlatformData::FontPlatformData(const FontPlatformData& src)
{
- src.mTypeface->safeRef();
+ if (hashTableDeletedFontValue() != src.mTypeface) {
+ src.mTypeface->safeRef();
+ }
+
mTypeface = src.mTypeface;
mTextSize = src.mTextSize;
@@ -80,8 +83,10 @@ FontPlatformData::FontPlatformData(const FontPlatformData& src)
FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic)
: mTypeface(tf), mTextSize(textSize), mFakeBold(fakeBold), mFakeItalic(fakeItalic)
{
- mTypeface->safeRef();
-
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeRef();
+ }
+
inc_count();
trace(3);
}
@@ -89,7 +94,9 @@ FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold
FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
: mTypeface(src.mTypeface), mTextSize(textSize), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic)
{
- mTypeface->safeRef();
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeRef();
+ }
inc_count();
trace(4);
@@ -102,13 +109,21 @@ FontPlatformData::~FontPlatformData()
SkDebugf("----------- ~FontPlatformData\n");
#endif
- mTypeface->safeUnref();
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeUnref();
+ }
}
FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
{
- SkRefCnt_SafeAssign(mTypeface, src.mTypeface);
+ if (hashTableDeletedFontValue() != src.mTypeface) {
+ src.mTypeface->safeRef();
+ }
+ if (hashTableDeletedFontValue() != mTypeface) {
+ mTypeface->safeUnref();
+ }
+ mTypeface = src.mTypeface;
mTextSize = src.mTextSize;
mFakeBold = src.mFakeBold;
mFakeItalic = src.mFakeItalic;
@@ -133,7 +148,7 @@ void FontPlatformData::setupPaint(SkPaint* paint) const
bool FontPlatformData::operator==(const FontPlatformData& a) const
{
- return SkTypeface::Equal(mTypeface, a.mTypeface) &&
+ return mTypeface == a.mTypeface &&
mTextSize == a.mTextSize &&
mFakeBold == a.mFakeBold &&
mFakeItalic == a.mFakeItalic;
@@ -141,9 +156,18 @@ bool FontPlatformData::operator==(const FontPlatformData& a) const
unsigned FontPlatformData::hash() const
{
- unsigned h = SkTypeface::UniqueID(mTypeface);
+ 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 ^= *(uint32_t*)&mTextSize;
+ h ^= sizeAsInt;
return h;
}
diff --git a/WebCore/platform/graphics/android/GradientAndroid.cpp b/WebCore/platform/graphics/android/GradientAndroid.cpp
new file mode 100644
index 0000000..c5882ef
--- /dev/null
+++ b/WebCore/platform/graphics/android/GradientAndroid.cpp
@@ -0,0 +1,107 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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;
+}
+
+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
index 23ac51d..901e56e 100644
--- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -16,18 +16,21 @@
*/
#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 "WebCoreViewBridge.h"
#include "PlatformGraphicsContext.h"
#include "AffineTransform.h"
@@ -47,6 +50,10 @@ 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?
@@ -55,46 +62,77 @@ static int RoundToInt(float x)
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;
- SkDrawLooper* mLooper;
+ 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()
- {
+ State() {
+ mPath = NULL; // lazily allocated
mMiterLimit = 4;
mAlpha = 1;
- mLooper = NULL;
+ 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)
- {
- other.mLooper->safeRef();
+ State(const State& other) {
memcpy(this, &other, sizeof(State));
+ mPath = deepCopyPtr<SkPath>(other.mPath);
}
- ~State()
- {
- mLooper->safeUnref();
+ ~State() {
+ delete mPath;
}
- SkDrawLooper* setDrawLooper(SkDrawLooper* dl)
- {
- SkRefCnt_SafeAssign(mLooper, dl);
- return dl;
+ 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
@@ -115,16 +153,13 @@ public:
GraphicsContextPlatformPrivate(GraphicsContext* cg, PlatformGraphicsContext* pgc)
: mCG(cg)
- , mPgc(pgc), mStateStack(sizeof(State))
-
- {
+ , mPgc(pgc), mStateStack(sizeof(State)) {
State* state = (State*)mStateStack.push_back();
new (state) State();
mState = state;
}
- ~GraphicsContextPlatformPrivate()
- {
+ ~GraphicsContextPlatformPrivate() {
if (mPgc && mPgc->deleteUs())
delete mPgc;
@@ -134,41 +169,70 @@ public:
this->restore();
}
- void save()
- {
+ void save() {
State* newState = (State*)mStateStack.push_back();
new (newState) State(*mState);
mState = newState;
}
- void restore()
- {
+ void restore() {
mState->~State();
mStateStack.pop_back();
mState = (State*)mStateStack.back();
}
- void setup_paint_common(SkPaint* paint) const
- {
-#ifdef SK_DEBUGx
- {
- SkPaint defaultPaint;
-
- SkASSERT(*paint == defaultPaint);
- }
-#endif
+ void setFillColor(const Color& c) {
+ mState->mFillColor = c.rgb();
+ }
- paint->setAntiAlias(true);
+ 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);
- paint->setLooper(mState->mLooper);
+ 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
- {
+ void setup_paint_fill(SkPaint* paint) const {
this->setup_paint_common(paint);
-
- paint->setColor(mState->applyAlpha(mCG->fillColor().rgb()));
+ paint->setColor(mState->mFillColor);
}
/* sets up the paint for stroking. Returns true if the style is really
@@ -176,15 +240,17 @@ public:
*/
bool setup_paint_stroke(SkPaint* paint, SkRect* rect) {
this->setup_paint_common(paint);
-
- float width = mCG->strokeThickness();
+ paint->setColor(mState->mStrokeColor);
+
+ float width = mState->mStrokeThickness;
- //this allows dashing and dotting to work properly for hairline strokes
+ // 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->setColor(mState->applyAlpha(mCG->strokeColor().rgb()));
paint->setStyle(SkPaint::kStroke_Style);
paint->setStrokeWidth(SkFloatToScalar(width));
paint->setStrokeCap(mState->mLineCap);
@@ -241,32 +307,6 @@ GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
return ctx;
}
-void GraphicsContext::drawOffscreenContext(GraphicsContext* ctx, const FloatRect* srcRect, const FloatRect& dstRect)
-{
- const SkBitmap& bm = GC2Canvas(ctx)->getDevice()->accessBitmap(false);
- SkIRect src;
- SkRect dst;
- SkPaint paint;
-
- paint.setFilterBitmap(true);
-
- GC2Canvas(this)->drawBitmapRect(bm,
- srcRect ? android_setrect(&src, *srcRect) : NULL,
- *android_setrect(&dst, dstRect),
- &paint);
-}
-
-FloatRect GraphicsContext::getClipLocalBounds() const
-{
- SkRect r;
-
- if (!GC2Canvas(this)->getClipBounds(&r))
- r.setEmpty();
-
- return FloatRect(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop),
- SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
-}
-
////////////////////////////////////////////////////////////////////////////////////////////////
GraphicsContext::GraphicsContext(PlatformGraphicsContext *gc)
@@ -298,6 +338,14 @@ void GraphicsContext::restorePlatformState()
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)
{
@@ -521,124 +569,31 @@ void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* poin
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);
}
}
-#ifdef ANDROID_CANVAS_IMPL
-
-static void check_set_shader(SkPaint* paint, SkShader* s0, SkShader* s1)
-{
- if (s0) {
- paint->setShader(s0);
- }
- else if (s1) {
- paint->setShader(s1);
- }
-}
-
-void GraphicsContext::fillPath(const Path& webCorePath, PlatformGradient* grad, PlatformPattern* pat)
-{
- if (paintingDisabled())
- return;
-
- SkPaint paint;
-
- m_data->setup_paint_fill(&paint);
- check_set_shader(&paint, grad, pat);
-
- const SkPath& path = *webCorePath.platformPath();
-
-#if 0
- SkDebugf("---- fillPath\n");
- SkPath::Iter iter(path, false);
- SkPoint pts[4];
- for (;;) {
- SkString str;
- const SkPoint* p = &pts[1];
- int n = 0;
- const char* name = "";
- switch (iter.next(pts)) {
- case SkPath::kMove_Verb:
- name = " M";
- p = &pts[0];
- n = 1;
- break;
- case SkPath::kLine_Verb:
- name = " L";
- n = 1;
- break;
- case SkPath::kQuad_Verb:
- name = " Q";
- n = 2;
- break;
- case SkPath::kCubic_Verb:
- name = " C";
- n = 3;
- break;
- case SkPath::kClose_Verb:
- name = " X";
- n = 0;
- break;
- case SkPath::kDone_Verb:
- goto DONE;
- }
- str.append(name);
- for (int i = 0; i < n; i++) {
- str.append(" ");
- str.appendScalar(p[i].fX);
- str.append(" ");
- str.appendScalar(p[i].fY);
- }
- SkDebugf("\"%s\"\n", str.c_str());
- }
-DONE:
-#endif
-
- GC2Canvas(this)->drawPath(path, paint);
-}
-
-void GraphicsContext::strokePath(const Path& webCorePath, PlatformGradient* grad, PlatformPattern* pat)
-{
- if (paintingDisabled())
- return;
-
- SkPaint paint;
-
- m_data->setup_paint_stroke(&paint, NULL);
- check_set_shader(&paint, grad, pat);
-
- GC2Canvas(this)->drawPath(*webCorePath.platformPath(), paint);
-}
-
-void GraphicsContext::fillRect(const FloatRect& rect, PlatformGradient* grad, PlatformPattern* pat)
-{
- if (paintingDisabled())
- return;
-
- SkRect r;
- SkPaint paint;
-
- m_data->setup_paint_fill(&paint);
- check_set_shader(&paint, grad, pat);
-
- GC2Canvas(this)->drawRect(*android_setrect(&r, rect), 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];
@@ -653,137 +608,19 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
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::strokeRect(const FloatRect& rect, float lineWidth, PlatformGradient* grad, PlatformPattern* pat)
+void GraphicsContext::fillRect(const FloatRect& rect)
{
- if (paintingDisabled())
- return;
-
- SkRect r;
SkPaint paint;
-
- m_data->setup_paint_stroke(&paint, NULL);
- paint.setStrokeWidth(SkFloatToScalar(lineWidth));
- check_set_shader(&paint, grad, pat);
-
- GC2Canvas(this)->drawRect(*android_setrect(&r, rect), paint);
-}
-
-static U8CPU F2B(float x)
-{
- return (int)(x * 255);
-}
-
-static SkColor make_color(float a, float r, float g, float b)
-{
- return SkColorSetARGB(F2B(a), F2B(r), F2B(g), F2B(b));
-}
-
-PlatformGradient* GraphicsContext::newPlatformLinearGradient(const FloatPoint& p0, const FloatPoint& p1,
- const float stopData[5], int count)
-{
- SkPoint pts[2];
-
- android_setpt(&pts[0], p0);
- android_setpt(&pts[1], p1);
-
- SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
- SkColor* colors = (SkColor*)storage.get();
- SkScalar* pos = (SkScalar*)(colors + count);
-
- for (int i = 0; i < count; i++)
- {
- pos[i] = SkFloatToScalar(stopData[0]);
- colors[i] = make_color(stopData[4], stopData[1], stopData[2], stopData[3]);
- stopData += 5;
- }
-
- return SkGradientShader::CreateLinear(pts, colors, pos, count,
- SkShader::kClamp_TileMode);
-}
-
-PlatformGradient* GraphicsContext::newPlatformRadialGradient(const FloatPoint& p0, float r0,
- const FloatPoint& p1, float r1,
- const float stopData[5], int count)
-{
- SkPoint center;
-
- android_setpt(&center, p1);
-
- SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
- SkColor* colors = (SkColor*)storage.get();
- SkScalar* pos = (SkScalar*)(colors + count);
+ SkRect r;
- for (int i = 0; i < count; i++)
- {
- pos[i] = SkFloatToScalar(stopData[0]);
- colors[i] = make_color(stopData[4], stopData[1], stopData[2], stopData[3]);
- stopData += 5;
- }
-
- return SkGradientShader::CreateRadial(center, SkFloatToScalar(r1),
- colors, pos, count,
- SkShader::kClamp_TileMode);
-}
-
-void GraphicsContext::freePlatformGradient(PlatformGradient* shader)
-{
- shader->safeUnref();
-}
-
-PlatformPattern* GraphicsContext::newPlatformPattern(Image* image,
- Image::TileRule hRule,
- Image::TileRule vRule)
-{
-//printf("----------- Image %p, [%d %d] %d %d\n", image, image->width(), image->height(), hRule, vRule);
- if (NULL == image)
- return NULL;
-
- SkBitmapRef* bm = image->nativeImageForCurrentFrame();
- if (NULL == bm)
- return NULL;
-
- return SkShader::CreateBitmapShader(bm->bitmap(),
- android_convert_TileRule(hRule),
- android_convert_TileRule(vRule));
-}
-
-void GraphicsContext::freePlatformPattern(PlatformPattern* shader)
-{
- shader->safeUnref();
-}
-
-#endif
-
-#if 0
-static int getBlendedColorComponent(int c, int a)
-{
- // We use white.
- float alpha = (float)(a) / 255;
- int whiteBlend = 255 - a;
- c -= whiteBlend;
- return (int)(c/alpha);
-}
-#endif
-
-void GraphicsContext::fillRect(const IntRect& 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());
- GC2Canvas(this)->drawRect(r, paint);
- }
+ android_setrect(&r, rect);
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawRect(r, paint);
}
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
@@ -797,12 +634,13 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
android_setrect(&r, rect);
m_data->setup_paint_common(&paint);
- paint.setColor(color.rgb());
+ 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 IntRect& rect)
+void GraphicsContext::clip(const FloatRect& rect)
{
if (paintingDisabled())
return;
@@ -872,6 +710,10 @@ void GraphicsContext::clipOut(const Path& p)
GC2Canvas(this)->clipPath(*p.platformPath(), SkRegion::kDifference_Op);
}
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) {
+ SkDebugf("xxxxxxxxxxxxxxxxxx clipToImageBuffer not implemented\n");
+}
+
//////////////////////////////////////////////////////////////////////////////////////////////////
#if SVG_SUPPORT
@@ -904,38 +746,76 @@ void GraphicsContext::endTransparencyLayer()
GC2Canvas(this)->restore();
}
-void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
+ ///////////////////////////////////////////////////////////////////////////
+
+ 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)
- {
- SkColor c;
-
- if (color.isValid())
- c = color.rgb();
- else
- c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" Apple shadow color
-
- SkDrawLooper* dl = new SkBlurDrawLooper(SkIntToScalar(blur),
- SkIntToScalar(size.width()),
- SkIntToScalar(size.height()),
- c);
- m_data->mState->setDrawLooper(dl)->unref();
+ if (blur <= 0) {
+ this->clearPlatformShadow();
}
- else
- m_data->mState->setDrawLooper(NULL);
+
+ 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::clearShadow()
+void GraphicsContext::clearPlatformShadow()
{
if (paintingDisabled())
return;
- m_data->mState->setDrawLooper(NULL);
+ m_data->mState->setShadow(0, 0, 0, 0);
}
+///////////////////////////////////////////////////////////////////////////////
+
void GraphicsContext::drawFocusRing(const Color& color)
{
// Do nothing, since we draw the focus ring independently.
@@ -1074,41 +954,152 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
{
- // appears to be PDF specific, so we ignore it
+// 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;
-
- CFURLRef urlRef = link.createCFURL();
- if (urlRef) {
- CGContextRef context = platformContext();
-
- // Get the bounding box to handle clipping.
- CGRect box = CGContextGetClipBoundingBox(context);
+ m_data->mState->mUseAA = useAA;
+}
+
+AffineTransform GraphicsContext::getCTM() const {
+ return AffineTransform(GC2Canvas(this)->getTotalMatrix());
+}
- IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
- IntRect rect = destRect;
- rect.intersect(intBox);
+///////////////////////////////////////////////////////////////////////////////
+
+void GraphicsContext::beginPath() {
+ m_data->beginPath();
+}
+
+void GraphicsContext::addPath(const Path& p) {
+ m_data->addPath(*p.platformPath());
+}
- CGPDFContextSetURLForRect(context, urlRef,
- CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+void GraphicsContext::drawPath() {
+ this->fillPath();
+ this->strokePath();
+}
- CFRelease(urlRef);
+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;
+}
+
+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;
}
-#endif
}
-// we don't need to push these down, since we query the current state and build our paint at draw-time
+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;
+ }
-void GraphicsContext::setPlatformStrokeColor(const Color&) {}
-void GraphicsContext::setPlatformStrokeThickness(float) {}
-void GraphicsContext::setPlatformFillColor(const Color&) {}
+ 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());
-// functions new to Feb-19 tip of tree merge:
-AffineTransform GraphicsContext::getCTM() const {
- notImplemented();
- return AffineTransform();
+ 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
index 00145af..a54f440 100644
--- a/WebCore/platform/graphics/android/ImageAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -37,17 +37,27 @@
#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* gGlobalAssetMgr;
+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) {
@@ -58,63 +68,83 @@ void FrameData::clear()
}
}
-SkBitmapRef* BitmapImage::getBitmap()
+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)
{
- return m_bitmapRef;
+ 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_bitmapRef = NULL;
m_source.clearURL();
}
void BitmapImage::invalidatePlatformData()
{
- if (m_bitmapRef) {
- m_bitmapRef->unref();
- m_bitmapRef = NULL;
- }
}
void BitmapImage::checkForSolidColor()
{
m_isSolidColor = false;
- if (this->frameCount() > 1) {
- if (!m_bitmapRef) {
- return;
+ if (frameCount() == 1) {
+ SkBitmapRef* ref = frameAtIndex(0);
+ if (!ref) {
+ return; // keep solid == false
}
- const SkBitmap& bm = m_bitmapRef->bitmap();
+ const SkBitmap& bm = ref->bitmap();
+ if (bm.width() != 1 || bm.height() != 1) {
+ return; // keep solid == false
+ }
- if (bm.width() == 1 && bm.height() == 1) {
- SkAutoLockPixels alp(bm);
- if (bm.getPixels() == NULL) {
- return;
- }
+ 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: // don't check other configs
- return;
+ 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;
}
- m_isSolidColor = true;
- m_solidColor = android_SkPMColorToWebCoreColor(color);
+ default:
+ return; // keep solid == false
}
+ m_isSolidColor = true;
+ m_solidColor = android_SkPMColorToWebCoreColor(color);
}
}
@@ -125,36 +155,46 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
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()) {
+ bitmap.height() != image->origHeight()) {
SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
bitmap.width(), bitmap.height(),
image->origWidth(), image->origHeight());
@@ -184,16 +224,16 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
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);
@@ -201,21 +241,21 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
// 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()) {
+ bitmap.height() != image->origHeight()) {
SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n",
bitmap.width(), bitmap.height(),
image->origWidth(), image->origHeight(),
@@ -225,30 +265,32 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
}
// missingImage, textAreaResizeCorner
-Image* Image::loadPlatformResource(const char *name)
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
{
- if (NULL == gGlobalAssetMgr) {
- gGlobalAssetMgr = new android::AssetManager();
- gGlobalAssetMgr->addDefaultAssets();
- }
-
+ android::AssetManager* am = globalAssetManager();
+
SkString path("webkit/");
path.append(name);
path.append(".png");
-
- android::Asset* a = gGlobalAssetMgr->open(path.c_str(),
- android::Asset::ACCESS_BUFFER);
+
+ 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;
}
-
- Image* image = new BitmapImage;
- RefPtr<SharedBuffer> buffer =
- new SharedBuffer((const char*)a->getBuffer(false), a->getLength());
- image->setData(buffer, true);
- delete a;
- return image;
+
+ 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
index 65fb7cd..b8c0138 100644
--- a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
@@ -16,29 +16,34 @@
*/
#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 {
-auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale)
+ImageBufferData::ImageBufferData(const IntSize&)
{
- // Ignore grayScale for now, since SkBitmap doesn't support it... yet
-
- GraphicsContext* ctx = GraphicsContext::createOffscreenContext(size.width(), size.height());
-
- auto_ptr<GraphicsContext> context(ctx);
-
- return auto_ptr<ImageBuffer>(new ImageBuffer(size, context));
}
-
-ImageBuffer::ImageBuffer(const IntSize& size, auto_ptr<GraphicsContext> context)
- : m_data(NULL), m_size(size), m_context(context.release())
+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()
@@ -50,4 +55,154 @@ 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..8050146
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageBufferData.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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
index 144968d..3dc7557 100644
--- a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
+++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
@@ -19,6 +19,7 @@
#include "ImageDecoder.h"
#include "ImageSource.h"
#include "IntSize.h"
+#include "NotImplemented.h"
#include "SharedBuffer.h"
#include "PlatformString.h"
@@ -42,6 +43,10 @@ SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src);
// 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;
}
@@ -72,7 +77,7 @@ static bool shouldReencodeAsRLE(const SkBitmap& bm) {
&&
bm.width() >= 64 // narrower than this won't compress well in RLE
&&
- bm.getSize() > (250*1024);
+ bm.getSize() > MIN_RLE_ALLOC_SIZE;
}
///////////////////////////////////////////////////////////////////////////////
@@ -227,6 +232,8 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
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;
@@ -240,10 +247,10 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
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());
+// 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());
+// SkDebugf("---- use globalpool for image [%d %d]\n", bm->width(), bm->height());
ref = new SkImageRef_GlobalPool(strm, bm->config(), decoder->fSampleSize);
}
@@ -256,6 +263,8 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
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());
}
}
@@ -333,4 +342,10 @@ 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
index 68f4c0d..f6d3d43 100644
--- a/WebCore/platform/graphics/android/PathAndroid.cpp
+++ b/WebCore/platform/graphics/android/PathAndroid.cpp
@@ -122,7 +122,16 @@ void Path::closeSubpath()
m_path->close();
}
-static const float gPI = 3.1415926f;
+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) {
@@ -134,23 +143,43 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea,
oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
float sweep = ea - sa;
- // check for a circle
- if (sweep >= 2*gPI || sweep <= -2*gPI) {
- m_path->addOval(oval);
- } else {
- SkScalar startDegrees = SkFloatToScalar(sa * 180 / gPI);
- SkScalar sweepDegrees = SkFloatToScalar(sweep * 180 / gPI);
-
- if (clockwise && sweepDegrees > 0) {
- sweepDegrees -= SkIntToScalar(360);
- } else if (!clockwise && sweepDegrees < 0) {
- sweepDegrees = SkIntToScalar(360) - sweepDegrees;
- }
+ 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);
+ }
-// SkDebugf("addArc sa=%g ea=%g cw=%d start=%g sweep=%g\n", sa, ea, clockwise,
-// SkScalarToFloat(startDegrees), SkScalarToFloat(sweepDegrees));
+ sa = fast_mod(sa, g2PI);
+ SkScalar startDegrees = SkFloatToScalar(sa * g180OverPI);
+ SkScalar sweepDegrees = SkFloatToScalar(sweep * g180OverPI);
- m_path->arcTo(oval, startDegrees, sweepDegrees, false);
+// 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);
}
}
diff --git a/WebCore/platform/graphics/android/PatternAndroid.cpp b/WebCore/platform/graphics/android/PatternAndroid.cpp
new file mode 100644
index 0000000..fa52b79
--- /dev/null
+++ b/WebCore/platform/graphics/android/PatternAndroid.cpp
@@ -0,0 +1,46 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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/PlatformGraphics.h b/WebCore/platform/graphics/android/PlatformGraphics.h
deleted file mode 100644
index 6efdb43..0000000
--- a/WebCore/platform/graphics/android/PlatformGraphics.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef PlatformGraphics_d
-#define PlatformGraphics_d
-
-typedef class SkShader PlatformGradient;
-typedef class SkShader PlatformPattern;
-
-#endif
-
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
index af443b8..86d5c0a 100644
--- a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
@@ -21,11 +21,10 @@
#include "SkCanvas.h"
namespace WebCore {
-
-PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas) : mCanvas(canvas), m_deleteCanvas(false)
+
+PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas, WTF::Vector<Container>* buttons)
+ : mCanvas(canvas), m_deleteCanvas(false), m_buttons(buttons)
{
- // This is useful only if this Canvas is part of an SkPicture object.
- m_buttons = new SkTDArray<Container*>;
}
PlatformGraphicsContext::PlatformGraphicsContext() : m_deleteCanvas(true)
@@ -42,32 +41,29 @@ PlatformGraphicsContext::~PlatformGraphicsContext()
// printf("-------------------- deleting offscreen canvas\n");
delete mCanvas;
}
- if (m_buttons != NULL) {
- m_buttons->deleteAll();
- delete m_buttons;
- }
-}
-
-SkTDArray<Container*>* PlatformGraphicsContext::getAndClearButtonInfo()
-{
- // The caller is now responsible for deleting the array
- SkTDArray<Container*>* buttons = m_buttons;
- m_buttons = NULL;
- return buttons;
}
void PlatformGraphicsContext::storeButtonInfo(Node* node, const IntRect& r)
{
if (m_buttons == NULL)
return;
- // Initialize all of the nodes to have disabled state, so that we guarantee
- // that we paint all of them the first time.
- RenderSkinAndroid::State state = RenderSkinAndroid::kDisabled;
- Container* container = new Container(node, r, state);
+ // 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()));
+ mCanvas->drawPicture(*(container.picture()));
// Keep track of the information about the button.
- *m_buttons->append() = container;
+ m_buttons->append(container);
}
} // WebCore
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
index a2d7ebe..d09dee2 100644
--- a/WebCore/platform/graphics/android/PlatformGraphicsContext.h
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
@@ -30,9 +30,8 @@ class WebCore::Node;
class Container {
public:
- Container(WebCore::Node* node, const WebCore::IntRect& r,
- WebCore::RenderSkinAndroid::State is)
- : m_node(node), m_rect(r), m_state(is)
+ Container(WebCore::Node* node, const WebCore::IntRect& r)
+ : m_node(node), m_rect(r), m_state(WebCore::RenderSkinAndroid::kDisabled)
{
m_picture = new SkPicture;
}
@@ -41,31 +40,81 @@ public:
{
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;
+ }
- bool matches(WebCore::Node* match) { return m_node == match; }
+ 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::Node* focus)
+ void updateFocusState(WebCore::RenderSkinAndroid::State state)
{
- WebCore::RenderSkinAndroid::State state = m_node == focus ?
- WebCore::RenderSkinAndroid::kFocused : WebCore::RenderSkinAndroid::kNormal;
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:
- // Mark copy and assignment private so noone can use them.
- Container& operator=(const Container& src) { return *this; }
- Container(const Container& src) { }
// Only used for comparison, since after it is stored it will be transferred
// to the UI thread.
WebCore::Node* m_node;
@@ -82,11 +131,18 @@ private:
namespace WebCore {
+ class GraphicsContext;
+
class PlatformGraphicsContext {
public:
PlatformGraphicsContext();
- PlatformGraphicsContext(SkCanvas* canvas);
+ // 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;
@@ -95,12 +151,9 @@ public:
// nod/rect, and record a new subpicture for this node/button in the current
// mCanvas
void storeButtonInfo(Node* node, const IntRect& r);
- // Detaches button array (if any), returning it to the caller and setting our
- // internal ptr to NULL
- SkTDArray<Container*>* getAndClearButtonInfo();
private:
bool m_deleteCanvas;
- SkTDArray<Container*>* m_buttons;
+ WTF::Vector<Container>* m_buttons;
};
}
diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp
index 3964ee1..16f3cfc 100644
--- a/WebCore/platform/graphics/android/android_graphics.cpp
+++ b/WebCore/platform/graphics/android/android_graphics.cpp
@@ -155,13 +155,14 @@ WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm)
{
SkColor c = SkPMColorToColor(pm);
- return WebCore::Color(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), SkColorGetA(c));
+ // 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(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
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
@@ -170,7 +171,6 @@ const static SkColor focusOuterColors[] = {
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(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
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
@@ -178,8 +178,7 @@ const static SkColor focusInnerColors[] = {
const static SkColor focusPressedColors[] = {
SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal focus ring pressed
- SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00), // fake focus ring pressed
- SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B) // button focus ring pressed
+ SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00) // fake focus ring pressed
};
#define FOCUS_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
@@ -209,8 +208,6 @@ void FocusRing::DrawRing(SkCanvas* canvas,
paint.setColor(focusPressedColors[flavor - NORMAL_ANIMATING]);
canvas->drawPath(path, paint);
}
- if (flavor == BUTTON_ANIMATING)
- return;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(FOCUS_RING_OUTER_DIAMETER);
paint.setColor(focusOuterColors[flavor]);
diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h
index 91c56b7..3bfa5ac 100644
--- a/WebCore/platform/graphics/android/android_graphics.h
+++ b/WebCore/platform/graphics/android/android_graphics.h
@@ -35,6 +35,7 @@ namespace WebCore {
class FloatRect;
class IntPoint;
class IntRect;
+ class GraphicsContext;
}
SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src);
@@ -51,10 +52,12 @@ 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 SkIntToScalar(5)
+#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
@@ -64,11 +67,9 @@ public:
enum Flavor {
NORMAL_FLAVOR,
FAKE_FLAVOR,
- BUTTON_NO_RING,
INVALID_FLAVOR,
NORMAL_ANIMATING,
FAKE_ANIMATING,
- BUTTON_ANIMATING,
ANIMATING_COUNT = 2
};
diff --git a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp b/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp
index 1080d2d..0f2fccd 100644
--- a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp
+++ b/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp
@@ -41,17 +41,17 @@ AffineTransform::AffineTransform()
AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
{
- cairo_matrix_init(&m_transform, a, c, b, d, tx, ty);
+ cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
}
-AffineTransform::AffineTransform(const cairo_matrix_t &matrix)
+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, c, b, d, tx, ty);
+ cairo_matrix_init(&m_transform, a, b, c, d, tx, ty);
}
void AffineTransform::map(double x, double y, double* x2, double* y2) const
@@ -147,22 +147,22 @@ void AffineTransform::setA(double a)
double AffineTransform::b() const
{
- return m_transform.xy;
+ return m_transform.yx;
}
void AffineTransform::setB(double b)
{
- m_transform.xy = b;
+ m_transform.yx = b;
}
double AffineTransform::c() const
{
- return m_transform.yx;
+ return m_transform.xy;
}
void AffineTransform::setC(double c)
{
- m_transform.yx = c;
+ m_transform.xy = c;
}
double AffineTransform::d() const
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
index 08e8616..c403f44 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -1,6 +1,8 @@
/*
* 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
@@ -33,10 +35,13 @@
#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>
@@ -48,6 +53,7 @@
#elif PLATFORM(WIN)
#include <cairo-win32.h>
#endif
+#include "GraphicsContextPrivate.h"
#include "GraphicsContextPlatformPrivateCairo.h"
#ifndef M_PI
@@ -72,6 +78,25 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const
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)
@@ -102,11 +127,13 @@ cairo_t* GraphicsContext::platformContext() const
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.
@@ -287,32 +314,88 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
cairo_new_path(cr);
}
-// FIXME: This function needs to be adjusted to match the functionality on the Mac side.
void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
{
- if (paintingDisabled())
- return;
-
- if (strokeStyle() == NoStroke)
+ if (paintingDisabled() || strokeStyle() == NoStroke)
return;
int x = rect.x();
int y = rect.y();
float w = rect.width();
-#if 0 // FIXME: unused so far
float h = rect.height();
float scaleFactor = h / w;
float reverseScaleFactor = w / h;
-#endif
- float r = w / 2;
+
+ float hRadius = w / 2;
+ float vRadius = h / 2;
float fa = startAngle;
float falen = fa + angleSpan;
cairo_t* cr = m_data->cr;
cairo_save(cr);
- cairo_arc_negative(cr, x + r, y + r, r, -fa * M_PI/180, -falen * M_PI/180);
+
+ 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());
- cairo_set_line_width(cr, strokeThickness());
+
+ 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);
}
@@ -350,13 +433,96 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
cairo_restore(cr);
}
-void GraphicsContext::fillRect(const IntRect& rect, const Color& color)
+void GraphicsContext::fillPath()
{
if (paintingDisabled())
return;
- if (color.alpha())
- fillRectSourceOver(m_data->cr, rect, color);
+ 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)
@@ -368,7 +534,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
fillRectSourceOver(m_data->cr, rect, color);
}
-void GraphicsContext::clip(const IntRect& rect)
+void GraphicsContext::clip(const FloatRect& rect)
{
if (paintingDisabled())
return;
@@ -379,6 +545,7 @@ void GraphicsContext::clip(const IntRect& rect)
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)
@@ -386,27 +553,48 @@ void GraphicsContext::drawFocusRing(const Color& color)
if (paintingDisabled())
return;
- int radius = (focusRingWidth() - 1) / 2;
- int offset = radius + focusRingOffset();
-
const Vector<IntRect>& rects = focusRingRects();
unsigned rectCount = rects.size();
- IntRect finalFocusRect;
- for (unsigned i = 0; i < rectCount; i++) {
- IntRect focusRect = rects[i];
- focusRect.inflate(offset);
- finalFocusRect.unite(focusRect);
- }
cairo_t* cr = m_data->cr;
cairo_save(cr);
- // FIXME: These rects should be rounded
- cairo_rectangle(cr, finalFocusRect.x(), finalFocusRect.y(), finalFocusRect.width(), finalFocusRect.height());
+ 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_stroke(cr);
+ 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);
}
@@ -430,7 +618,6 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin,
if (paintingDisabled())
return;
-#if PLATFORM(GTK)
cairo_t* cr = m_data->cr;
cairo_save(cr);
@@ -441,13 +628,14 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin,
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);
-
- cairo_restore(cr);
#else
notImplemented();
#endif
+
+ cairo_restore(cr);
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
@@ -480,6 +668,7 @@ void GraphicsContext::translate(float x, float y)
cairo_t* cr = m_data->cr;
cairo_translate(cr, x, y);
+ m_data->translate(x, y);
}
IntPoint GraphicsContext::origin()
@@ -492,14 +681,14 @@ IntPoint GraphicsContext::origin()
void GraphicsContext::setPlatformFillColor(const Color& col)
{
- // FIXME: this is probably a no-op but I'm not sure
- // notImplemented(); // commented-out because it's chatty and clutters output
+ // 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)
{
- // FIXME: this is probably a no-op but I'm not sure
- //notImplemented(); // commented-out because it's chatty and clutters output
+ // 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)
@@ -532,9 +721,6 @@ void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle)
case DashedStroke:
cairo_set_dash(m_data->cr, dashPattern, 2, 0);
break;
- default:
- notImplemented();
- break;
}
}
@@ -543,9 +729,6 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
notImplemented();
}
-#if PLATFORM(GTK)
-// FIXME: This should be moved to something like GraphicsContextCairoGTK.cpp,
-// as there is a Windows implementation in platform/graphics/win/GraphicsContextCairoWin.cpp
void GraphicsContext::concatCTM(const AffineTransform& transform)
{
if (paintingDisabled())
@@ -554,8 +737,8 @@ void GraphicsContext::concatCTM(const AffineTransform& transform)
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);
}
-#endif
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
{
@@ -580,13 +763,20 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
cairo_set_fill_rule(cr, savedFillRule);
}
+void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer* imageBuffer)
+{
+ if (paintingDisabled())
+ return;
-void GraphicsContext::setShadow(IntSize const&, int, Color const&)
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&)
{
notImplemented();
}
-void GraphicsContext::clearShadow()
+void GraphicsContext::clearPlatformShadow()
{
notImplemented();
}
@@ -599,6 +789,7 @@ void GraphicsContext::beginTransparencyLayer(float opacity)
cairo_t* cr = m_data->cr;
cairo_push_group(cr);
m_data->layers.append(opacity);
+ m_data->beginTransparencyLayer();
}
void GraphicsContext::endTransparencyLayer()
@@ -611,6 +802,7 @@ void GraphicsContext::endTransparencyLayer()
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)
@@ -635,9 +827,8 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width)
cairo_t* cr = m_data->cr;
cairo_save(cr);
cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
- setColor(cr, strokeColor());
cairo_set_line_width(cr, width);
- cairo_stroke(cr);
+ strokePath();
cairo_restore(cr);
}
@@ -661,6 +852,11 @@ void GraphicsContext::setLineCap(LineCap lineCap)
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())
@@ -689,9 +885,14 @@ void GraphicsContext::setMiterLimit(float miter)
cairo_set_miter_limit(m_data->cr, miter);
}
-void GraphicsContext::setAlpha(float)
+void GraphicsContext::setAlpha(float alpha)
{
- notImplemented();
+ m_common->state.globalAlpha = alpha;
+}
+
+float GraphicsContext::getAlpha()
+{
+ return m_common->state.globalAlpha;
}
static inline cairo_operator_t toCairoOperator(CompositeOperator op)
@@ -772,6 +973,7 @@ void GraphicsContext::clip(const Path& path)
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)
@@ -779,6 +981,7 @@ 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);
@@ -789,6 +992,9 @@ void GraphicsContext::clipOut(const Path& path)
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)
@@ -797,6 +1003,7 @@ void GraphicsContext::rotate(float radians)
return;
cairo_rotate(m_data->cr, radians);
+ m_data->rotate(radians);
}
void GraphicsContext::scale(const FloatSize& size)
@@ -805,6 +1012,7 @@ void GraphicsContext::scale(const FloatSize& size)
return;
cairo_scale(m_data->cr, size.width(), size.height());
+ m_data->scale(size);
}
void GraphicsContext::clipOut(const IntRect& r)
@@ -812,6 +1020,7 @@ 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);
@@ -821,6 +1030,9 @@ void GraphicsContext::clipOut(const IntRect& r)
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)
@@ -865,17 +1077,6 @@ GdkDrawable* GraphicsContext::gdkDrawable() const
return GDK_DRAWABLE(m_data->expose->window);
}
-
-IntPoint GraphicsContext::translatePoint(const IntPoint& point) const
-{
- cairo_matrix_t tm;
- cairo_get_matrix(m_data->cr, &tm);
- double x = point.x();
- double y = point.y();
-
- cairo_matrix_transform_point(&tm, &x, &y);
- return IntPoint(x, y);
-}
#endif
void GraphicsContext::setUseAntialiasing(bool enable)
@@ -889,6 +1090,15 @@ void GraphicsContext::setUseAntialiasing(bool enable)
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
index f0ef490..9a14555 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -44,7 +44,7 @@ namespace WebCore {
class GraphicsContextPlatformPrivate {
public:
GraphicsContextPlatformPrivate()
- : cr(0)
+ : cr(0)
#if PLATFORM(GTK)
, expose(0)
#elif PLATFORM(WIN)
@@ -62,8 +62,28 @@ public:
#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;
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 776529e..5f65ed2 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -1,6 +1,7 @@
/*
* 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
@@ -27,39 +28,47 @@
#include "config.h"
#include "ImageBuffer.h"
+#include "Base64.h"
+#include "BitmapImage.h"
#include "GraphicsContext.h"
-#include <cairo.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 {
-auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool)
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_surface(0)
{
- cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- size.width(), size.height());
- if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
- return auto_ptr<ImageBuffer>();
-
- return auto_ptr<ImageBuffer>(new ImageBuffer(surface));
}
-ImageBuffer::ImageBuffer(_cairo_surface* surface)
- : m_surface(surface)
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
{
- cairo_t* cr = cairo_create(m_surface);
- m_context.set(new GraphicsContext(cr));
+ 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.
- /*
- * The context is now owned by the GraphicsContext
- */
- cairo_destroy(cr);
+ 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_surface);
+ cairo_surface_destroy(m_data.m_surface);
}
GraphicsContext* ImageBuffer::context() const
@@ -67,10 +76,149 @@ GraphicsContext* ImageBuffer::context() const
return m_context.get();
}
-cairo_surface_t* ImageBuffer::surface() const
+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)
{
- return m_surface;
+ 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
index 4faa512..0a35cf2 100644
--- a/WebCore/platform/graphics/cairo/ImageCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp
@@ -43,23 +43,56 @@ void FrameData::clear()
if (m_frame) {
cairo_surface_destroy(m_frame);
m_frame = 0;
- m_duration = 0.;
- m_hasAlpha = true;
+ // 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.
}
}
-void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op)
+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)
{
- if (!m_source.initialized())
- return;
+ initPlatformData();
- FloatRect srcRect(src);
- FloatRect dstRect(dst);
+ // 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;
@@ -97,12 +130,11 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo
cairo_set_source(cr, pattern);
cairo_pattern_destroy(pattern);
cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height());
- cairo_fill(cr);
+ cairo_clip(cr);
+ cairo_paint_with_alpha(cr, context->getAlpha());
cairo_restore(cr);
- startAnimation();
-
if (imageObserver())
imageObserver()->didDraw(this);
}
diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
index 8cc15b3..b7a4cbb 100644
--- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
@@ -26,19 +26,21 @@
#include "config.h"
#include "ImageSource.h"
-#include "SharedBuffer.h"
#if PLATFORM(CAIRO)
+#include "BMPImageDecoder.h"
#include "GIFImageDecoder.h"
+#include "ICOImageDecoder.h"
#include "JPEGImageDecoder.h"
#include "PNGImageDecoder.h"
-#include "BMPImageDecoder.h"
-#include "ICOImageDecoder.h"
-#include "XBMImageDecoder.h"
-
+#include "SharedBuffer.h"
#include <cairo.h>
+#if !PLATFORM(WIN)
+#include "XBMImageDecoder.h"
+#endif
+
namespace WebCore {
ImageDecoder* createDecoder(const Vector<char>& data)
@@ -78,17 +80,20 @@ ImageDecoder* createDecoder(const Vector<char>& data)
!memcmp(contents, "\000\000\002\000", 4))
return new ICOImageDecoder();
+#if !PLATFORM(WIN)
// XBMs require 8 bytes of info.
if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
return new XBMImageDecoder();
+#endif
// Give up. We don't know what the heck this is.
return 0;
}
ImageSource::ImageSource()
- : m_decoder(0)
-{}
+ : m_decoder(0)
+{
+}
ImageSource::~ImageSource()
{
@@ -137,6 +142,11 @@ IntSize ImageSource::size() const
return m_decoder->size();
}
+IntSize ImageSource::frameSizeAtIndex(size_t) const
+{
+ return size();
+}
+
int ImageSource::repetitionCount()
{
if (!m_decoder)
@@ -152,6 +162,9 @@ size_t ImageSource::frameCount() const
NativeImagePtr ImageSource::createFrameAtIndex(size_t index)
{
+ if (!initialized())
+ return 0;
+
if (!m_decoder)
return 0;
diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp
index e4c9f72..3f8d588 100644
--- a/WebCore/platform/graphics/cairo/PathCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -76,15 +76,15 @@ void Path::clear()
bool Path::isEmpty() const
{
- // FIXME: if/when the patch to get current pt return status is applied
- // double dx,dy;
- // return cairo_get_current_point(cr, &dx, &dy);
-
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)
@@ -180,7 +180,11 @@ FloatRect Path::boundingRect() const
{
cairo_t* cr = platformPath()->m_cr;
double x0, x1, y0, y1;
- cairo_fill_extents(cr, &x0, &y0, &x1, &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);
}
@@ -239,6 +243,7 @@ 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);
}
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/cg/AffineTransformCG.cpp b/WebCore/platform/graphics/cg/AffineTransformCG.cpp
index 8fdd1e6..4f0bca0 100644
--- a/WebCore/platform/graphics/cg/AffineTransformCG.cpp
+++ b/WebCore/platform/graphics/cg/AffineTransformCG.cpp
@@ -37,8 +37,8 @@
namespace WebCore {
AffineTransform::AffineTransform()
+ : m_transform(CGAffineTransformIdentity)
{
- m_transform = CGAffineTransformIdentity;
}
AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
@@ -51,9 +51,9 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double
narrowPrecisionToCGFloat(ty));
}
-AffineTransform::AffineTransform(CGAffineTransform t)
+AffineTransform::AffineTransform(const PlatformAffineTransform& t)
+ : m_transform(t)
{
- m_transform = t;
}
void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
@@ -190,7 +190,7 @@ AffineTransform AffineTransform::inverse() const
return AffineTransform();
}
-AffineTransform::operator CGAffineTransform() const
+AffineTransform::operator PlatformAffineTransform() const
{
return m_transform;
}
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
index c490dcb..3f0e6e7 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -1,5 +1,6 @@
/*
* 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
@@ -29,11 +30,21 @@
#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;
@@ -98,6 +109,8 @@ void GraphicsContext::restorePlatformState()
// 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;
@@ -252,14 +265,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
CGContextAddArc(context, rect.x() + r, rect.y() + r, r, 0.0f, 2.0f * piFloat, 0);
CGContextClosePath(context);
- if (fillColor().alpha()) {
- if (strokeStyle() != NoStroke)
- // stroke and fill
- CGContextDrawPath(context, kCGPathFillStroke);
- else
- CGContextFillPath(context);
- } else if (strokeStyle() != NoStroke)
- CGContextStrokePath(context);
+ drawPath();
}
@@ -372,29 +378,177 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
CGContextAddLineToPoint(context, points[i].x(), points[i].y());
CGContextClosePath(context);
- if (fillColor().alpha()) {
- if (strokeStyle() != NoStroke)
- CGContextDrawPath(context, kCGPathEOFillStroke);
- else
- CGContextEOFillPath(context);
- } else
- CGContextStrokePath(context);
+ drawPath();
CGContextRestoreGState(context);
}
-void GraphicsContext::fillRect(const IntRect& rect, const Color& color)
+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;
- if (color.alpha()) {
- CGContextRef context = platformContext();
- Color oldFillColor = fillColor();
- if (oldFillColor != color)
- setCGFillColor(context, color);
+
+ 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);
- if (oldFillColor != color)
- setCGFillColor(context, oldFillColor);
+ break;
+ case GradientColorSpace:
+ CGContextSaveGState(context);
+ CGContextClipToRect(context, rect);
+ CGContextDrawShading(context, m_common->state.fillGradient->platformGradient());
+ CGContextRestoreGState(context);
+ break;
}
}
@@ -424,14 +578,13 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef
setCGFillColor(context, color);
addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight));
- CGContextFillPath(context);
+ fillPath();
if (oldFillColor != color)
setCGFillColor(context, oldFillColor);
}
-
-void GraphicsContext::clip(const IntRect& rect)
+void GraphicsContext::clip(const FloatRect& rect)
{
if (paintingDisabled())
return;
@@ -478,6 +631,18 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
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())
@@ -501,19 +666,28 @@ void GraphicsContext::endTransparencyLayer()
m_data->m_userToDeviceTransformKnownToBeIdentity = false;
}
-void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
+void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color)
{
- // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp
- blur = min(blur, 1000);
-
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 width = size.width();
- CGFloat height = size.height();
+ 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;
-#ifdef BUILDING_ON_TIGER
// 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);
@@ -526,23 +700,22 @@ void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& colo
height += extraShadowOffset;
else if (height < 0)
height -= extraShadowOffset;
-#endif
// 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), blur); // y is flipped.
+ CGContextSetShadow(context, CGSizeMake(width, height), blurRadius);
else {
CGColorRef colorCG = cgColor(color);
CGContextSetShadowWithColor(context,
- CGSizeMake(width, -height), // y is flipped.
- blur,
+ CGSizeMake(width, height),
+ blurRadius,
colorCG);
CGColorRelease(colorCG);
}
}
-void GraphicsContext::clearShadow()
+void GraphicsContext::clearPlatformShadow()
{
if (paintingDisabled())
return;
@@ -594,6 +767,11 @@ void GraphicsContext::setLineCap(LineCap cap)
}
}
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ CGContextSetLineDash(platformContext(), dashOffset, dashes.data(), dashes.size());
+}
+
void GraphicsContext::setLineJoin(LineJoin join)
{
if (paintingDisabled())
@@ -610,7 +788,7 @@ void GraphicsContext::setLineJoin(LineJoin join)
break;
}
}
-
+
void GraphicsContext::beginPath()
{
CGContextBeginPath(platformContext());
@@ -789,20 +967,57 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
}
}
-void GraphicsContext::setUseLowQualityImageInterpolation(bool lowQualityMode)
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode)
{
if (paintingDisabled())
return;
-
- CGContextSetInterpolationQuality(platformContext(), lowQualityMode ? kCGInterpolationNone : kCGInterpolationDefault);
+
+ 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);
}
-bool GraphicsContext::useLowQualityImageInterpolation() const
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
{
if (paintingDisabled())
- return false;
-
- return CGContextGetInterpolationQuality(platformContext());
+ 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)
@@ -924,6 +1139,6 @@ void GraphicsContext::setCompositeOperation(CompositeOperator mode)
CGContextSetBlendMode(platformContext(), target);
}
#endif
-
+
}
diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
index 937481b..8827ff7 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
+++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h
@@ -45,11 +45,11 @@ public:
CGContextRelease(m_cgContext);
}
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
// These methods do nothing on Mac.
void save() {}
void restore() {}
- void clip(const IntRect&) {}
+ void clip(const FloatRect&) {}
void clip(const Path&) {}
void scale(const FloatSize&) {}
void rotate(float) {}
@@ -63,7 +63,7 @@ public:
// On Windows, we need to update the HDC for form controls to draw in the right place.
void save();
void restore();
- void clip(const IntRect&);
+ void clip(const FloatRect&);
void clip(const Path&);
void scale(const FloatSize&);
void rotate(float);
@@ -71,9 +71,7 @@ public:
void concatCTM(const AffineTransform&);
void beginTransparencyLayer() { m_transparencyCount++; }
void endTransparencyLayer() { m_transparencyCount--; }
-#endif
-#if PLATFORM(WIN)
HDC m_hdc;
unsigned m_transparencyCount;
#endif
diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
index 2d1ac01..502313b 100644
--- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -1,5 +1,6 @@
/*
* 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
@@ -20,65 +21,69 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "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 {
-auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale)
+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 auto_ptr<ImageBuffer>();
- unsigned int bytesPerRow = size.width();
+ return;
+ bytesPerRow = size.width();
if (!grayScale) {
// Protect against overflow
if (bytesPerRow > 0x3FFFFFFF)
- return auto_ptr<ImageBuffer>();
+ return;
bytesPerRow *= 4;
}
- void* imageBuffer = fastCalloc(size.height(), bytesPerRow);
- if (!imageBuffer)
- return auto_ptr<ImageBuffer>();
-
+ 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(imageBuffer, size.width(), size.height(), 8, bytesPerRow,
+ CGContextRef cgContext = CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow,
colorSpace, grayScale ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
- if (!cgContext) {
- fastFree(imageBuffer);
- return auto_ptr<ImageBuffer>();
- }
+ if (!cgContext)
+ return;
- auto_ptr<GraphicsContext> context(new GraphicsContext(cgContext));
+ m_context.set(new GraphicsContext(cgContext));
+ m_context->scale(FloatSize(1, -1));
+ m_context->translate(0, -size.height());
CGContextRelease(cgContext);
-
- return auto_ptr<ImageBuffer>(new ImageBuffer(imageBuffer, size, context));
-}
-
-
-ImageBuffer::ImageBuffer(void* imageData, const IntSize& size, auto_ptr<GraphicsContext> context)
- : m_data(imageData)
- , m_size(size)
- , m_context(context.release())
- , m_cgImage(0)
-{
+ success = true;
}
ImageBuffer::~ImageBuffer()
{
- fastFree(m_data);
- CGImageRelease(m_cgImage);
+ fastFree(m_data.m_data);
}
GraphicsContext* ImageBuffer::context() const
@@ -86,16 +91,185 @@ GraphicsContext* ImageBuffer::context() const
return m_context.get();
}
-CGImageRef ImageBuffer::cgImage() const
+Image* ImageBuffer::image() const
{
- // It's assumed that if cgImage() is called, the actual rendering to the
- // contained GraphicsContext must be done, as we create the CGImageRef here.
- if (!m_cgImage) {
+ if (!m_image) {
+ // It's assumed that if image() is called, the actual rendering to the
+ // GraphicsContext must be done.
ASSERT(context());
- m_cgImage = CGBitmapContextCreateImage(context()->platformContext());
+ 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");
- return m_cgImage;
+ 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
index 5958d86..8609c46 100644
--- a/WebCore/platform/graphics/cg/ImageCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageCG.cpp
@@ -37,7 +37,7 @@
#include "PlatformString.h"
#include <ApplicationServices/ApplicationServices.h>
-#if PLATFORM(MAC)
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
#include "WebCoreSystemInterface.h"
#endif
@@ -52,8 +52,9 @@ void FrameData::clear()
if (m_frame) {
CGImageRelease(m_frame);
m_frame = 0;
- m_duration = 0.0f;
- m_hasAlpha = true;
+ // 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.
}
}
@@ -61,6 +62,37 @@ void FrameData::clear()
// 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()
@@ -97,78 +129,73 @@ CGImageRef BitmapImage::getCGImageRef()
return frameAtIndex(0);
}
-void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp)
{
- if (!m_source.initialized())
- return;
-
- CGRect fr = ctxt->roundToDevicePixels(srcRect);
- CGRect ir = ctxt->roundToDevicePixels(dstRect);
+ 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, ir, solidColor(), compositeOp);
+ fillWithSolidColor(ctxt, destRect, solidColor(), compositeOp);
return;
}
- // Get the height (in adjusted, i.e. scaled, coords) of the portion of the image
- // that is currently decoded. This could be less that the actual height.
- CGSize selfSize = size(); // full image size, in pixels
- float curHeight = CGImageGetHeight(image); // height of loaded portion, in pixels
-
- CGSize adjustedSize = selfSize;
- if (curHeight < selfSize.height) {
- adjustedSize.height *= curHeight / selfSize.height;
-
- // Is the amount of available bands less than what we need to draw? If so,
- // we may have to clip 'fr' if it goes outside the available bounds.
- if (CGRectGetMaxY(fr) > adjustedSize.height) {
- float frHeight = adjustedSize.height - fr.origin.y; // clip fr to available bounds
- if (frHeight <= 0)
- return; // clipped out entirely
- ir.size.height *= (frHeight / fr.size.height); // scale ir proportionally to fr
- fr.size.height = frHeight;
- }
- }
+ 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, ir.origin.x, ir.origin.y);
+ CGContextTranslateCTM(context, adjustedDestRect.x(), adjustedDestRect.bottom());
CGContextScaleCTM(context, 1, -1);
- CGContextTranslateCTM(context, 0, -ir.size.height);
-
- // Translated to origin, now draw at 0,0.
- ir.origin.x = ir.origin.y = 0;
-
- // If we're drawing a sub portion of the image then create
- // a image for the sub portion and draw that.
- // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
- if (fr.size.width != adjustedSize.width || fr.size.height != adjustedSize.height) {
- // Convert ft to image pixel coords:
- float xscale = adjustedSize.width / selfSize.width;
- float yscale = adjustedSize.height / curHeight; // yes, curHeight, not selfSize.height!
- fr.origin.x /= xscale;
- fr.origin.y /= yscale;
- fr.size.width /= xscale;
- fr.size.height /= yscale;
-
- image = CGImageCreateWithImageInRect(image, fr);
- if (image) {
- CGContextDrawImage(context, ir, image);
- CFRelease(image);
- }
- } else // Draw the whole image.
- CGContextDrawImage(context, ir, image);
-
+ adjustedDestRect.setLocation(FloatPoint());
+
+ // Draw the image.
+ CGContextDrawImage(context, adjustedDestRect, image);
+
+ if (shouldUseSubimage)
+ CGImageRelease(image);
+
ctxt->restore();
-
- startAnimation();
if (imageObserver())
imageObserver()->didDraw(this);
@@ -183,6 +210,9 @@ void Image::drawPatternCallback(void* info, CGContextRef context)
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.
@@ -192,9 +222,8 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const
ctxt->save();
CGContextClipToRect(context, destRect);
ctxt->setCompositeOperation(op);
- CGContextTranslateCTM(context, destRect.x(), destRect.y());
+ CGContextTranslateCTM(context, destRect.x(), destRect.y() + destRect.height());
CGContextScaleCTM(context, 1, -1);
- CGContextTranslateCTM(context, 0, -destRect.height());
// Compute the scaled tile size.
float scaledTileHeight = tileRect.height() * narrowPrecisionToFloat(patternTransform.d());
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
index 2bfc204..73907c9 100644
--- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -25,15 +25,17 @@
#include "config.h"
#include "ImageSource.h"
-#include "SharedBuffer.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)
{
@@ -52,15 +54,13 @@ void ImageSource::clear()
}
}
-const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
-
CFDictionaryRef imageSourceOptions()
{
static CFDictionaryRef options;
if (!options) {
- const void *keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
- const void *values[2] = { kCFBooleanTrue, kCFBooleanTrue };
+ const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
+ const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue };
options = CFDictionaryCreate(NULL, keys, values, 2,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
@@ -108,10 +108,10 @@ bool ImageSource::isSizeAvailable()
return result;
}
-IntSize ImageSource::size() const
+IntSize ImageSource::frameSizeAtIndex(size_t index) const
{
IntSize result;
- CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions());
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
if (properties) {
int w = 0, h = 0;
CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
@@ -120,16 +120,23 @@ IntSize ImageSource::size() const
num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
if (num)
CFNumberGetValue(num, kCFNumberIntType, &h);
- result = IntSize(w, 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) {
@@ -154,7 +161,23 @@ size_t ImageSource::frameCount() const
CGImageRef ImageSource::createFrameAtIndex(size_t index)
{
- return CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions());
+ 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)
@@ -164,6 +187,9 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index)
float ImageSource::frameDurationAtIndex(size_t index)
{
+ if (!initialized())
+ return 0;
+
float duration = 0;
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions());
if (properties) {
diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h
index caddc05..5c9d4e1 100644
--- a/WebCore/platform/graphics/cg/PDFDocumentImage.h
+++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h
@@ -38,14 +38,25 @@ namespace WebCore {
class PDFDocumentImage : public Image {
public:
- PDFDocumentImage();
+ 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);
diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp
index c0a0caf..1382589 100644
--- a/WebCore/platform/graphics/cg/PathCG.cpp
+++ b/WebCore/platform/graphics/cg/PathCG.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
- * 2006 Rob Buis <buis@kde.org>
+ * 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
@@ -189,17 +189,17 @@ static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *ele
CGPoint* points = element->points;
switch (element->type) {
case kCGPathElementMoveToPoint:
- CFStringAppendFormat(string, 0, CFSTR("M%.2f,%.2f"), points[0].x, points[0].y);
+ 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);
+ 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"),
+ 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"),
+ 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;
@@ -215,6 +215,8 @@ static CFStringRef CFStringFromCGPath(CGPathRef path)
CFMutableStringRef string = CFStringCreateMutable(NULL, 0);
CGPathApply(path, string, CGPathToCFStringApplierFunction);
+ CFStringTrimWhitespace(string);
+
return string;
}
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/FontCacheGtk.cpp b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp
index aec5758..d2b43cc 100644
--- a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp
@@ -1,31 +1,21 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * All rights reserved.
+ * Copyright (C) 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:
+ * 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.
*
- * 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 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 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"
@@ -45,12 +35,33 @@ void FontCache::platformInit()
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
{
- return new SimpleFontData(FontPlatformData(font.fontDescription(), font.family().family()));
+#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 new FontPlatformData(font.fontDescription(), font.family().family());
+ return 0;
}
FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
@@ -61,10 +72,8 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fo
return getCachedFontPlatformData(fontDescription, timesStr);
}
-bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
{
- FontPlatformData platformData(fontDescription, family);
- return platformData.m_pattern != 0;
}
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp
index 3ff63c2..bb2e064 100644
--- a/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp
@@ -31,7 +31,7 @@ FontCustomPlatformData::~FontCustomPlatformData()
cairo_font_face_destroy(m_fontFace);
}
-FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic)
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
{
return FontPlatformData(m_fontFace, size, bold, italic);
}
diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.h b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h
index 237904d..b36cc79 100644
--- a/WebCore/platform/graphics/gtk/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h
@@ -21,6 +21,7 @@
#ifndef FontCustomPlatformData_h
#define FontCustomPlatformData_h
+#include "FontRenderingMode.h"
#include <wtf/Noncopyable.h>
typedef struct _cairo_font_face cairo_font_face_t;
@@ -37,7 +38,7 @@ struct FontCustomPlatformData : Noncopyable {
~FontCustomPlatformData();
- FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
cairo_font_face_t* m_fontFace;
};
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
index 5d50c6e..288ba91 100644
--- a/WebCore/platform/graphics/gtk/FontGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontGtk.cpp
@@ -5,6 +5,7 @@
* 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
@@ -37,8 +38,18 @@
#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 {
@@ -88,7 +99,7 @@ static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &l
}
glong items_written;
- text = g_utf16_to_utf8(aText, aLength, NULL, &items_written, NULL);
+ text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL);
length = items_written;
if (need_copy)
@@ -133,10 +144,29 @@ static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int fro
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((int)(font->size() * PANGO_SCALE));
+ attr = pango_attr_size_new_absolute(font->pixelSize() * PANGO_SCALE);
attr->end_index = G_MAXUINT;
pango_attr_list_insert_before(list, attr);
@@ -151,78 +181,111 @@ static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout
pango_layout_set_attributes(layout, list);
pango_attr_list_unref(list);
-
- 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);
}
-void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
- int from, int numGlyphs, const FloatPoint& point) const
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
- cairo_t* cr = graphicsContext->platformContext();
+ cairo_t* cr = context->platformContext();
cairo_save(cr);
+ cairo_translate(cr, point.x(), point.y());
- // Set the text color to use for drawing.
- float red, green, blue, alpha;
- Color penColor = graphicsContext->fillColor();
- penColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
-
- font->setFont(cr);
+ PangoLayout* layout = pango_cairo_create_layout(cr);
+ setPangoAttributes(this, run, layout);
- GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
- float offset = point.x();
+ // Our layouts are single line
+ PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
- for (int i = 0; i < numGlyphs; i++) {
- glyphs[i].x = offset;
- glyphs[i].y = point.y();
- offset += glyphBuffer.advanceAt(from + i);
+ 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());
}
- cairo_show_glyphs(cr, glyphs, numGlyphs);
- cairo_restore(cr);
-}
+ Color fillColor = context->fillColor();
+ float red, green, blue, alpha;
-void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
-{
- cairo_t* cr = context->platformContext();
- cairo_save(cr);
+ // Text shadow, inspired by FontMac
+ IntSize shadowSize;
+ int shadowBlur = 0;
+ Color shadowColor;
+ bool hasShadow = context->textDrawingMode() == cTextFill &&
+ context->getShadow(shadowSize, shadowBlur, shadowColor);
- PangoLayout* layout = pango_cairo_create_layout(cr);
+ // 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);
- gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), from, to);
- pango_layout_set_text(layout, utf8, -1);
- g_free(utf8);
+ shadowFillColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
- setPangoAttributes(this, run, layout);
+ cairo_translate(cr, shadowSize.width(), shadowSize.height());
- // Set the text color to use for drawing.
- float red, green, blue, alpha;
- Color penColor = context->fillColor();
- penColor.getRGBA(red, green, blue, alpha);
+ 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);
- // Our layouts are single line
- cairo_move_to(cr, point.x(), point.y());
- PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
+ 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);
}
-// FIXME: we should create the layout with our actual context, but it seems
-// we can't access it from here
+// We should create the layout with our actual context but we can't access it from here.
static PangoLayout* getDefaultPangoLayout(const TextRun& run)
{
- PangoFontMap* map = pango_cairo_font_map_get_default();
- PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
+ 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);
- g_object_unref(pangoContext);
return layout;
}
@@ -237,11 +300,11 @@ float Font::floatWidthForComplexText(const TextRun& run) const
gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
pango_layout_set_text(layout, utf8, -1);
- g_free(utf8);
- int layoutWidth;
- pango_layout_get_size(layout, &layoutWidth, 0);
- float width = (float)layoutWidth / (double)PANGO_SCALE;
+ int width;
+ pango_layout_get_pixel_size(layout, &width, 0);
+
+ g_free(utf8);
g_object_unref(layout);
return width;
@@ -258,6 +321,9 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includ
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);
@@ -266,8 +332,40 @@ int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includ
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
{
- notImplemented();
- return FloatRect();
+ 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
index 778d525..efa5dd5 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformData.h
+++ b/WebCore/platform/graphics/gtk/FontPlatformData.h
@@ -5,6 +5,7 @@
* 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
@@ -30,21 +31,42 @@
#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:
- class Deleted {};
- FontPlatformData(Deleted)
- : m_pattern(reinterpret_cast<FcPattern*>(-1))
+ 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)
{ }
@@ -58,21 +80,51 @@ public:
static bool init();
bool isFixedPitch();
- float size() const { return m_fontDescription.specifiedSize(); }
+ 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));
+ 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;
- FontDescription m_fontDescription;
+ 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
};
}
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
index ef5cb4a..17d789b 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
@@ -37,19 +37,23 @@ namespace WebCore {
FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
: m_pattern(0)
- , m_fontDescription(fontDescription)
+ , m_fallbacks(0)
+ , m_size(fontDescription.computedPixelSize())
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
, m_scaledFont(0)
{
FontPlatformData::init();
- CString familyNameString = familyName.domString().utf8();
+ 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;
- float fcsize = fontDescription.computedSize();
+ double fcsize = fontDescription.computedPixelSize();
if (fontDescription.italic())
fcslant = FC_SLANT_ITALIC;
- if (fontDescription.bold())
+ if (fontDescription.weight() >= FontWeight600)
fcweight = FC_WEIGHT_BOLD;
int type = fontDescription.genericFamily();
@@ -64,27 +68,30 @@ FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const
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::NoFamily:
- case FontDescription::StandardFamily:
- default:
- fcfamily = "sans-serif";
+ 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 (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily)))
- goto freePattern;
- if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant))
+ 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;
@@ -98,7 +105,7 @@ FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const
goto freePattern;
fontFace = cairo_ft_font_face_create_for_pattern(m_pattern);
cairo_matrix_t ctm;
- cairo_matrix_init_scale(&fontMatrix, m_fontDescription.computedSize(), m_fontDescription.computedSize());
+ cairo_matrix_init_scale(&fontMatrix, fontDescription.computedPixelSize(), fontDescription.computedPixelSize());
cairo_matrix_init_identity(&ctm);
#if GTK_CHECK_VERSION(2,10,0)
@@ -119,36 +126,39 @@ freePattern:
FontPlatformData::FontPlatformData(float size, bool bold, bool italic)
: m_pattern(0)
- , m_fontDescription()
+ , m_fallbacks(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
, m_scaledFont(0)
{
- m_fontDescription.setSpecifiedSize(size);
- m_fontDescription.setBold(bold);
- m_fontDescription.setItalic(italic);
}
FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic)
: m_pattern(0)
- , m_fontDescription()
+ , m_fallbacks(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(italic)
, m_scaledFont(0)
{
- m_fontDescription.setSpecifiedSize(size);
- m_fontDescription.setBold(bold);
- m_fontDescription.setItalic(italic);
-
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();
+ static const cairo_font_options_t* defaultOptions = cairo_font_options_create();
+ const cairo_font_options_t* options = NULL;
- // 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);
+#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_options_destroy(options);
}
bool FontPlatformData::init()
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/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
index c6e9a14..d8b38a0 100644
--- a/WebCore/platform/graphics/gtk/IconGtk.cpp
+++ b/WebCore/platform/graphics/gtk/IconGtk.cpp
@@ -43,12 +43,11 @@ namespace WebCore {
Icon::Icon()
: m_icon(0)
{
- notImplemented();
}
Icon::~Icon()
{
- if(m_icon)
+ if (m_icon)
g_object_unref(m_icon);
}
@@ -89,7 +88,7 @@ static String lookupIconName(String MIMEType)
return GTK_STOCK_FILE;
}
-PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
{
if (!g_path_skip_root(filename.utf8().data()))
return 0;
@@ -97,13 +96,24 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename);
String iconName = lookupIconName(MIMEType);
- Icon* icon = new Icon;
+ 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);
- return icon->m_icon ? icon : 0;
+ 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);
diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp
index a74bc54..b745209 100644
--- a/WebCore/platform/graphics/gtk/ImageGtk.cpp
+++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp
@@ -26,8 +26,6 @@
#include "config.h"
#include "BitmapImage.h"
-#include "Image.h"
-#include "NotImplemented.h"
// This function loads resources from WebKit
Vector<char> loadResourceIntoArray(const char*);
@@ -42,12 +40,13 @@ void BitmapImage::invalidatePlatformData()
{
}
-Image* Image::loadPlatformResource(const char *name)
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
{
Vector<char> arr = loadResourceIntoArray(name);
- BitmapImage* img = new BitmapImage;
- RefPtr<SharedBuffer> buffer = new SharedBuffer(arr.data(), arr.size());
+ RefPtr<BitmapImage> img = BitmapImage::create();
+ RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size());
img->setData(buffer, true);
- return img;
+ return img.release();
}
+
}
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index c60bc20..1f0cac6 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -35,6 +35,7 @@
#include "NotImplemented.h"
#include "ScrollView.h"
#include "Widget.h"
+#include <wtf/GOwnPtr.h>
#include <gdk/gdkx.h>
#include <gst/base/gstbasesrc.h>
@@ -42,7 +43,6 @@
#include <gst/interfaces/mixer.h>
#include <gst/interfaces/xoverlay.h>
#include <gst/video/video.h>
-#include <libgnomevfs/gnome-vfs.h>
#include <limits>
#include <math.h>
@@ -54,20 +54,17 @@ gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpoin
{
if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR)
{
- GError* err;
- gchar* debug;
+ GOwnPtr<GError> err;
+ GOwnPtr<gchar> debug;
- gst_message_parse_error(message, &err, &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 {
+ } else
LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message);
- g_error_free(err);
- g_free(debug);
- }
}
return true;
}
diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
index a754c45..1ca3e95 100644
--- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp
@@ -62,19 +62,25 @@ void SimpleFontData::platformInit()
void SimpleFontData::platformDestroy()
{
- if (!isCustomFont()) {
- if (m_font.m_pattern && ((FcPattern*)-1 != m_font.m_pattern)) {
- FcPatternDestroy(m_font.m_pattern);
- m_font.m_pattern = 0;
- }
+ delete m_smallCapsFontData;
- if (m_font.m_scaledFont) {
- cairo_scaled_font_destroy(m_font.m_scaledFont);
- m_font.m_scaledFont = 0;
- }
+ if (isCustomFont())
+ return;
+
+ if (m_font.m_pattern && ((FcPattern*)-1 != m_font.m_pattern)) {
+ FcPatternDestroy(m_font.m_pattern);
+ m_font.m_pattern = 0;
}
- delete m_smallCapsFontData;
+ 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
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
index 7e97688..04df7ac 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
@@ -40,10 +40,10 @@ GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug);
#define GST_CAT_DEFAULT webkit_video_sink_debug
static GstElementDetails webkit_video_sink_details =
- GST_ELEMENT_DETAILS("WebKit video sink",
- "Sink/Video",
- "Sends video data from a GStreamer pipeline to a Cairo surface",
- "Alp Toker <alp@atoker.com>");
+ GST_ELEMENT_DETAILS((gchar*) "WebKit video sink",
+ (gchar*) "Sink/Video",
+ (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface",
+ (gchar*) "Alp Toker <alp@atoker.com>");
enum {
PROP_0,
@@ -181,7 +181,7 @@ webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps)
priv->par_n = priv->par_d = 1;
gst_structure_get_int(structure, "red_mask", &red_mask);
- priv->rgb_ordering = (red_mask == 0xff000000);
+ priv->rgb_ordering = (red_mask == static_cast<int>(0xff000000));
return TRUE;
}
@@ -208,8 +208,6 @@ webkit_video_sink_dispose(GObject* object)
static void
webkit_video_sink_finalize(GObject* object)
{
- WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
-
G_OBJECT_CLASS(parent_class)->finalize(object);
}
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm
index 5c89715..96fdc39 100644
--- a/WebCore/platform/graphics/mac/ColorMac.mm
+++ b/WebCore/platform/graphics/mac/ColorMac.mm
@@ -39,8 +39,6 @@ namespace WebCore {
// NSColor calls don't throw, so no need to block Cocoa exceptions in this file
static RGBA32 oldAquaFocusRingColor = 0xFF7DADD9;
-static bool tintIsKnown;
-static void (*tintChangeFunction)();
static RGBA32 systemFocusRingColor;
static bool useOldAquaFocusRingColor;
@@ -126,29 +124,17 @@ CGColorRef cgColor(const Color& c)
return CGColorFromNSColor(nsColor(c));
}
-static void observeTint()
-{
- ASSERT(!tintIsKnown);
- [[NSNotificationCenter defaultCenter] addObserver:[WebCoreControlTintObserver class]
- selector:@selector(controlTintDidChange)
- name:NSControlTintDidChangeNotification
- object:NSApp];
- [WebCoreControlTintObserver controlTintDidChange];
- tintIsKnown = true;
-}
-
-void setFocusRingColorChangeFunction(void (*function)())
-{
- ASSERT(!tintChangeFunction);
- tintChangeFunction = function;
- if (!tintIsKnown)
- observeTint();
-}
-
Color focusRingColor()
{
- if (!tintIsKnown)
- observeTint();
+ 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;
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/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm
index ffb3068..e7cda66 100644
--- a/WebCore/platform/graphics/mac/FontCacheMac.mm
+++ b/WebCore/platform/graphics/mac/FontCacheMac.mm
@@ -1,5 +1,6 @@
/*
* 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
@@ -41,84 +42,37 @@ typedef int NSInteger;
namespace WebCore {
-static bool getAppDefaultValue(CFStringRef key, int *v)
+static void fontCacheATSNotificationCallback(ATSFontNotificationInfoRef, void*)
{
- CFPropertyListRef value;
-
- value = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication,
- kCFPreferencesAnyUser,
- kCFPreferencesAnyHost);
- if (value == 0) {
- value = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication,
- kCFPreferencesCurrentUser,
- kCFPreferencesAnyHost);
- if (value == 0)
- return false;
- }
-
- if (CFGetTypeID(value) == CFNumberGetTypeID()) {
- if (v != 0)
- CFNumberGetValue((const CFNumberRef)value, kCFNumberIntType, v);
- } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
- if (v != 0)
- *v = CFStringGetIntValue((const CFStringRef)value);
- } else {
- CFRelease(value);
- return false;
- }
-
- CFRelease(value);
- return true;
+ FontCache::invalidate();
}
-static bool getUserDefaultValue(CFStringRef key, int *v)
+void FontCache::platformInit()
{
- CFPropertyListRef value;
-
- value = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication,
- kCFPreferencesCurrentUser,
- kCFPreferencesCurrentHost);
- if (value == 0)
- return false;
-
- if (CFGetTypeID(value) == CFNumberGetTypeID()) {
- if (v != 0)
- CFNumberGetValue((const CFNumberRef)value, kCFNumberIntType, v);
- } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
- if (v != 0)
- *v = CFStringGetIntValue((const CFStringRef)value);
- } else {
- CFRelease(value);
- return false;
- }
-
- CFRelease(value);
- return true;
+ wkSetUpFontCache();
+ // FIXME: Passing kATSFontNotifyOptionReceiveWhileSuspended may be an overkill and does not seem to work anyway.
+ ATSFontNotificationSubscribe(fontCacheATSNotificationCallback, kATSFontNotifyOptionReceiveWhileSuspended, 0, 0);
}
-static int getLCDScaleParameters(void)
+static int toAppKitFontWeight(FontWeight fontWeight)
{
- int mode;
- CFStringRef key;
-
- key = CFSTR("AppleFontSmoothing");
- if (!getAppDefaultValue(key, &mode)) {
- if (!getUserDefaultValue(key, &mode))
- return 1;
- }
-
- if (wkFontSmoothingModeIsLCD(mode))
- return 4;
- return 1;
+ static int appKitFontWeights[] = {
+ 2, // FontWeight100
+ 3, // FontWeight200
+ 4, // FontWeight300
+ 5, // FontWeight400
+ 6, // FontWeight500
+ 8, // FontWeight600
+ 9, // FontWeight700
+ 10, // FontWeight800
+ 12, // FontWeight900
+ };
+ return appKitFontWeights[fontWeight];
}
-#define MINIMUM_GLYPH_CACHE_SIZE 1536 * 1024
-
-void FontCache::platformInit()
+static inline bool isAppKitFontWeightBold(NSInteger appKitFontWeight)
{
- size_t s = MINIMUM_GLYPH_CACHE_SIZE*getLCDScaleParameters();
-
- wkSetUpFontCache(s);
+ return appKitFontWeight >= 7;
}
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
@@ -126,8 +80,7 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons
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];
+ NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(characters) length:length freeWhenDone:NO];
NSFont *substituteFont = wkGetFontInLanguageForRange(nsFont, string, NSMakeRange(0, length));
[string release];
@@ -135,49 +88,45 @@ const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, cons
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 *manager = [NSFontManager sharedFontManager];
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSFontTraitMask traits;
NSInteger weight;
CGFloat size;
if (nsFont) {
- traits = [manager traitsOfFont:nsFont];
+ traits = [fontManager traitsOfFont:nsFont];
if (platformData.m_syntheticBold)
traits |= NSBoldFontMask;
if (platformData.m_syntheticOblique)
- traits |= NSItalicFontMask;
- weight = [manager weightOfFont:nsFont];
+ traits |= NSFontItalicTrait;
+ weight = [fontManager weightOfFont:nsFont];
size = [nsFont pointSize];
} else {
// For custom fonts nsFont is nil.
- traits = (font.bold() ? NSBoldFontMask : 0) | (font.italic() ? NSItalicFontMask : 0);
- weight = 5;
+ traits = font.italic() ? NSFontItalicTrait : 0;
+ weight = toAppKitFontWeight(font.weight());
size = font.pixelSize();
}
- NSFont *bestVariation = [manager fontWithFamily:[substituteFont familyName]
- traits:traits
- weight:weight
- size:size];
- if (bestVariation)
+ if (NSFont *bestVariation = [fontManager fontWithFamily:[substituteFont familyName] traits:traits weight:weight size:size])
substituteFont = bestVariation;
- substituteFont = font.fontDescription().usePrinterFont()
- ? [substituteFont printerFont] : [substituteFont screenFont];
+ substituteFont = font.fontDescription().usePrinterFont() ? [substituteFont printerFont] : [substituteFont screenFont];
- NSFontTraitMask substituteFontTraits = [manager traitsOfFont:substituteFont];
+ NSFontTraitMask substituteFontTraits = [fontManager traitsOfFont:substituteFont];
+ NSInteger substituteFontWeight = [fontManager weightOfFont:substituteFont];
FontPlatformData alternateFont(substituteFont,
- !font.isPlatformFont() && (traits & NSBoldFontMask) && !(substituteFontTraits & NSBoldFontMask),
- !font.isPlatformFont() && (traits & NSItalicFontMask) && !(substituteFontTraits & NSItalicFontMask));
+ !font.isPlatformFont() && isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(substituteFontWeight),
+ !font.isPlatformFont() && (traits & NSFontItalicTrait) && !(substituteFontTraits & NSFontItalicTrait));
return getCachedFontData(&alternateFont);
}
@@ -220,42 +169,33 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fo
return platformFont;
}
-bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
{
- NSFontTraitMask traits = 0;
- if (fontDescription.italic())
- traits |= NSItalicFontMask;
- if (fontDescription.bold())
- traits |= NSBoldFontMask;
- float size = fontDescription.computedPixelSize();
-
- NSFont* nsFont = [WebFontCache fontWithFamily:family traits:traits size:size];
- return nsFont != 0;
+ [WebFontCache getTraits:traitsMasks inFamily:familyName];
}
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
{
- NSFontTraitMask traits = 0;
- if (fontDescription.italic())
- traits |= NSItalicFontMask;
- if (fontDescription.bold())
- traits |= NSBoldFontMask;
+ NSFontTraitMask traits = fontDescription.italic() ? NSFontItalicTrait : 0;
+ NSInteger weight = toAppKitFontWeight(fontDescription.weight());
float size = fontDescription.computedPixelSize();
-
- NSFont* nsFont = [WebFontCache fontWithFamily:family traits:traits size:size];
+
+ NSFont *nsFont = [WebFontCache fontWithFamily:family traits:traits weight:weight size:size];
if (!nsFont)
return 0;
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
NSFontTraitMask actualTraits = 0;
- if (fontDescription.bold() || fontDescription.italic())
- actualTraits = [[NSFontManager sharedFontManager] traitsOfFont:nsFont];
-
+ 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 = (traits & NSBoldFontMask) && !(actualTraits & NSBoldFontMask);
- result->m_syntheticOblique = (traits & NSItalicFontMask) && !(actualTraits & NSItalicFontMask);
+ result->m_syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight);
+ result->m_syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait);
return result;
}
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
index f143458..1fb144c 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
@@ -33,7 +33,7 @@ FontCustomPlatformData::~FontCustomPlatformData()
CGFontRelease(m_cgFont);
}
-FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic)
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
{
return FontPlatformData(m_cgFont, (ATSUFontID)m_atsFont, size, bold, italic);
}
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
index d2e83ca..1e73ae0 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.h
@@ -21,6 +21,7 @@
#ifndef FontCustomPlatformData_h
#define FontCustomPlatformData_h
+#include "FontRenderingMode.h"
#include <wtf/Noncopyable.h>
typedef struct CGFont* CGFontRef;
@@ -38,7 +39,7 @@ struct FontCustomPlatformData : Noncopyable {
{}
~FontCustomPlatformData();
- FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
ATSFontContainerRef m_atsContainer;
ATSFontRef m_atsFont;
diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm
index 06d8d9e..bef18d0 100644
--- a/WebCore/platform/graphics/mac/FontMac.mm
+++ b/WebCore/platform/graphics/mac/FontMac.mm
@@ -1,6 +1,4 @@
-/**
- * This file is part of the html renderer for KDE.
- *
+/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
@@ -20,20 +18,14 @@
* 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 "BlockExceptions.h"
-#import "CharacterNames.h"
-#import "FontFallbackList.h"
#import "GlyphBuffer.h"
#import "GraphicsContext.h"
-#import "IntRect.h"
#import "Logging.h"
-#import "ShapeArabic.h"
#import "SimpleFontData.h"
#import "WebCoreSystemInterface.h"
#import "WebCoreTextRenderer.h"
@@ -50,559 +42,6 @@ using namespace std;
namespace WebCore {
-// =================================================================
-// Font Class (Platform-Specific Portion)
-// =================================================================
-
-struct ATSULayoutParameters
-{
- ATSULayoutParameters(const TextRun& run)
- : m_run(run)
- , m_font(0)
- , m_fonts(0)
- , m_charBuffer(0)
- , m_hasSyntheticBold(false)
- , m_syntheticBoldPass(false)
- , m_padPerSpace(0)
- {}
-
- void initialize(const Font*, const GraphicsContext* = 0);
-
- const TextRun& m_run;
-
- const Font* m_font;
-
- ATSUTextLayout m_layout;
- const SimpleFontData **m_fonts;
-
- UChar *m_charBuffer;
- bool m_hasSyntheticBold;
- bool m_syntheticBoldPass;
- float m_padPerSpace;
-};
-
-// Be sure to free the array allocated by this function.
-static TextRun addDirectionalOverride(const TextRun& run, bool rtl)
-{
- UChar* charactersWithOverride = new UChar[run.length() + 2];
- charactersWithOverride[0] = rtl ? rightToLeftOverride : leftToRightOverride;
- memcpy(&charactersWithOverride[1], run.data(0), sizeof(UChar) * run.length());
- charactersWithOverride[run.length() + 1] = popDirectionalFormatting;
-
- TextRun result = run;
- result.setText(charactersWithOverride, run.length() + 2);
- return result;
-}
-
-static void initializeATSUStyle(const SimpleFontData* fontData)
-{
- // The two NSFont calls in this method (pointSize and _atsFontID) do not raise exceptions.
-
- if (!fontData->m_ATSUStyleInitialized) {
- OSStatus status;
- ByteCount propTableSize;
-
- status = ATSUCreateStyle(&fontData->m_ATSUStyle);
- if (status != noErr)
- LOG_ERROR("ATSUCreateStyle failed (%d)", status);
-
- ATSUFontID fontID = fontData->platformData().m_atsuFontID;
- if (fontID == 0) {
- ATSUDisposeStyle(fontData->m_ATSUStyle);
- LOG_ERROR("unable to get ATSUFontID for %@", fontData->m_font.font());
- return;
- }
-
- 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);
-
- // Turn off automatic kerning until it is supported in the CG code path (6136 in bugzilla)
- Fract kerningInhibitFactor = FloatToFract(1.0);
- ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
- ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) };
- 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);
- status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);
- if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info
- fontData->m_ATSUMirrors = true;
- else if (status == kATSInvalidFontTableAccess)
- fontData->m_ATSUMirrors = false;
- else
- LOG_ERROR("ATSFontGetTable failed (%d)", status);
-
- // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bugzilla 6135 is fixed.
- // 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->m_font.font() coveredCharacterSet] characterIsMember:'a']) {
- ATSUFontFeatureType featureTypes[] = { kLigaturesType };
- ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
- status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors);
- }
-
- fontData->m_ATSUStyleInitialized = true;
- }
-}
-
-static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector iCurrentOperation, ATSULineRef iLineRef, URefCon iRefCon,
- void *iOperationCallbackParameterPtr, ATSULayoutOperationCallbackStatus *oCallbackStatus)
-{
- ATSULayoutParameters *params = (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 : params->m_run.characters();
- const SimpleFontData **renderers = params->m_fonts;
- const SimpleFontData *renderer;
- const SimpleFontData *lastRenderer = 0;
- UChar ch, nextCh;
- ByteCount offset = layoutRecords[0].originalOffset;
- 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();
- 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->m_font.font() renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
- 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();
- }
- }
-
- 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 = new const SimpleFontData*[m_run.length()];
- m_charBuffer = font->isSmallCaps() ? new UChar[m_run.length()] : 0;
-
- 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, m_run.characters(), runLength * sizeof(UChar));
-
- status = ATSUCreateTextLayoutWithTextPtr(
- (m_charBuffer ? m_charBuffer : 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 = new UChar[runLength];
- memcpy(m_charBuffer, m_run.characters(), i * sizeof(UChar));
- ATSUTextMoved(layout, m_charBuffer);
- }
- shapeArabic(m_run.characters(), m_charBuffer, 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 = new UChar[runLength];
- memcpy(m_charBuffer, m_run.characters(), runLength * sizeof(UChar));
- ATSUTextMoved(layout, m_charBuffer);
- }
- 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;
-}
-
-static void disposeATSULayoutParameters(ATSULayoutParameters *params)
-{
- ATSUDisposeTextLayout(params->m_layout);
- delete []params->m_charBuffer;
- delete []params->m_fonts;
-}
-
-FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
-{
- TextRun adjustedRun = run.directionalOverride() ? addDirectionalOverride(run, run.rtl()) : run;
- 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;
- }
- disposeATSULayoutParameters(&params);
-
- 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);
-
- if (run.directionalOverride())
- delete []adjustedRun.characters();
-
- return rect;
-}
-
-void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const
-{
- OSStatus status;
-
- int drawPortionLength = to - from;
- TextRun adjustedRun = run.directionalOverride() ? addDirectionalOverride(run, run.rtl()) : run;
- 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());
- 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);
-
- disposeATSULayoutParameters(&params);
-
- if (run.directionalOverride())
- delete []adjustedRun.characters();
-}
-
-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);
-
- disposeATSULayoutParameters(&params);
-
- 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
-{
- TextRun adjustedRun = run.directionalOverride() ? addDirectionalOverride(run, run.rtl()) : run;
-
- 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;
-
- disposeATSULayoutParameters(&params);
-
- if (run.directionalOverride())
- delete []adjustedRun.characters();
-
- return offset;
-}
-
void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
{
CGContextRef cgContext = context->platformContext();
@@ -628,7 +67,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
[[[platformData.font() fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]);
}
- CGContextSetFont(cgContext, platformData.m_cgFont);
+ CGContextSetFont(cgContext, platformData.cgFont());
CGAffineTransform matrix = CGAffineTransformIdentity;
if (drawFont)
@@ -644,7 +83,28 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
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) {
@@ -652,6 +112,9 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
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
index 8f118e0..40a2dbd 100644
--- a/WebCore/platform/graphics/mac/FontPlatformData.h
+++ b/WebCore/platform/graphics/mac/FontPlatformData.h
@@ -1,8 +1,8 @@
/*
- * 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.
+ * This file is part of the internal font implementation.
+ * It should not be included by source files outside it.
*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * 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
@@ -34,46 +34,52 @@ class NSFont;
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 {
-struct FontPlatformData {
- class Deleted {};
-
- FontPlatformData(Deleted)
- : m_syntheticBold(false), m_syntheticOblique(false), m_cgFont(0), m_atsuFontID(0), m_size(0), m_font((NSFont*)-1)
- {}
+#ifndef BUILDING_ON_TIGER
+inline CTFontRef toCTFontRef(NSFont *nsFont) { return reinterpret_cast<CTFontRef>(nsFont); }
+#endif
- FontPlatformData(float s, bool b, bool o)
- : m_syntheticBold(b)
- , m_syntheticOblique(o)
- , m_cgFont(0)
+struct FontPlatformData {
+ FontPlatformData(float size, bool syntheticBold, bool syntheticOblique)
+ : m_syntheticBold(syntheticBold)
+ , m_syntheticOblique(syntheticOblique)
, m_atsuFontID(0)
- , m_size(s)
+ , m_size(size)
, m_font(0)
+#ifdef BUILDING_ON_TIGER
+ , m_cgFont(0)
+#endif
{
}
- FontPlatformData(NSFont* f = 0, bool b = false, bool o = false);
+ 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_cgFont(f), m_atsuFontID(fontID), m_size(s), m_font(0)
+ : m_syntheticBold(b), m_syntheticOblique(o), m_atsuFontID(fontID), m_size(s), m_font(0), m_cgFont(f)
{
}
- FontPlatformData(const FontPlatformData& 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;
-
- CGFontRef m_cgFont; // It is not necessary to refcount this, since either an NSFont owns it or some CachedFont has it referenced.
+
ATSUFontID m_atsuFontID;
float m_size;
@@ -84,6 +90,8 @@ struct FontPlatformData {
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 &&
@@ -91,10 +99,26 @@ struct FontPlatformData {
}
NSFont *font() const { return m_font; }
- void setFont(NSFont* 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
};
}
diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
index d1e00d1..15e573d 100644
--- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
+++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm
@@ -27,19 +27,24 @@
namespace WebCore {
-FontPlatformData::FontPlatformData(NSFont* f, bool b , bool o)
+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 != (NSFont*)-1) ? (NSFont*)CFRetain(f.m_font) : f.m_font;
+ 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;
@@ -49,22 +54,54 @@ FontPlatformData::FontPlatformData(const FontPlatformData& f)
FontPlatformData:: ~FontPlatformData()
{
- if (m_font && m_font != (NSFont*)-1)
+ if (m_font && m_font != reinterpret_cast<NSFont *>(-1))
CFRelease(m_font);
}
-void FontPlatformData::setFont(NSFont* 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 != (NSFont*)-1)
+ 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
index b9f2da3..143e665 100644
--- a/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp
+++ b/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp
@@ -37,6 +37,21 @@ 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)];
@@ -56,7 +71,6 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b
return false;
}
- bool haveGlyphs = false;
ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector);
for (unsigned i = 0; i < length; i++) {
Glyph glyph = glyphRecord->glyphID;
@@ -69,6 +83,7 @@ bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned b
glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
}
wkClearGlyphVector(&glyphVector);
+#endif
return haveGlyphs;
}
diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm
index cda73a0..63abe59 100644
--- a/WebCore/platform/graphics/mac/IconMac.mm
+++ b/WebCore/platform/graphics/mac/IconMac.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * 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
@@ -28,10 +28,6 @@
namespace WebCore {
-Icon::Icon()
-{
-}
-
Icon::Icon(NSImage *image)
: m_nsImage(image)
{
@@ -43,7 +39,7 @@ Icon::~Icon()
{
}
-PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
+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)[]
@@ -54,7 +50,23 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
if (!image)
return 0;
- return new Icon(image);
+ 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)
diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm
index 0b14d71..a0d257b 100644
--- a/WebCore/platform/graphics/mac/ImageMac.mm
+++ b/WebCore/platform/graphics/mac/ImageMac.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -30,8 +30,12 @@
#import "FoundationExtras.h"
#import "GraphicsContext.h"
#import "PlatformString.h"
-#import "WebCoreFrameBridge.h"
-#import "WebCoreSystemInterface.h"
+
+@interface WebCoreBundleFinder : NSObject
+@end
+
+@implementation WebCoreBundleFinder
+@end
namespace WebCore {
@@ -48,24 +52,22 @@ void BitmapImage::invalidatePlatformData()
m_tiffRep = 0;
}
-Image* Image::loadPlatformResource(const char *name)
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
{
- static BitmapImage nullImage;
-
- NSBundle *bundle = [NSBundle bundleForClass:[WebCoreFrameBridge class]];
+ NSBundle *bundle = [NSBundle bundleForClass:[WebCoreBundleFinder class]];
NSString *imagePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"tiff"];
NSData *namedImageData = [NSData dataWithContentsOfFile:imagePath];
if (namedImageData) {
- Image* image = new BitmapImage;
+ RefPtr<Image> image = BitmapImage::create();
image->setData(SharedBuffer::wrapNSData(namedImageData), true);
- return image;
+ 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 &nullImage;
+ return Image::nullImage();
}
CFDataRef BitmapImage::getTIFFRepresentation()
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index 8975d9b..3f18ab4 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -36,14 +36,20 @@
#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 {
@@ -99,8 +105,12 @@ public:
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();
@@ -115,6 +125,7 @@ private:
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;
@@ -124,6 +135,12 @@ private:
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
};
}
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index 85c7a9e..0ec56d6 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * 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
@@ -32,12 +32,20 @@
#import "BlockExceptions.h"
#import "GraphicsContext.h"
#import "KURL.h"
-#import "ScrollView.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)
{
@@ -59,6 +67,7 @@ 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 *)
@@ -74,6 +83,7 @@ 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()
@@ -83,6 +93,7 @@ SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *)
#define QTMediaTypeSound getQTMediaTypeSound()
#define QTMediaTypeText getQTMediaTypeText()
#define QTMediaTypeVideo getQTMediaTypeVideo()
+#define QTMovieAskUnresolvedDataRefsAttribute getQTMovieAskUnresolvedDataRefsAttribute()
#define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute()
#define QTMovieDidEndNotification getQTMovieDidEndNotification()
#define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute()
@@ -98,6 +109,7 @@ SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *)
#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
@@ -116,10 +128,12 @@ 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;
@@ -129,11 +143,19 @@ using namespace std;
-(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])
@@ -145,12 +167,18 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, 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()
{
- detachQTMovieView();
+ tearDownVideoRendering();
[[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
[m_objcObserver.get() disconnect];
@@ -160,23 +188,29 @@ void MediaPlayerPrivate::createQTMovie(const String& url)
{
[[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
- m_qtMovie = 0;
+ if (m_qtMovie) {
+ destroyQTVideoRenderer();
+ m_qtMovie = 0;
+ }
// Disable streaming support for now, <rdar://problem/5693967>
- if (url.startsWith("rtsp:"))
+ if (protocolIs(url, "rtsp"))
return;
-
- NSDictionary* movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
- KURL(url.deprecatedString()).getNSURL(), QTMovieURLAttribute,
+
+ 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 = url.startsWith("rtsp:");
+ m_isStreaming = protocolIs(url, "rtsp");
if (!m_qtMovie)
return;
@@ -220,13 +254,16 @@ static void mainThreadSetNeedsDisplay(id self, SEL _cmd)
[delegate repaint];
}
+static Class QTVideoRendererClass()
+{
+ static Class QTVideoRendererWebKitOnlyClass = NSClassFromString(@"QTVideoRendererWebKitOnly");
+ return QTVideoRendererWebKitOnlyClass;
+}
+
void MediaPlayerPrivate::createQTMovieView()
{
detachQTMovieView();
- if (!m_player->m_parentWidget || !m_qtMovie)
- return;
-
static bool addedCustomMethods = false;
if (!addedCustomMethods) {
Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView");
@@ -241,7 +278,7 @@ void MediaPlayerPrivate::createQTMovieView()
m_qtMovieView.adoptNS([[QTMovieView alloc] init]);
setRect(m_player->rect());
- NSView* parentView = static_cast<ScrollView*>(m_player->m_parentWidget)->getDocumentView();
+ 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
@@ -249,17 +286,24 @@ void MediaPlayerPrivate::createQTMovieView()
#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]];
- wkQTMovieViewSetDrawSynchronously(m_qtMovieView.get(), YES);
+
+ // 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];
@@ -271,6 +315,59 @@ void MediaPlayerPrivate::detachQTMovieView()
}
}
+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)
@@ -295,8 +392,6 @@ void MediaPlayerPrivate::load(const String& url)
[m_objcObserver.get() setDelayCallbacks:YES];
createQTMovie(url);
- if (m_player->visible())
- createQTMovieView();
[m_objcObserver.get() loadStateChanged:nil];
[m_objcObserver.get() setDelayCallbacks:NO];
@@ -307,6 +402,9 @@ 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];
@@ -318,6 +416,9 @@ 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];
@@ -521,7 +622,7 @@ void MediaPlayerPrivate::cancelLoad()
if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
return;
- detachQTMovieView();
+ tearDownVideoRendering();
m_qtMovie = nil;
updateStates();
@@ -534,14 +635,14 @@ void MediaPlayerPrivate::updateStates()
long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError);
- if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData) {
+ 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)
@@ -576,6 +677,9 @@ void MediaPlayerPrivate::updateStates()
m_player->networkStateChanged();
if (m_readyState != oldReadyState)
m_player->readyStateChanged();
+
+ if (loadState >= QTMovieLoadStateLoaded && oldNetworkState < MediaPlayer::LoadedMetaData && m_player->visible())
+ setUpVideoRendering();
}
void MediaPlayerPrivate::loadStateChanged()
@@ -602,6 +706,9 @@ void MediaPlayerPrivate::didEnd()
{
m_endPointTimer.stop();
m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate];
+#endif
updateStates();
m_player->timeChanged();
}
@@ -610,23 +717,42 @@ void MediaPlayerPrivate::setRect(const IntRect& r)
{
if (!m_qtMovieView)
return;
- // 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];
+
+ 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 (b)
- createQTMovieView();
- else
- detachQTMovieView();
+ 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();
}
@@ -635,16 +761,52 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
if (context->paintingDisabled())
return;
NSView *view = m_qtMovieView.get();
- if (view == nil)
+ 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];
- [view displayRectIgnoringOpacity:paintRect inContext:newContext];
+
+ // 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];
@@ -668,9 +830,9 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
bool MediaPlayerPrivate::isAvailable()
{
+#ifdef BUILDING_ON_TIGER
SInt32 version;
OSErr result;
- // This Carbon API is available in 64 bit too
result = Gestalt(gestaltQuickTime, &version);
if (result != noErr) {
LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support.");
@@ -681,6 +843,10 @@ bool MediaPlayerPrivate::isAvailable()
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)
@@ -784,6 +950,17 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
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)
@@ -832,6 +1009,11 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount)
m_callback->didEnd();
}
+- (void)newImageAvailable:(NSNotification *)notification
+{
+ [self repaint];
+}
+
- (void)setDelayCallbacks:(BOOL)shouldDelay
{
m_delayCallbacks = shouldDelay;
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index 1f45c94..4ee5933 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -56,13 +56,14 @@ static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (c
bool initFontData(SimpleFontData* fontData)
{
- if (!fontData->m_font.m_cgFont)
+ 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);
@@ -84,6 +85,7 @@ bool initFontData(SimpleFontData* fontData)
}
ATSUDisposeStyle(fontStyle);
+#endif
return true;
}
@@ -96,16 +98,63 @@ static NSString *webFallbackFontFamily(void)
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.
@@ -126,9 +175,12 @@ void SimpleFontData::platformInit()
#if !ERROR_DISABLED
RetainPtr<NSFont> initialFont = m_font.font();
#endif
- m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:fallbackFontFamily]);
+ 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 = wkPathFromFont(initialFont.get());
+ NSString *filePath = pathFromFont(initialFont.get());
if (!filePath)
filePath = @"not known";
#endif
@@ -165,7 +217,15 @@ void SimpleFontData::platformInit()
int iAscent;
int iDescent;
int iLineGap;
- wkGetFontMetrics(m_font.m_cgFont, &iAscent, &iDescent, &iLineGap, &m_unitsPerEm);
+#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;
@@ -179,6 +239,13 @@ void SimpleFontData::platformInit()
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);
@@ -209,11 +276,14 @@ void SimpleFontData::platformInit()
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
@@ -290,13 +360,14 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
float pointSize = m_font.m_size;
CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
CGSize advance;
- if (!wkGetGlyphTransformedAdvances(m_font.m_cgFont, font, &m, &glyph, &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);
@@ -325,5 +396,40 @@ void SimpleFontData::checkShapesArabic() const
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
index 8bd5c87..2793043 100644
--- a/WebCore/platform/graphics/qt/AffineTransformQt.cpp
+++ b/WebCore/platform/graphics/qt/AffineTransformQt.cpp
@@ -41,7 +41,7 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double
{
}
-AffineTransform::AffineTransform(const QMatrix& matrix)
+AffineTransform::AffineTransform(const PlatformAffineTransform& matrix)
: m_transform(matrix)
{
}
diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp
index 8fb3fba..be31d96 100644
--- a/WebCore/platform/graphics/qt/FontCacheQt.cpp
+++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2007 Trolltech ASA
+ 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
@@ -26,14 +26,8 @@
namespace WebCore {
-bool FontCache::fontExists(const FontDescription &desc, const AtomicString& family)
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
{
- // try to construct a QFont inside WebCore::Font to see if we know about this font
- FontDescription fnt(desc);
- FontFamily fam;
- fam.setFamily(family);
- fnt.setFamily(fam);
- return Font(fnt, /*letterSpacing*/0, /*wordSpacing*/0).font().exactMatch();
}
FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName)
@@ -51,4 +45,12 @@ 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
index 67193d4..8fc3ea0 100644
--- a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2007 Trolltech ASA
+ 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
@@ -33,7 +33,7 @@ FontCustomPlatformData::~FontCustomPlatformData()
QFontDatabase::removeApplicationFont(handle);
}
-FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic)
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode)
{
FontPlatformData result;
result.handle = handle;
diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/WebCore/platform/graphics/qt/FontCustomPlatformData.h
index b7a2b15..da5159d 100644
--- a/WebCore/platform/graphics/qt/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2007 Trolltech ASA
+ 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
@@ -22,6 +22,7 @@
#ifndef FontCustomPlatformData_h_
#define FontCustomPlatformData_h_
+#include "FontRenderingMode.h"
#include <wtf/Noncopyable.h>
namespace WebCore {
@@ -34,7 +35,7 @@ struct FontCustomPlatformData : Noncopyable {
int handle; // for use with QFontDatabase::addApplicationFont/removeApplicationFont
- FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
};
FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h
index 7daf6ed..e4363be 100644
--- a/WebCore/platform/graphics/qt/FontPlatformData.h
+++ b/WebCore/platform/graphics/qt/FontPlatformData.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2007 Trolltech ASA
+ 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
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index 29b63bf..e2ef605 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2007 Trolltech ASA
+ 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
@@ -15,10 +15,8 @@
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 "Font.h"
#include "FontDescription.h"
@@ -64,12 +62,12 @@ Font::Font(const FontDescription& description, short letterSpacing, short wordSp
m_font.setFamily(familyName);
m_font.setPixelSize(qRound(description.computedSize()));
m_font.setItalic(description.italic());
- if (description.bold()) {
- // Qt's Bold is 75, Webkit is 63.
+ // FIXME: Map all FontWeight values to QFont weights.
+ if (description.weight() >= FontWeight600)
m_font.setWeight(QFont::Bold);
- } else {
- m_font.setWeight(description.weight());
- }
+ else
+ m_font.setWeight(QFont::Normal);
+
bool smallCaps = description.smallCaps();
m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase);
@@ -133,6 +131,12 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint&
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);
@@ -145,9 +149,31 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint&
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;
@@ -157,6 +183,14 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint&
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());
}
@@ -165,7 +199,9 @@ int Font::width(const TextRun& run) const
if (!run.length())
return 0;
QString string = qstring(run);
- int w = QFontMetrics(m_font).width(string);
+ 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;
@@ -178,6 +214,13 @@ 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);
@@ -272,12 +315,12 @@ Font::Font(const FontDescription& description, short letterSpacing, short wordSp
m_font.setFamily(familyName);
m_font.setPixelSize(qRound(description.computedSize()));
m_font.setItalic(description.italic());
- if (description.bold()) {
- // Qt's Bold is 75, Webkit is 63.
+ // FIXME: Map all FontWeight values to QFont weights.
+ if (description.weight() >= FontWeight600)
m_font.setWeight(QFont::Bold);
- } else {
- m_font.setWeight(description.weight());
- }
+ else
+ m_font.setWeight(QFont::Normal);
+
QFontMetrics metrics = QFontMetrics(m_font);
m_spaceWidth = metrics.width(QLatin1Char(' '));
m_scFont = m_font;
@@ -469,6 +512,13 @@ 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;
@@ -633,6 +683,11 @@ 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();
diff --git a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
index 220807e..d32cc63 100644
--- a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
+++ b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2007 Trolltech ASA
+ 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
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
index cf097c8..600d77c 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -5,6 +5,9 @@
* 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.
*
@@ -32,20 +35,32 @@
#include "config.h"
+#ifdef Q_WS_WIN
+#include <windows.h>
+#endif
+
#include "AffineTransform.h"
-#include "Path.h"
#include "Color.h"
-#include "GraphicsContext.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 <QStack>
+#include <QDebug>
+#include <QGradient>
#include <QPainter>
-#include <QPolygonF>
-#include <QPainterPath>
#include <QPaintDevice>
-#include <QDebug>
+#include <QPaintEngine>
+#include <QPainterPath>
+#include <QPixmap>
+#include <QPolygonF>
+#include <QStack>
+#include <QVector>
#ifndef M_PI
#define M_PI 3.14159265358979323846
@@ -137,6 +152,22 @@ static Qt::PenStyle toQPenStyle(StrokeStyle 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)
@@ -145,13 +176,15 @@ struct TransparencyLayer
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());
- painter.setCompositionMode(p->compositionMode());
+ if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ painter.setCompositionMode(p->compositionMode());
painter.setClipPath(p->clipPath());
}
@@ -168,24 +201,6 @@ private:
TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
};
-struct TextShadow
-{
- TextShadow()
- : x(0)
- , y(0)
- , blur(0)
- {
- }
-
- bool isNull() { return !x && !y && !blur; }
-
- int x;
- int y;
- int blur;
-
- Color color;
-};
-
class GraphicsContextPlatformPrivate
{
public:
@@ -203,12 +218,12 @@ public:
return &layers.top()->painter;
}
- QPaintDevice* device;
+ bool antiAliasingForRectsAndLines;
QStack<TransparencyLayer *> layers;
QPainter* redirect;
- TextShadow shadow;
+ QBrush solidColor;
// Only used by SVG for now.
QPainterPath currentPath;
@@ -221,12 +236,18 @@ private:
GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p)
{
painter = p;
- device = painter ? painter->device() : 0;
redirect = 0;
- // FIXME: Maybe only enable in SVG mode?
- if (painter)
- painter->setRenderHint(QPainter::Antialiasing);
+ 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()
@@ -386,7 +407,13 @@ void GraphicsContext::drawRect(const IntRect& rect)
if (paintingDisabled())
return;
- m_data->p()->drawRect(rect);
+ 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.
@@ -429,8 +456,25 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
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());
- m_data->p()->drawLine(p1, p2);
+
+ 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.
@@ -447,7 +491,13 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp
if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha())
return;
- m_data->p()->drawArc(rect, startAngle * 16, angleSpan * 16);
+ 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)
@@ -470,12 +520,80 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
p->restore();
}
-void GraphicsContext::fillRect(const IntRect& rect, const Color& c)
+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;
- m_data->p()->fillRect(rect, QColor(c));
+ 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)
@@ -483,7 +601,8 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c)
if (paintingDisabled())
return;
- m_data->p()->fillRect(rect, QColor(c));
+ 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)
@@ -505,9 +624,9 @@ void GraphicsContext::addPath(const Path& path)
m_data->currentPath = *(path.platformPath());
}
-void GraphicsContext::setFillRule(WindRule rule)
+bool GraphicsContext::inTransparencyLayer() const
{
- m_data->currentPath.setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+ return !m_data->layers.isEmpty();
}
PlatformPath* GraphicsContext::currentPath()
@@ -515,7 +634,7 @@ PlatformPath* GraphicsContext::currentPath()
return &m_data->currentPath;
}
-void GraphicsContext::clip(const IntRect& rect)
+void GraphicsContext::clip(const FloatRect& rect)
{
if (paintingDisabled())
return;
@@ -531,7 +650,6 @@ void GraphicsContext::clip(const IntRect& rect)
* RenderTheme handles drawing focus on widgets which
* need it.
*/
-void setFocusRingColorChangeFunction(void (*)()) { }
Color focusRingColor() { return Color(0, 0, 0); }
void GraphicsContext::drawFocusRing(const Color& color)
{
@@ -545,6 +663,8 @@ void GraphicsContext::drawFocusRing(const Color& color)
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();
@@ -568,6 +688,8 @@ void GraphicsContext::drawFocusRing(const Color& color)
#endif
p->setPen(oldPen);
p->setBrush(oldBrush);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
}
void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing)
@@ -597,23 +719,16 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
return FloatRect(QRectF(result));
}
-void GraphicsContext::setShadow(const IntSize& pos, int blur, const Color &color)
+void GraphicsContext::setPlatformShadow(const IntSize& pos, int blur, const Color &color)
{
- if (paintingDisabled())
- return;
-
- m_data->shadow.x = pos.width();
- m_data->shadow.y = pos.height();
- m_data->shadow.blur = blur;
- m_data->shadow.color = color;
+ // Qt doesn't support shadows natively, they are drawn manually in the draw*
+ // functions
}
-void GraphicsContext::clearShadow()
+void GraphicsContext::clearPlatformShadow()
{
- if (paintingDisabled())
- return;
-
- m_data->shadow = TextShadow();
+ // Qt doesn't support shadows natively, they are drawn manually in the draw*
+ // functions
}
void GraphicsContext::beginTransparencyLayer(float opacity)
@@ -623,20 +738,18 @@ void GraphicsContext::beginTransparencyLayer(float opacity)
int x, y, w, h;
x = y = 0;
- w = m_data->device->width();
- h = m_data->device->height();
-
QPainter *p = m_data->p();
+ const QPaintDevice *device = p->device();
+ w = device->width();
+ h = device->height();
+
QRectF clip = p->clipPath().boundingRect();
- bool ok;
- QTransform transform = p->transform().inverted(&ok);
- if (ok) {
- QRectF deviceClip = 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);
- }
+ 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;
@@ -668,9 +781,11 @@ void GraphicsContext::clearRect(const FloatRect& rect)
QPainter *p = m_data->p();
QPainter::CompositionMode currentCompositionMode = p->compositionMode();
- p->setCompositionMode(QPainter::CompositionMode_Source);
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(QPainter::CompositionMode_Source);
p->eraseRect(rect);
- p->setCompositionMode(currentCompositionMode);
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(currentCompositionMode);
}
void GraphicsContext::strokeRect(const FloatRect& rect, float width)
@@ -678,12 +793,12 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width)
if (paintingDisabled())
return;
- QPainter *p = m_data->p();
QPainterPath path;
path.addRect(rect);
- QPen nPen = p->pen();
- nPen.setWidthF(width);
- p->strokePath(path, nPen);
+ setStrokeThickness(width);
+ m_data->currentPath = path;
+
+ strokePath();
}
void GraphicsContext::setLineCap(LineCap lc)
@@ -697,6 +812,26 @@ void GraphicsContext::setLineCap(LineCap 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())
@@ -732,7 +867,8 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op)
if (paintingDisabled())
return;
- m_data->p()->setCompositionMode(toQtCompositionMode(op));
+ if (m_data->p()->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ m_data->p()->setCompositionMode(toQtCompositionMode(op));
}
void GraphicsContext::clip(const Path& path)
@@ -780,7 +916,7 @@ void GraphicsContext::rotate(float radians)
if (paintingDisabled())
return;
- m_data->p()->rotate(radians);
+ m_data->p()->rotate(180/M_PI*radians);
}
void GraphicsContext::scale(const FloatSize& s)
@@ -795,7 +931,7 @@ void GraphicsContext::clipOut(const IntRect& rect)
{
if (paintingDisabled())
return;
-
+
QPainter *p = m_data->p();
QRectF clipBounds = p->clipPath().boundingRect();
QPainterPath newClip;
@@ -810,7 +946,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
{
if (paintingDisabled())
return;
-
+
QPainter *p = m_data->p();
QRectF clipBounds = p->clipPath().boundingRect();
QPainterPath newClip;
@@ -821,6 +957,11 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect)
p->setClipPath(newClip, Qt::IntersectClip);
}
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
+{
+ notImplemented();
+}
+
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
int thickness)
{
@@ -872,7 +1013,7 @@ void GraphicsContext::setPlatformStrokeColor(const Color& color)
}
void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle)
-{
+{
if (paintingDisabled())
return;
QPainter *p = m_data->p();
@@ -905,6 +1046,101 @@ void GraphicsContext::setUseAntialiasing(bool enable)
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
index e39d161..b04668c 100644
--- a/WebCore/platform/graphics/qt/IconQt.cpp
+++ b/WebCore/platform/graphics/qt/IconQt.cpp
@@ -22,7 +22,6 @@
#include "Icon.h"
#include "GraphicsContext.h"
-#include "DeprecatedString.h"
#include "PlatformString.h"
#include "IntRect.h"
#include "NotImplemented.h"
@@ -42,11 +41,17 @@ Icon::~Icon()
{
}
-PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
{
- Icon *i = new Icon;
+ RefPtr<Icon> i = adoptRef(new Icon);
i->m_icon = QIcon(filename);
- return PassRefPtr<Icon>(i);
+ return i.release();
+}
+
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ //FIXME: Implement this
+ return 0;
}
void Icon::paint(GraphicsContext* ctx, const IntRect& rect)
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
index c95d8c8..d4ab59f 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -1,5 +1,6 @@
/*
* 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
@@ -26,47 +27,89 @@
#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 {
-std::auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale)
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_pixmap(size)
{
- QPixmap px(size);
- return std::auto_ptr<ImageBuffer>(new ImageBuffer(px));
+ m_pixmap.fill(QColor(Qt::transparent));
+ m_painter.set(new QPainter(&m_pixmap));
}
-ImageBuffer::ImageBuffer(const QPixmap& px)
- : m_pixmap(px),
- m_painter(0)
+ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success)
+ : m_data(size)
+ , m_size(size)
{
- m_painter = new QPainter(&m_pixmap);
- m_context.set(new GraphicsContext(m_painter));
+ m_context.set(new GraphicsContext(m_data.m_painter.get()));
+ success = true;
}
ImageBuffer::~ImageBuffer()
{
- delete m_painter;
}
GraphicsContext* ImageBuffer::context() const
{
- if (!m_painter->isActive())
- m_painter->begin(&m_pixmap);
+ ASSERT(m_data.m_painter->isActive());
return m_context.get();
}
-QPixmap* ImageBuffer::pixmap() const
+Image* ImageBuffer::image() const
{
- if (!m_painter)
- return &m_pixmap;
- if (m_painter->isActive())
- m_painter->end();
- return &m_pixmap;
+ 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
index 44ab0d3..e3b00a1 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
- * Copyright (C) 2006 Trolltech ASA
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
*
* All rights reserved.
*
@@ -206,7 +206,7 @@ void ImageDecoderQt::reset()
void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived)
{
reset();
- ReadContext readContext(data, ReadContext::LoadIncrementally, m_imageList);
+ ReadContext readContext(data, ReadContext::LoadComplete, m_imageList);
if (debugImageDecoderQt)
qDebug() << " setData " << data.size() << " image bytes, complete=" << allDataReceived;
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h
index 32f91d1..3573dd0 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.h
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
- * Copyright (C) 2006 Trolltech ASA
+ * 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
diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp
index 206aee3..9234c69 100644
--- a/WebCore/platform/graphics/qt/ImageQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -36,6 +36,7 @@
#include "GraphicsContext.h"
#include "AffineTransform.h"
#include "NotImplemented.h"
+#include "StillImageQt.h"
#include "qwebsettings.h"
#include <QPixmap>
@@ -53,17 +54,15 @@
// This function loads resources into WebKit
static QPixmap loadResourcePixmap(const char *name)
{
- const QString resource = name;
-
QPixmap pixmap;
- if (resource == "missingImage")
+ if (qstrcmp(name, "missingImage") == 0)
pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic);
- else if (resource == "nullPlugin")
+ else if (qstrcmp(name, "nullPlugin") == 0)
pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic);
- else if (resource == "urlIcon")
- pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFaviconGraphic);
- else if (resource == "textAreaResizeCorner")
- pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaResizeCornerGraphic);
+ else if (qstrcmp(name, "urlIcon") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic);
+ else if (qstrcmp(name, "textAreaResizeCorner") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic);
return pixmap;
}
@@ -74,8 +73,9 @@ void FrameData::clear()
{
if (m_frame) {
m_frame = 0;
- m_duration = 0.0f;
- m_hasAlpha = true;
+ // 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.
}
}
@@ -85,10 +85,9 @@ void FrameData::clear()
// Image Class
// ================================================
-Image* Image::loadPlatformResource(const char* name)
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
{
- BitmapImage* img = new BitmapImage(loadResourcePixmap(name));
- return img;
+ return StillImage::create(loadResourcePixmap(name));
}
@@ -98,39 +97,20 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const
notImplemented();
}
-BitmapImage::BitmapImage(const QPixmap &pixmap, ImageObserver *observer)
- : Image(observer)
- , m_currentFrame(0)
- , m_frames(0)
- , m_frameTimer(0)
- , m_repetitionCount(0)
- , m_repetitionsComplete(0)
- , m_isSolidColor(false)
- , m_animatingImageType(true)
- , m_animationFinished(false)
- , m_allDataReceived(false)
- , m_haveSize(false)
- , m_sizeAvailable(false)
- , m_decodedSize(0)
-{
- m_pixmap = new QPixmap(pixmap);
-}
-
void BitmapImage::initPlatformData()
{
- m_pixmap = 0;
}
void BitmapImage::invalidatePlatformData()
{
- delete m_pixmap;
- m_pixmap = 0;
}
// Drawing Routines
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
const FloatRect& src, CompositeOperator op)
{
+ startAnimation();
+
QPixmap* image = nativeImageForCurrentFrame();
if (!image)
return;
@@ -154,8 +134,6 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
painter->drawPixmap(dst, *image, src);
ctxt->restore();
-
- startAnimation();
}
void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
@@ -171,23 +149,14 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
pixmap = pixmap.copy(tr);
}
- if (patternTransform.isIdentity()) {
- ctxt->save();
- ctxt->setCompositeOperation(op);
- QPainter* p = ctxt->platformContext();
- p->setBrushOrigin(phase);
- p->drawTiledPixmap(destRect, pixmap);
- ctxt->restore();
- } else {
- QBrush b(pixmap);
- b.setMatrix(patternTransform);
- ctxt->save();
- ctxt->setCompositeOperation(op);
- QPainter* p = ctxt->platformContext();
- p->setBrushOrigin(phase);
- p->fillRect(destRect, b);
- ctxt->restore();
- }
+ 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()
@@ -196,14 +165,6 @@ void BitmapImage::checkForSolidColor()
m_isSolidColor = false;
}
-QPixmap* BitmapImage::getPixmap() const
-{
- if (!m_pixmap)
- return const_cast<BitmapImage*>(this)->frameAtIndex(0);
- else
- return m_pixmap;
-}
-
}
diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
index 84d503f..1d14f9d 100644
--- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2006 Trolltech ASA
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
*
* All rights reserved.
*
@@ -31,63 +31,29 @@
#include "ImageDecoderQt.h"
#include "SharedBuffer.h"
+#include <QBuffer>
#include <QImage>
-#include <qdebug.h>
-
+#include <QImageReader>
namespace WebCore {
- enum ImageFormat { ImageFormat_None, ImageFormat_GIF, ImageFormat_PNG, ImageFormat_JPEG,
- ImageFormat_BMP, ImageFormat_ICO, ImageFormat_XBM };
-
-ImageFormat detectImageFormat(const SharedBuffer& data)
+static bool canHandleImage(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 ImageFormat_None;
-
- 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 ImageFormat_GIF;
-
- // Test for PNG.
- if (uContents[0] == 0x89 &&
- uContents[1] == 0x50 &&
- uContents[2] == 0x4E &&
- uContents[3] == 0x47)
- return ImageFormat_PNG;
-
- // JPEG
- if (uContents[0] == 0xFF &&
- uContents[1] == 0xD8 &&
- uContents[2] == 0xFF)
- return ImageFormat_JPEG;
-
- // BMP
- if (strncmp(contents, "BM", 2) == 0)
- return ImageFormat_BMP;
-
- // 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 ImageFormat_ICO;
-
- // XBMs require 8 bytes of info.
- if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
- return ImageFormat_XBM;
-
- // Give up. We don't know what the heck this is.
- return ImageFormat_None;
+ 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 (detectImageFormat(data) != ImageFormat_None)
- return new ImageDecoderQt();
- return 0;
+ if (!canHandleImage(data))
+ return 0;
+ return new ImageDecoderQt();
}
ImageSource::ImageSource()
@@ -136,6 +102,11 @@ IntSize ImageSource::size() const
return m_decoder->size();
}
+IntSize ImageSource::frameSizeAtIndex(size_t) const
+{
+ return size();
+}
+
int ImageSource::repetitionCount()
{
if (!m_decoder)
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
index 240350f..76f375c 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -155,7 +155,7 @@ void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool antic
// this is also due to switched coordinate system
// we would end up with a 0 span instead of 360
- if (!(qFuzzyCompare(span + (ea - sa), 0.0) &&
+ if (!(qFuzzyCompare(span + (ea - sa) + 1, 1.0) &&
qFuzzyCompare(qAbs(span), 360.0))) {
span += ea - sa;
}
@@ -194,10 +194,10 @@ String Path::debugString() const
switch (cur.type) {
case QPainterPath::MoveToElement:
- ret += QString("M %1 %2").arg(cur.x).arg(cur.y);
+ ret += QString(QLatin1String("M %1 %2")).arg(cur.x).arg(cur.y);
break;
case QPainterPath::LineToElement:
- ret += QString("L %1 %2").arg(cur.x).arg(cur.y);
+ ret += QString(QLatin1String("L %1 %2")).arg(cur.x).arg(cur.y);
break;
case QPainterPath::CurveToElement:
{
@@ -207,7 +207,7 @@ String Path::debugString() const
Q_ASSERT(c1.type == QPainterPath::CurveToDataElement);
Q_ASSERT(c2.type == QPainterPath::CurveToDataElement);
- ret += QString("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);
+ 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;
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
index 1a45ce4..1ffce33 100644
--- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
+++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2007 Trolltech ASA
+ 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
@@ -22,10 +22,14 @@
#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)
+ : m_font(font)
+ , m_isCustomFont(customFont)
+ , m_isLoading(loading)
{
}
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
index e7fbf47..a04fd81 100644
--- a/WebCore/platform/graphics/win/ColorSafari.cpp
+++ b/WebCore/platform/graphics/win/ColorSafari.cpp
@@ -68,9 +68,4 @@ Color focusRingColor()
return focusRingColor;
}
-void setFocusRingColorChangeFunction(void (*)())
-{
- notImplemented();
-}
-
} // namespace WebCore
diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp
index 8b59a48..1766cd9 100644
--- a/WebCore/platform/graphics/win/FontCGWin.cpp
+++ b/WebCore/platform/graphics/win/FontCGWin.cpp
@@ -26,11 +26,14 @@
#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>
@@ -39,59 +42,266 @@ namespace WebCore {
const int syntheticObliqueAngle = 14;
-void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
- int from, int numGlyphs, const FloatPoint& point) const
+static inline CGFloat toCGFloat(FIXED f)
{
- if (font->m_font.useGDI()) {
- // FIXME: Support alpha blending.
- // FIXME: Support text stroke/fill.
- // FIXME: Support text shadow.
- Color fillColor = graphicsContext->fillColor();
- if (fillColor.alpha() == 0)
+ 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;
- // 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];
+ 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();
- IntRect textRect(point.x() - lineGap, point.y() - font->ascent() - lineGap, totalWidth + 2 * lineGap, font->lineSpacing());
- HDC hdc = graphicsContext->getWindowsContext(textRect);
- SelectObject(hdc, font->m_font.hfont());
+ 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();
- // Set the correct color.
- HDC textDrawingDC = 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);
+ 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;
+ // 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.eM22 = 1.0;
- xform.eDx = translation.width();
- xform.eDy = translation.height();
+ 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);
+ }
}
- ExtTextOut(hdc, point.x(), point.y(), ETO_GLYPH_INDEX, 0, (WCHAR*)glyphBuffer.glyphs(from), numGlyphs, gdiAdvances.data());
+ 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);
+}
- graphicsContext->releaseWindowsContext(hdc, textRect);
+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);
+ uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, WebCoreShouldUseFontSmoothing());
const FontPlatformData& platformData = font->platformData();
@@ -102,25 +312,49 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
matrix.d = -matrix.d;
if (platformData.syntheticOblique()) {
- static float skew = -tanf(syntheticObliqueAngle * acosf(0) / 90.0f);
+ 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);
- if (translation.width() || translation.height())
- CGAffineTransformTranslate(matrix, translation.width(), translation.height());
-
- CGContextSetTextMatrix(cgContext, matrix);
CGContextSetFontSize(cgContext, platformData.size());
- CGContextSetTextPosition(cgContext, point.x(), point.y());
+ 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() + font->m_syntheticBoldOffset, point.y());
+ 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
index 502863b..49b3d76 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * 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
@@ -35,8 +35,10 @@
#include "UnicodeRange.h"
#include <windows.h>
#include <mlang.h>
+#if PLATFORM(CG)
#include <ApplicationServices/ApplicationServices.h>
#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
using std::min;
@@ -45,7 +47,9 @@ namespace WebCore
void FontCache::platformInit()
{
+#if PLATFORM(CG)
wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
+#endif
}
IMLangFontLink2* FontCache::getFontLinkInterface()
@@ -304,55 +308,169 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fo
return getCachedFontPlatformData(fontDescription, timesStr);
}
-bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+static LONG toGDIFontWeight(FontWeight fontWeight)
{
- LOGFONT winfont;
-
- // The size here looks unusual. The negative number is intentional. The logical size constant is 32.
- winfont.lfHeight = -fontDescription.computedPixelSize() * 32;
- winfont.lfWidth = 0;
- winfont.lfEscapement = 0;
- winfont.lfOrientation = 0;
- winfont.lfUnderline = false;
- winfont.lfStrikeOut = false;
- winfont.lfCharSet = DEFAULT_CHARSET;
-#if PLATFORM(CG)
- winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ 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
- winfont.lfOutPrecision = OUT_TT_PRECIS;
+ matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS;
#endif
- winfont.lfQuality = 5; // Force cleartype.
- winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- winfont.lfItalic = fontDescription.italic();
-
- // FIXME: Support weights for real. Do our own enumeration of the available weights.
- // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
- // gaps in the weight list.
- // FIXME: Hardcoding Lucida Grande for now. It uses different weights than typical Win32 fonts
- // (500/600 instead of 400/700).
- static AtomicString lucidaStr("Lucida Grande");
- if (equalIgnoringCase(family, lucidaStr))
- winfont.lfWeight = fontDescription.bold() ? 600 : 500;
- else
- winfont.lfWeight = fontDescription.bold() ? 700 : 400;
- int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
- memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
- winfont.lfFaceName[len] = '\0';
-
- HFONT hfont = CreateFontIndirect(&winfont);
- // Windows will always give us a valid pointer here, even if the face name is non-existent. We have to double-check
- // and see if the family name was really used.
- HDC dc = GetDC(0);
- SaveDC(dc);
- SelectObject(dc, hfont);
- WCHAR name[LF_FACESIZE];
- GetTextFace(dc, LF_FACESIZE, name);
- RestoreDC(dc, -1);
- ReleaseDC(0, dc);
-
- DeleteObject(hfont);
-
- return !wcsicmp(winfont.lfFaceName, name);
+ 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)
@@ -364,57 +482,34 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande;
- LOGFONT winfont;
-
- // The size here looks unusual. The negative number is intentional. 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.
- winfont.lfHeight = -fontDescription.computedPixelSize() * (useGDI ? 1 : 32);
- winfont.lfWidth = 0;
- winfont.lfEscapement = 0;
- winfont.lfOrientation = 0;
- winfont.lfUnderline = false;
- winfont.lfStrikeOut = false;
- winfont.lfCharSet = DEFAULT_CHARSET;
- winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
- winfont.lfQuality = DEFAULT_QUALITY;
- winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- winfont.lfItalic = fontDescription.italic();
-
- // FIXME: Support weights for real. Do our own enumeration of the available weights.
- // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
- // gaps in the weight list.
- // FIXME: Hardcoding Lucida Grande for now. It uses different weights than typical Win32 fonts
- // (500/600 instead of 400/700).
- if (isLucidaGrande) {
- winfont.lfWeight = fontDescription.bold() ? 600 : 500;
- useGDI = false; // Never use GDI for Lucida Grande.
- } else
- winfont.lfWeight = fontDescription.bold() ? 700 : 400;
- int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
- memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
- winfont.lfFaceName[len] = '\0';
-
- HFONT hfont = CreateFontIndirect(&winfont);
- // Windows will always give us a valid pointer here, even if the face name is non-existent. We have to double-check
- // and see if the family name was really used.
- HDC dc = GetDC(0);
- SaveDC(dc);
- SelectObject(dc, hfont);
- WCHAR name[LF_FACESIZE];
- GetTextFace(dc, LF_FACESIZE, name);
- RestoreDC(dc, -1);
- ReleaseDC(0, dc);
-
- if (_wcsicmp(winfont.lfFaceName, name)) {
- DeleteObject(hfont);
+ // 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;
- }
-
- FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(),
- fontDescription.bold(), fontDescription.italic(), useGDI);
- if (!result->cgFont()) {
+
+ 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.
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
index cf03502..26fceba 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Computer, Inc.
+ * 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
@@ -21,21 +21,72 @@
#include "config.h"
#include "FontCustomPlatformData.h"
-#include <wtf/RetainPtr.h>
-#include <ApplicationServices/ApplicationServices.h>
-#include "SharedBuffer.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)
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode renderingMode)
{
- return FontPlatformData(m_cgFont, size, bold, italic);
+ 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)
@@ -60,9 +111,82 @@ size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count)
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 };
@@ -70,7 +194,42 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider.get());
if (!cgFont)
return 0;
- return new FontCustomPlatformData(cgFont);
+
+ // 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
index 9f30424..34a9851 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Computer, Inc.
+ * 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
@@ -21,6 +21,8 @@
#ifndef FontCustomPlatformData_h
#define FontCustomPlatformData_h
+#include "FontRenderingMode.h"
+#include "PlatformString.h"
#include <wtf/Noncopyable.h>
typedef struct CGFont* CGFontRef;
@@ -31,17 +33,23 @@ class FontPlatformData;
class SharedBuffer;
struct FontCustomPlatformData : Noncopyable {
- FontCustomPlatformData(CGFontRef cgFont)
- : m_cgFont(cgFont)
- {}
+ 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);
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
CGFontRef m_cgFont;
+ HANDLE m_fontReference;
+ String m_name;
};
-FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
}
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/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h
index 15d23cd..d61afa8 100644
--- a/WebCore/platform/graphics/win/FontPlatformData.h
+++ b/WebCore/platform/graphics/win/FontPlatformData.h
@@ -2,7 +2,7 @@
* This file is part of the internal font implementation. It should not be included by anyone other than
* FontMac.cpp, FontWin.cpp and Font.cpp.
*
- * Copyright (C) 2006, 2007 Apple Inc.
+ * 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
@@ -25,45 +25,58 @@
#define FontPlatformData_H
#include "StringImpl.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/RefCounted.h>
-typedef struct HFONT__ *HFONT;
-typedef struct CGFont *CGFontRef;
+#if PLATFORM(CAIRO)
+#include <cairo-win32.h>
+#endif
+
+typedef struct HFONT__* HFONT;
+typedef struct CGFont* CGFontRef;
namespace WebCore {
class FontDescription;
-class FontPlatformData
-{
+class FontPlatformData {
public:
- class Deleted {};
-
- // Used for deleted values in the font cache's hash tables.
- FontPlatformData(Deleted)
- : m_font((HFONT)-1)
- , m_cgFont(NULL)
- , m_size(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
- , m_useGDI(false)
- {}
-
FontPlatformData()
- : m_font(0)
- , m_cgFont(NULL)
- , m_size(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
- , m_useGDI(false)
- {}
+#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);
- FontPlatformData(CGFontRef, 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();
- HFONT hfont() const { return m_font; }
- CGFontRef cgFont() const { return m_cgFont; }
+ 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; }
@@ -73,19 +86,55 @@ public:
unsigned hash() const
{
- return StringImpl::computeHash((UChar*)(&m_font), sizeof(HFONT) / sizeof(UChar));
+ return m_font->hash();
}
bool operator==(const FontPlatformData& other) const
{
- return m_font == other.m_font && m_cgFont ==other.m_cgFont && m_size == other.m_size &&
+ 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:
- HFONT m_font;
- CGFontRef m_cgFont;
+ 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;
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
index a5fab36..4b4df5a 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -2,7 +2,8 @@
* This file is part of the internal font implementation. It should not be included by anyone other than
* FontMac.cpp, FontWin.cpp and Font.cpp.
*
- * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 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
@@ -26,7 +27,6 @@
#include "PlatformString.h"
#include "StringHash.h"
-#include <ApplicationServices/ApplicationServices.h>
#include <wtf/HashMap.h>
#include <wtf/RetainPtr.h>
#include <wtf/Vector.h>
@@ -35,105 +35,17 @@ using std::min;
namespace WebCore {
-static const int Bold = (1 << 0);
-static const int Italic = (1 << 1);
-static const int BoldOblique = (1 << 2);
-
-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();
-}
-
-static int CALLBACK enumStylesCallback(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
-{
- int *style = reinterpret_cast<int*>(lParam);
-
- // FIXME: In order to accommodate Lucida we go ahead and consider a weight of 600 to be bold.
- // This does mean we'll consider demibold and semibold fonts on windows to also be bold. This
- // is rare enough that it seems like an ok hack for now.
- if (logFont->lfWeight >= 600) {
- if (logFont->lfItalic)
- *style |= BoldOblique;
- else
- *style |= Bold;
- } else if (logFont->lfItalic)
- *style |= Italic;
-
- return 1;
-}
-
FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
- : m_font(font)
+ : m_font(RefCountedHFONT::create(font))
, m_size(size)
+#if PLATFORM(CG)
, m_cgFont(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
, m_useGDI(useGDI)
{
HDC hdc = GetDC(0);
@@ -142,54 +54,16 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
SelectObject(hdc, font);
UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL);
- ASSERT_WITH_MESSAGE(bufferSize != 0, "Bitmap fonts not supported with CoreGraphics.");
+ ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics.");
- if (bufferSize != 0) {
+ if (bufferSize) {
OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize);
GetOutlineTextMetricsW(hdc, bufferSize, metrics);
WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName);
- if (!useGDI && (bold || oblique)) {
- LOGFONT logFont;
-
- int len = min((int)wcslen(faceName), LF_FACESIZE - 1);
- memcpy(logFont.lfFaceName, faceName, len * sizeof(WORD));
- logFont.lfFaceName[len] = '\0';
- logFont.lfCharSet = metrics->otmTextMetrics.tmCharSet;
- logFont.lfPitchAndFamily = 0;
-
- int styles = 0;
- EnumFontFamiliesEx(hdc, &logFont, enumStylesCallback, reinterpret_cast<LPARAM>(&styles), 0);
-
- // Check if we need to synthesize bold or oblique. The rule that complicates things here
- // is that if the requested font is bold and oblique, and both a bold font and an oblique font
- // exist, the bold font should be used, and oblique synthesized.
- if (bold && oblique) {
- if (styles == 0) {
- m_syntheticBold = true;
- m_syntheticOblique = true;
- } else if (styles & Bold)
- m_syntheticOblique = true;
- else if (styles & Italic)
- m_syntheticBold = true;
- } else if (bold && (!(styles & Bold)))
- m_syntheticBold = true;
- else if (oblique && !(styles & Italic))
- m_syntheticOblique = true;
- }
+ platformDataInit(font, size, hdc, 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 = CGFontCreateWithFontName(fullName.get());
- if (!m_cgFont) {
- CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc);
- if (postScriptName) {
- m_cgFont = CGFontCreateWithFontName(postScriptName);
- ASSERT(m_cgFont);
- }
- }
free(metrics);
}
@@ -198,19 +72,13 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
}
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
- : m_font(0)
- , m_size(size)
+ : m_size(size)
+#if PLATFORM(CG)
, m_cgFont(0)
- , m_syntheticBold(bold)
- , m_syntheticOblique(oblique)
- , m_useGDI(false)
-{
-}
-
-FontPlatformData::FontPlatformData(CGFontRef font, float size, bool bold, bool oblique)
- : m_font(0)
- , m_size(size)
- , m_cgFont(font)
+#elif PLATFORM(CAIRO)
+ , m_fontFace(0)
+ , m_scaledFont(0)
+#endif
, m_syntheticBold(bold)
, m_syntheticOblique(oblique)
, m_useGDI(false)
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
index 23b756c..c11fc1b 100644
--- a/WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp
+++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * 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
@@ -36,9 +36,9 @@ 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.
+ // 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 > GlyphPage::size)
+ if (bufferLength > length)
return false;
bool haveGlyphs = false;
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
index 58829b5..5a4279a 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -38,7 +38,7 @@ using namespace std;
namespace WebCore {
-static CGContextRef CGContextWithHDC(HDC hdc)
+static CGContextRef CGContextWithHDC(HDC hdc, bool hasAlpha)
{
HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
@@ -46,8 +46,10 @@ static CGContextRef CGContextWithHDC(HDC hdc)
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, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
+ info.bmWidthBytes, deviceRGB, bitmapInfo);
CGColorSpaceRelease(deviceRGB);
// Flip coords
@@ -60,9 +62,9 @@ static CGContextRef CGContextWithHDC(HDC hdc)
return context;
}
-GraphicsContext::GraphicsContext(HDC hdc)
+GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha)
: m_common(createGraphicsContextPrivate())
- , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc)))
+ , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha)))
{
CGContextRelease(m_data->m_cgContext);
m_data->m_hdc = hdc;
@@ -76,9 +78,12 @@ GraphicsContext::GraphicsContext(HDC hdc)
bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend)
+// 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)
{
- if (inTransparencyLayer()) {
+ // FIXME: Should a bitmap be created also when a shadow is set?
+ if (mayCreateBitmap && inTransparencyLayer()) {
if (dstRect.isEmpty())
return 0;
@@ -133,9 +138,9 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
return m_data->m_hdc;
}
-void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend)
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
{
- if (hdc && inTransparencyLayer()) {
+ if (mayCreateBitmap && hdc && inTransparencyLayer()) {
if (dstRect.isEmpty())
return;
@@ -168,75 +173,60 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
m_data->restore();
}
-void GraphicsContextPlatformPrivate::save()
+GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size)
+ : m_hdc(0)
+ , m_size(size)
{
- if (!m_hdc)
+ 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;
- SaveDC(m_hdc);
-}
-void GraphicsContextPlatformPrivate::restore()
-{
- if (!m_hdc)
- return;
- RestoreDC(m_hdc, -1);
-}
+ m_hdc = CreateCompatibleDC(hdc);
+ SelectObject(m_hdc, m_bitmap);
-void GraphicsContextPlatformPrivate::clip(const IntRect& clipRect)
-{
- if (!m_hdc)
- return;
- IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom());
-}
+ BITMAP bmpInfo;
+ GetObject(m_bitmap, sizeof(bmpInfo), &bmpInfo);
+ m_bytesPerRow = bmpInfo.bmWidthBytes;
+ m_bitmapBufferLength = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
-void GraphicsContextPlatformPrivate::clip(const Path&)
-{
- notImplemented();
+ SetGraphicsMode(m_hdc, GM_ADVANCED);
}
-void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
+GraphicsContext::WindowsBitmap::~WindowsBitmap()
{
- if (!m_hdc)
+ if (!m_bitmap)
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
+ DeleteDC(m_hdc);
+ DeleteObject(m_bitmap);
+}
-void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize size)
{
- 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);
+ return new WindowsBitmap(m_data->m_hdc, size);
}
-void GraphicsContextPlatformPrivate::translate(float x , float y)
+void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point)
{
- 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);
+ 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)
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index c3fbdd7..3dcf6ba 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -37,7 +37,7 @@ using namespace std;
namespace WebCore {
-GraphicsContext::GraphicsContext(HDC dc)
+GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha)
: m_common(createGraphicsContextPrivate())
, m_data(new GraphicsContextPlatformPrivate)
{
@@ -58,8 +58,13 @@ GraphicsContext::GraphicsContext(HDC dc)
}
}
-HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend)
+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);
@@ -77,36 +82,41 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha
xform.eM22 = mat.yy;
xform.eDx = mat.x0;
xform.eDy = mat.y0;
- SetWorldTransform(hdc, &xform);
+ ::SetWorldTransform(hdc, &xform);
return hdc;
}
bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; }
-void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend)
+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 GraphicsContext::concatCTM(const AffineTransform& transform)
+void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
{
- cairo_surface_t* surface = cairo_get_target(platformContext());
+ cairo_surface_t* surface = cairo_get_target(cr);
HDC hdc = cairo_win32_surface_get_dc(surface);
SaveDC(hdc);
- cairo_matrix_t mat;
- cairo_get_matrix(platformContext(), &mat);
+ const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
+
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;
+ 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
index a8f2148..dbf9fad 100644
--- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -26,6 +26,12 @@
#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"
@@ -37,6 +43,77 @@ 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*)
{
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
index 60cebe3..c02b56e 100644
--- a/WebCore/platform/graphics/win/IconWin.cpp
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (C) 2006, 2007 Apple Inc.
+* 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
@@ -23,27 +23,25 @@
#include "GraphicsContext.h"
#include "PlatformString.h"
+#include <tchar.h>
#include <windows.h>
namespace WebCore {
-Icon::Icon()
- : m_hIcon(0)
-{
-}
+static const int shell32MultipleFileIconIndex = 54;
Icon::Icon(HICON icon)
: m_hIcon(icon)
{
+ ASSERT(icon);
}
Icon::~Icon()
{
- if (m_hIcon)
- DestroyIcon(m_hIcon);
+ DestroyIcon(m_hIcon);
}
-PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
+PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
@@ -52,9 +50,23 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON))
return 0;
- Icon* icon = new Icon();
- icon->m_hIcon = sfi.hIcon;
- return icon;
+ 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)
diff --git a/WebCore/platform/graphics/win/ImageWin.cpp b/WebCore/platform/graphics/win/ImageWin.cpp
index 2d3a87a..54c5b41 100644
--- a/WebCore/platform/graphics/win/ImageWin.cpp
+++ b/WebCore/platform/graphics/win/ImageWin.cpp
@@ -42,12 +42,12 @@ void BitmapImage::invalidatePlatformData()
{
}
-Image* Image::loadPlatformResource(const char *name)
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
{
RefPtr<SharedBuffer> buffer = loadResourceIntoBuffer(name);
- BitmapImage* img = new BitmapImage;
+ RefPtr<BitmapImage> img = BitmapImage::create();
img->setData(buffer.release(), true);
- return img;
+ return img.release();
}
bool BitmapImage::getHBITMAP(HBITMAP bmp)
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index 65b3db6..cef4217 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -28,13 +28,22 @@
#if ENABLE(VIDEO)
#include "MediaPlayerPrivateQuickTimeWin.h"
-#include "DeprecatedString.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 {
@@ -51,6 +60,11 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_readyState(MediaPlayer::DataUnavailable)
, m_startedPlaying(false)
, m_isStreaming(false)
+#if DRAW_FRAME_RATE
+ , m_frameCountWhilePlaying(0)
+ , m_timeStartedPlaying(0)
+ , m_timeStoppedPlaying(0)
+#endif
{
}
@@ -88,6 +102,9 @@ void MediaPlayerPrivate::play()
if (!m_qtMovie)
return;
m_startedPlaying = true;
+#if DRAW_FRAME_RATE
+ m_frameCountWhilePlaying = 0;
+#endif
m_qtMovie->play();
startEndPointTimerIfNeeded();
@@ -98,6 +115,9 @@ void MediaPlayerPrivate::pause()
if (!m_qtMovie)
return;
m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
m_qtMovie->pause();
m_endPointTimer.stop();
}
@@ -304,7 +324,7 @@ void MediaPlayerPrivate::updateStates()
long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError;
- if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData) {
+ 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>
@@ -352,6 +372,9 @@ void MediaPlayerPrivate::didEnd()
{
m_endPointTimer.stop();
m_startedPlaying = false;
+#if DRAW_FRAME_RATE
+ m_timeStoppedPlaying = GetTickCount();
+#endif
updateStates();
m_player->timeChanged();
}
@@ -376,6 +399,31 @@ void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r)
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)
@@ -417,6 +465,15 @@ void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie)
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();
}
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index 37b5b05..c4c893c 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -33,6 +33,10 @@
#include <QTMovieWin.h>
#include <wtf/OwnPtr.h>
+#ifndef DRAW_FRAME_RATE
+#define DRAW_FRAME_RATE 0
+#endif
+
namespace WebCore {
class GraphicsContext;
@@ -111,6 +115,11 @@ private:
MediaPlayer::ReadyState m_readyState;
bool m_startedPlaying;
bool m_isStreaming;
+#if DRAW_FRAME_RATE
+ int m_frameCountWhilePlaying;
+ int m_timeStartedPlaying;
+ int m_timeStoppedPlaying;
+#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
index 80c6d50..8eee41b 100644
--- a/WebCore/platform/graphics/win/QTMovieWin.cpp
+++ b/WebCore/platform/graphics/win/QTMovieWin.cpp
@@ -30,6 +30,7 @@
// Put Movies.h first so build failures here point clearly to QuickTime
#include <Movies.h>
+#include <QuickTimeComponents.h>
#include <GXMath.h>
#include <QTML.h>
@@ -59,6 +60,7 @@ union UppParam {
static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0;
static HashSet<QTMovieWinPrivate*>* gTaskList;
static Vector<CFStringRef>* gSupportedTypes = 0;
+static SInt32 quickTimeVersion = 0;
static void updateTaskTimer(int maxInterval = 1000)
{
@@ -82,16 +84,19 @@ public:
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;
@@ -112,6 +117,7 @@ public:
QTMovieWinPrivate::QTMovieWinPrivate()
: m_movieWin(0)
, m_movie(0)
+ , m_movieController(0)
, m_tasking(false)
, m_client(0)
, m_loadState(0)
@@ -135,6 +141,8 @@ QTMovieWinPrivate::~QTMovieWinPrivate()
endTask();
if (m_gWorld)
deleteGWorld();
+ if (m_movieController)
+ DisposeMovieController(m_movieController);
if (m_movie)
DisposeMovie(m_movie);
}
@@ -175,8 +183,12 @@ void QTMovieWinPrivate::task()
{
ASSERT(m_tasking);
- if (!m_loadError)
- MoviesTask(m_movie, 0);
+ 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) {
@@ -184,7 +196,15 @@ void QTMovieWinPrivate::task()
// 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();
@@ -209,6 +229,27 @@ void QTMovieWinPrivate::task()
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;
@@ -218,7 +259,7 @@ void QTMovieWinPrivate::registerDrawingCallback()
void QTMovieWinPrivate::drawingComplete()
{
- if (!m_gWorld)
+ if (!m_gWorld || m_loadState < kMovieLoadStateLoaded)
return;
m_client->movieNewImageAvailable(m_movieWin);
}
@@ -257,12 +298,36 @@ void QTMovieWinPrivate::createGWorld()
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)
@@ -276,6 +341,8 @@ void QTMovieWinPrivate::setSize(int width, int height)
bounds.left = 0;
bounds.right = width;
bounds.bottom = height;
+ if (m_movieController)
+ MCSetControllerBoundsRect(m_movieController, &bounds);
SetMovieBox(m_movie, &bounds);
updateGWorld();
}
@@ -283,6 +350,8 @@ void QTMovieWinPrivate::setSize(int width, int height)
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;
@@ -308,24 +377,37 @@ QTMovieWin::~QTMovieWin()
void QTMovieWin::play()
{
- StartMovie(m_private->m_movie);
+ 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()
{
- StopMovie(m_private->m_movie);
+ 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)
{
- SetMovieRate(m_private->m_movie, FloatToFixed(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();
}
@@ -353,19 +435,26 @@ void QTMovieWin::setCurrentTime(float time) const
return;
m_private->m_seeking = true;
TimeScale scale = GetMovieTimeScale(m_private->m_movie);
- SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale));
+ 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
{
- // FIXME: How to get this?
- return 1000;
+ if (!m_private->m_movie)
+ return 0;
+ return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));
}
float QTMovieWin::maxTimeLoaded() const
@@ -385,8 +474,10 @@ long QTMovieWin::loadState() const
void QTMovieWin::getNaturalSize(int& width, int& height)
{
- Rect rect;
- GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
+ Rect rect = { 0, };
+
+ if (m_private->m_movie)
+ GetMovieNaturalBoundsRect(m_private->m_movie, &rect);
width = rect.right;
height = rect.bottom;
}
@@ -428,6 +519,9 @@ void QTMovieWin::load(const UChar* url, int len)
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;
}
@@ -630,18 +724,89 @@ static void initializeSupportedTypes()
{
if (gSupportedTypes)
return;
- // FIXME: This list might not be complete.
- // There must be some way to get it out from QuickTime.
+
gSupportedTypes = new Vector<CFStringRef>;
- gSupportedTypes->append(CFSTR("video/3gpp"));
- gSupportedTypes->append(CFSTR("video/3gpp2"));
- gSupportedTypes->append(CFSTR("video/mp4"));
- gSupportedTypes->append(CFSTR("video/mpeg"));
+ 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"));
- gSupportedTypes->append(CFSTR("audio/ac3"));
- gSupportedTypes->append(CFSTR("audio/aiff"));
- gSupportedTypes->append(CFSTR("audio/basic"));
- gSupportedTypes->append(CFSTR("audio/mpeg"));
+
+ 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()
@@ -676,15 +841,14 @@ bool QTMovieWin::initializeQuickTime()
initialized = true;
// Initialize and check QuickTime version
OSErr result = InitializeQTML(0);
- SInt32 version = 0;
if (result == noErr)
- result = Gestalt(gestaltQuickTime, &version);
+ result = Gestalt(gestaltQuickTime, &quickTimeVersion);
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);
+ if (quickTimeVersion < minimumQuickTimeVersion) {
+ LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", quickTimeVersion, minimumQuickTimeVersion);
return false;
}
EnterMovies();
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
index 0c31672..8b5ab87 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -34,7 +34,9 @@
#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>
@@ -54,32 +56,9 @@ void SimpleFontData::platformInit()
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_isSystemFont = false;
-
- if (m_font.useGDI()) {
- 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;
- }
+
+ if (m_font.useGDI())
+ return initGDIFont();
CGFontRef font = m_font.cgFont();
int iAscent = CGFontGetAscent(font);
@@ -139,29 +118,13 @@ void SimpleFontData::platformInit()
void SimpleFontData::platformDestroy()
{
- if (!isCustomFont()) {
- DeleteObject(m_font.hfont());
- CGFontRelease(m_font.cgFont());
- }
-
- // We don't hash this on Win32, so it's effectively owned by us.
- delete m_smallCapsFontData;
-
- ScriptFreeCache(&m_scriptCache);
- delete m_scriptFontProperties;
+ platformCommonDestroy();
}
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
- if (m_font.useGDI()) {
- 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;
- }
+ if (m_font.useGDI())
+ return widthForGDIGlyph(glyph);
CGFontRef font = m_font.cgFont();
float pointSize = m_font.size();
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
index e7b2c81..07d5305 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -34,7 +34,10 @@
#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>
@@ -45,58 +48,84 @@ void SimpleFontData::platformInit()
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_isSystemFont = false;
-
- if (m_font.useGDI()) {
- 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.
+ 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;
-
- m_unitsPerEm = metrics.otmEMSquare;
+ m_xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier;
+ }
- SelectObject(hdc, oldFont);
- ReleaseDC(0, hdc);
+ cairo_win32_scaled_font_done_font(scaledFont);
- return;
- }
+ m_isSystemFont = false;
+ m_scriptCache = 0;
+ m_scriptFontProperties = 0;
- // FIXME: This section should determine font dimensions (see CG implementation).
- notImplemented();
+ RestoreDC(hdc, -1);
+ ReleaseDC(0, hdc);
}
void SimpleFontData::platformDestroy()
{
- notImplemented();
+ 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()) {
- 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;
- }
+ 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);
- // FIXME: Flesh out with Cairo/win32 font implementation
- notImplemented();
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
- return 0;
+ 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
index 344d964..0e9f9fb 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -60,6 +60,42 @@ 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) {
@@ -73,7 +109,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes
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, fontDescription.bold(), fontDescription.italic(), m_font.useGDI()));
+ m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, m_font.syntheticBold(), m_font.syntheticOblique(), m_font.useGDI()));
}
}
return m_smallCapsFontData;
@@ -137,6 +173,17 @@ void SimpleFontData::determinePitch()
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) {
diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp
index 876ff43..371bc51 100644
--- a/WebCore/platform/graphics/win/UniscribeController.cpp
+++ b/WebCore/platform/graphics/win/UniscribeController.cpp
@@ -299,7 +299,9 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S
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
@@ -361,7 +363,7 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const S
// as well, so that when the time comes to draw those glyphs, we can apply the appropriate
// translation.
if (glyphBuffer) {
- FloatSize size(offsetX, offsetY);
+ FloatSize size(offsetX, -offsetY);
glyphBuffer->add(glyph, fontData, advance, &size);
}
@@ -422,25 +424,9 @@ bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, con
if (FAILED(shapeResult))
return false;
-
- // FIXME: We need to do better than this. Falling back on the entire item is not good enough.
- // We may still have missing glyphs even if we succeeded. We need to treat missing glyphs as
- // a failure so that we will fall back to another font.
- bool containsMissingGlyphs = false;
- SCRIPT_FONTPROPERTIES* fontProperties = fontData->scriptFontProperties();
- for (int i = 0; i < glyphCount; i++) {
- WORD glyph = glyphs[i];
- if (glyph == fontProperties->wgDefault) {
- containsMissingGlyphs = true;
- break;
- }
- }
-
- if (containsMissingGlyphs)
- return false;
- glyphs.resize(glyphCount);
- visualAttributes.resize(glyphCount);
+ glyphs.shrink(glyphCount);
+ visualAttributes.shrink(glyphCount);
return true;
}
diff --git a/WebCore/platform/graphics/wx/AffineTransformWx.cpp b/WebCore/platform/graphics/wx/AffineTransformWx.cpp
index b9c504d..12485ae 100644
--- a/WebCore/platform/graphics/wx/AffineTransformWx.cpp
+++ b/WebCore/platform/graphics/wx/AffineTransformWx.cpp
@@ -37,7 +37,7 @@
namespace WebCore {
#if USE(WXGC)
-AffineTransform::AffineTransform(const wxGraphicsMatrix &matrix)
+AffineTransform::AffineTransform(const PlatformAffineTransform& matrix)
{
m_transform = matrix;
}
@@ -48,8 +48,8 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double
#if USE(WXGC)
wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer();
m_transform = renderer->CreateMatrix();
- m_transform.Set(a, b, c, d, e, f);
#endif
+ setMatrix(a, b, c, d, e, f);
}
AffineTransform::AffineTransform()
@@ -69,6 +69,13 @@ AffineTransform AffineTransform::inverse() const
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();
@@ -132,6 +139,9 @@ bool AffineTransform::operator== (const AffineTransform &other) const
{
#if USE(WXGC)
return m_transform.IsEqual((wxGraphicsMatrix)other);
+#else
+ notImplemented();
+ return true;
#endif
}
@@ -154,4 +164,88 @@ AffineTransform::operator wxGraphicsMatrix() const
}
#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/FontCacheWx.cpp b/WebCore/platform/graphics/wx/FontCacheWx.cpp
index eb41c89..db107e4 100755
--- a/WebCore/platform/graphics/wx/FontCacheWx.cpp
+++ b/WebCore/platform/graphics/wx/FontCacheWx.cpp
@@ -64,10 +64,9 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
return new FontPlatformData(fontDescription,family);
}
-bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
{
notImplemented();
- return true;
}
}
diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h
index f48068b..e3a3cce 100644
--- a/WebCore/platform/graphics/wx/FontPlatformData.h
+++ b/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -41,11 +41,9 @@ namespace WebCore {
class FontPlatformData {
public:
- class Deleted {};
-
enum FontState { UNINITIALIZED, DELETED, VALID };
- FontPlatformData(Deleted)
+ FontPlatformData(WTF::HashTableDeletedValueType)
: m_fontState(DELETED)
{ }
@@ -76,7 +74,7 @@ public:
case UNINITIALIZED:
return 0;
case VALID:
- return m_fontHash;
+ return computeHash();
}
}
@@ -87,11 +85,19 @@ public:
else
return m_fontState == other.m_fontState;
}
+
+ bool isHashTableDeletedValue() const { return m_fontState == DELETED; }
unsigned computeHash() const {
- wxCharBuffer charBuffer(m_font.GetNativeFontInfoDesc().mb_str(wxConvUTF8));
- const char* contents = charBuffer;
- return StringImpl::computeHash( (UChar*)contents, strlen(contents));
+ 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:
diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
index f3fb480..7162eab 100755
--- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
+++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
@@ -54,9 +54,9 @@ static wxFontFamily fontFamilyToWxFontFamily(const int family)
}
}
-static wxFontWeight fontWeightToWxFontWeight(bool isBold)
+static wxFontWeight fontWeightToWxFontWeight(FontWeight weight)
{
- if (isBold)
+ if (weight >= FontWeight600)
return wxFONTWEIGHT_BOLD;
return wxFONTWEIGHT_NORMAL;
@@ -81,17 +81,17 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri
m_font = wxFont( wxSize(0, -desc.computedPixelSize()),
fontFamilyToWxFontFamily(desc.genericFamily()),
italicToWxFontStyle(desc.italic()),
- fontWeightToWxFontWeight(desc.bold()),
+ fontWeightToWxFontWeight(desc.weight()),
false,
- family.domString()
+ family.string()
);
#else
m_font = wxFont( desc.computedPixelSize(),
fontFamilyToWxFontFamily(desc.genericFamily()),
italicToWxFontStyle(desc.italic()),
- fontWeightToWxFontWeight(desc.bold()),
+ fontWeightToWxFontWeight(desc.weight()),
false,
- family.domString()
+ family.string()
);
#endif
m_fontState = VALID;
diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp
index e94ae3b..07223e9 100644
--- a/WebCore/platform/graphics/wx/FontWx.cpp
+++ b/WebCore/platform/graphics/wx/FontWx.cpp
@@ -33,9 +33,9 @@
#include "NotImplemented.h"
#include "SimpleFontData.h"
-#include "fontprops.h"
-#include <wx/defs.h>
#include <wx/dcclient.h>
+#include "fontprops.h"
+#include "non-kerned-drawing.h"
namespace WebCore {
@@ -45,33 +45,11 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
// prepare DC
Color color = graphicsContext->fillColor();
-#if USE(WXGC)
- wxGCDC* dc = (wxGCDC*)graphicsContext->platformContext();
- wxFont wxfont = font->getWxFont();
- if (wxfont.IsOk())
- dc->SetFont(wxfont);
- dc->SetTextForeground(color);
-#else
- wxDC* dc = graphicsContext->platformContext();
- dc->SetTextBackground(color);
- dc->SetTextForeground(color);
- dc->SetFont(font->getWxFont());
-#endif
-
- // convert glyphs to wxString
- GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
- int offset = point.x();
- wxString text = wxEmptyString;
- for (unsigned i = 0; i < numGlyphs; i++) {
- text = text.Append((wxChar)glyphs[i]);
- offset += glyphBuffer.advanceAt(from + i);
- }
-
- // the y point is actually the bottom point of the text, turn it into the top
- float height = font->ascent() - font->descent();
- wxCoord ypoint = (wxCoord) (point.y() - height);
-
- dc->DrawText(text, (wxCoord)point.x(), ypoint);
+ // 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
diff --git a/WebCore/platform/graphics/win/FontCairoWin.cpp b/WebCore/platform/graphics/wx/GradientWx.cpp
index 302e79d..fc4661e 100644
--- a/WebCore/platform/graphics/win/FontCairoWin.cpp
+++ b/WebCore/platform/graphics/wx/GradientWx.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * 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
@@ -24,19 +24,27 @@
*/
#include "config.h"
-#include "Font.h"
+#include "Gradient.h"
-#include "GlyphBuffer.h"
-#include "GraphicsContext.h"
+#include "CSSParser.h"
#include "NotImplemented.h"
-#include "SimpleFontData.h"
namespace WebCore {
-void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
- int from, int numGlyphs, const FloatPoint& point) const
+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
index 78149ad..435e7ce 100644
--- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -252,22 +252,12 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points
delete [] polygon;
}
-void GraphicsContext::fillRect(const IntRect& 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::fillRect(const FloatRect& rect, const Color& color)
{
if (paintingDisabled())
return;
- m_data->context->SetPen(wxPen(color));
+ m_data->context->SetPen(*wxTRANSPARENT_PEN);
m_data->context->SetBrush(wxBrush(color));
m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height());
}
@@ -288,7 +278,7 @@ void GraphicsContext::drawFocusRing(const Color& color)
notImplemented();
}
-void GraphicsContext::clip(const IntRect& r)
+void GraphicsContext::clip(const FloatRect& r)
{
wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context);
wxPoint pos(0, 0);
@@ -334,7 +324,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr
return;
IntPoint endPoint = origin + IntSize(width, 0);
- m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle())));
+ m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), wxSOLID));
m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y());
}
@@ -354,6 +344,11 @@ void GraphicsContext::clip(const Path&)
notImplemented();
}
+void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
+{
+ notImplemented();
+}
+
AffineTransform GraphicsContext::getCTM() const
{
notImplemented();
@@ -422,6 +417,16 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op)
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())
@@ -466,4 +471,33 @@ void GraphicsContext::setUseAntialiasing(bool enable)
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
index bc54a88..ea3dfe8 100644
--- a/WebCore/platform/graphics/wx/ImageBufferWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp
@@ -25,13 +25,22 @@
#include "config.h"
#include "ImageBuffer.h"
+
#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "NotImplemented.h"
namespace WebCore {
-std::auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize&, bool grayScale)
+ImageBufferData::ImageBufferData(const IntSize&)
{
- return std::auto_ptr<ImageBuffer>(new ImageBuffer());
+}
+
+ImageBuffer::ImageBuffer(const IntSize&, bool grayScale, bool& success) :
+ m_data(IntSize())
+{
+ notImplemented();
+ success = false;
}
ImageBuffer::~ImageBuffer()
@@ -40,7 +49,31 @@ 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
index fc36635..3ce4f2a 100644
--- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp
@@ -128,6 +128,11 @@ IntSize ImageSource::size() const
return m_decoder->size();
}
+IntSize ImageSource::frameSizeAtIndex(size_t) const
+{
+ return size();
+}
+
int ImageSource::repetitionCount()
{
if (!m_decoder)
@@ -215,7 +220,13 @@ float ImageSource::frameDurationAtIndex(size_t index)
if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty)
return 0;
- return buffer->duration() / 1000.0f;
+ 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)
diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp
index 785466c..a05a31f 100644
--- a/WebCore/platform/graphics/wx/ImageWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageWx.cpp
@@ -57,8 +57,9 @@ void FrameData::clear()
if (m_frame) {
delete m_frame;
m_frame = 0;
- m_duration = 0.;
- m_hasAlpha = true;
+ // 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.
}
}
@@ -66,13 +67,13 @@ void FrameData::clear()
// Image Class
// ================================================
-Image* Image::loadPlatformResource(const char *name)
+PassRefPtr<Image> Image::loadPlatformResource(const char *name)
{
Vector<char> arr = loadResourceIntoArray(name);
- Image* img = new BitmapImage();
- RefPtr<SharedBuffer> buffer = new SharedBuffer(arr.data(), arr.size());
+ RefPtr<Image> img = BitmapImage::create();
+ RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size());
img->setData(buffer, true);
- return img;
+ return img.release();
}
void BitmapImage::initPlatformData()
@@ -87,30 +88,49 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR
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;
-
- IntSize selfSize = size();
- FloatRect srcRect(src);
- FloatRect dstRect(dst);
// 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)dst.x(),(wxCoord)dst.y(), (wxCoord)dst.width(), (wxCoord)dst.height(), &mydc,
- (wxCoord)src.x(), (wxCoord)src.y(), wxCOPY, true);
+
+ 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
@@ -118,10 +138,14 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR
// suddenly becomes invalid after returning. It's possible these errors deal
// with reentrancy and threding problems.
//delete bitmap;
- startAnimation();
+ 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())
diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp
index 86ecb93..5ff9914 100644
--- a/WebCore/platform/graphics/wx/PathWx.cpp
+++ b/WebCore/platform/graphics/wx/PathWx.cpp
@@ -171,4 +171,10 @@ void Path::apply(void* info, PathApplierFunction function) const
notImplemented();
}
+bool Path::isEmpty() const
+{
+ notImplemented();
+ return false;
+}
+
}