diff options
author | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
---|---|---|
committer | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
commit | d8543bb6618c17b12da906afa77d216f58cf4058 (patch) | |
tree | c58dc05ed86825bd0ef8d305d58c8205106b540f /WebCore/platform/graphics | |
download | external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.zip external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.gz external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.bz2 |
external/webkit r30707
Diffstat (limited to 'WebCore/platform/graphics')
201 files changed, 30986 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/AffineTransform.cpp b/WebCore/platform/graphics/AffineTransform.cpp new file mode 100644 index 0000000..664bf28 --- /dev/null +++ b/WebCore/platform/graphics/AffineTransform.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AffineTransform.h" + +#include "FloatRect.h" +#include "IntRect.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +bool AffineTransform::isInvertible() const +{ + return det() != 0.0; +} + +AffineTransform& AffineTransform::multiply(const AffineTransform& other) +{ + return (*this) *= other; +} + +AffineTransform& AffineTransform::scale(double s) +{ + return scale(s, s); +} + +AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy) +{ + return scale(sx, sy); +} + +AffineTransform& AffineTransform::rotateFromVector(double x, double y) +{ + return rotate(rad2deg(atan2(y, x))); +} + +AffineTransform& AffineTransform::flipX() +{ + return scale(-1.0f, 1.0f); +} + +AffineTransform& AffineTransform::flipY() +{ + return scale(1.0f, -1.0f); +} + +AffineTransform& AffineTransform::skew(double angleX, double angleY) +{ + return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY))); +} + +AffineTransform& AffineTransform::skewX(double angle) +{ + return shear(tan(deg2rad(angle)), 0.0f); +} + +AffineTransform& AffineTransform::skewY(double angle) +{ + return shear(0.0f, tan(deg2rad(angle))); +} + +IntPoint AffineTransform::mapPoint(const IntPoint& point) const +{ + double x2, y2; + map(point.x(), point.y(), &x2, &y2); + + // Round the point. + return IntPoint(lround(x2), lround(y2)); +} + +FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const +{ + double x2, y2; + map(point.x(), point.y(), &x2, &y2); + + return FloatPoint(static_cast<float>(x2), static_cast<float>(y2)); +} + +} diff --git a/WebCore/platform/graphics/AffineTransform.h b/WebCore/platform/graphics/AffineTransform.h new file mode 100644 index 0000000..2ba4ce7 --- /dev/null +++ b/WebCore/platform/graphics/AffineTransform.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AffineTransform_h +#define AffineTransform_h + +#if PLATFORM(CG) +#include <CoreGraphics/CGAffineTransform.h> +#elif PLATFORM(QT) +#include <QMatrix> +#elif PLATFORM(CAIRO) +#include <cairo.h> +#elif PLATFORM(WX) && USE(WXGC) +#include <wx/defs.h> +#include <wx/graphics.h> +#endif + +namespace WebCore { + +class IntPoint; +class IntRect; +class FloatPoint; +class FloatRect; + +class AffineTransform { +public: + AffineTransform(); + AffineTransform(double a, double b, double c, double d, double e, double f); +#if PLATFORM(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); +#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; + IntPoint mapPoint(const IntPoint&) const; + FloatPoint mapPoint(const FloatPoint&) const; + IntRect mapRect(const IntRect&) const; + FloatRect mapRect(const FloatRect&) const; + + bool isIdentity() const; + + double a() const; + void setA(double a); + + double b() const; + void setB(double b); + + double c() const; + void setC(double c); + + double d() const; + void setD(double d); + + double e() const; + void setE(double e); + + double f() const; + void setF(double f); + + void reset(); + + AffineTransform& multiply(const AffineTransform&); + AffineTransform& scale(double); + AffineTransform& scale(double sx, double sy); + AffineTransform& scaleNonUniform(double sx, double sy); + AffineTransform& rotate(double d); + AffineTransform& rotateFromVector(double x, double y); + AffineTransform& translate(double tx, double ty); + AffineTransform& shear(double sx, double sy); + AffineTransform& flipX(); + AffineTransform& flipY(); + AffineTransform& skew(double angleX, double angleY); + AffineTransform& skewX(double angle); + AffineTransform& skewY(double angle); + + double det() const; + bool isInvertible() const; + AffineTransform inverse() const; + +#if PLATFORM(CG) + operator CGAffineTransform() const; +#elif PLATFORM(QT) + operator QMatrix() const; +#elif PLATFORM(CAIRO) + operator cairo_matrix_t() const; +#elif PLATFORM(WX) && USE(WXGC) + operator wxGraphicsMatrix() const; +#endif + + bool operator==(const AffineTransform&) const; + bool operator!=(const AffineTransform& other) const { return !(*this == other); } + AffineTransform& operator*=(const AffineTransform&); + AffineTransform operator*(const AffineTransform&); + +private: +#if PLATFORM(CG) + CGAffineTransform m_transform; +#elif PLATFORM(QT) + QMatrix m_transform; +#elif PLATFORM(CAIRO) + cairo_matrix_t m_transform; +#elif PLATFORM(WX) && USE(WXGC) + wxGraphicsMatrix m_transform; +#endif +}; + +} // namespace WebCore + +#endif // AffineTransform_h diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp new file mode 100644 index 0000000..9ef1d6a --- /dev/null +++ b/WebCore/platform/graphics/BitmapImage.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) + * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BitmapImage.h" + +#include "FloatRect.h" +#include "ImageObserver.h" +#include "IntRect.h" +#include "PlatformString.h" +#include "Timer.h" +#include <wtf/Vector.h> +#include "MIMETypeRegistry.h" + +namespace WebCore { + +// Animated images >5MB are considered large enough that we'll only hang on to +// one frame at a time. +const unsigned cLargeAnimationCutoff = 5242880; + +BitmapImage::BitmapImage(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) +{ + initPlatformData(); +} + +BitmapImage::~BitmapImage() +{ + invalidatePlatformData(); + stopAnimation(); +} + +void BitmapImage::destroyDecodedData(bool incremental) +{ + // Destroy the cached images and release them. + if (m_frames.size()) { + int sizeChange = 0; + int frameSize = m_size.width() * m_size.height() * 4; + for (unsigned i = incremental ? m_frames.size() - 1 : 0; i < m_frames.size(); i++) { + if (m_frames[i].m_frame) { + sizeChange -= frameSize; + m_frames[i].clear(); + } + } + + // We just always invalidate our platform data, even in the incremental case. + // This could be better, but it's not a big deal. + m_isSolidColor = false; + invalidatePlatformData(); + + if (sizeChange) { + m_decodedSize += sizeChange; + if (imageObserver()) + imageObserver()->decodedSizeChanged(this, sizeChange); + } + + if (!incremental) { + // Reset the image source, since Image I/O has an underlying cache that it uses + // while animating that it seems to never clear. + m_source.clear(); + m_source.setData(m_data.get(), m_allDataReceived); + } + } +} + +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); + + m_frames[index].m_frame = m_source.createFrameAtIndex(index); + if (numFrames == 1 && m_frames[index].m_frame) + checkForSolidColor(); + + if (shouldAnimate()) + 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; + if (sizeChange) { + m_decodedSize += sizeChange; + if (imageObserver()) + imageObserver()->decodedSizeChanged(this, sizeChange); + } +} + +IntSize BitmapImage::size() const +{ + if (m_sizeAvailable && !m_haveSize) { + m_size = m_source.size(); + m_haveSize = true; + } + return m_size; +} + +bool BitmapImage::dataChanged(bool allDataReceived) +{ + destroyDecodedData(true); + + // Feed all the data we've seen so far to the image decoder. + m_allDataReceived = allDataReceived; + m_source.setData(m_data.get(), allDataReceived); + + // Image properties will not be available until the first frame of the file + // reaches kCGImageStatusIncomplete. + return isSizeAvailable(); +} + +size_t BitmapImage::frameCount() +{ + return m_source.frameCount(); +} + +bool BitmapImage::isSizeAvailable() +{ + if (m_sizeAvailable) + return true; + + m_sizeAvailable = m_source.isSizeAvailable(); + + return m_sizeAvailable; +} + +NativeImagePtr BitmapImage::frameAtIndex(size_t index) +{ + if (index >= frameCount()) + return 0; + + if (index >= m_frames.size() || !m_frames[index].m_frame) + cacheFrame(index); + + return m_frames[index].m_frame; +} + +float BitmapImage::frameDurationAtIndex(size_t index) +{ + if (index >= frameCount()) + return 0; + + if (index >= m_frames.size() || !m_frames[index].m_frame) + cacheFrame(index); + + return m_frames[index].m_duration; +} + +bool BitmapImage::frameHasAlphaAtIndex(size_t index) +{ + if (index >= frameCount()) + return 0; + + if (index >= m_frames.size() || !m_frames[index].m_frame) + cacheFrame(index); + + return m_frames[index].m_hasAlpha; +} + +bool BitmapImage::shouldAnimate() +{ + return (m_animatingImageType && !m_animationFinished && imageObserver()); +} + +void BitmapImage::startAnimation() +{ + 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)) + return; + + m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation); + m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame)); +} + +void BitmapImage::stopAnimation() +{ + // This timer is used to animate all occurrences of this image. Don't invalidate + // the timer unless all renderers have stopped drawing. + delete m_frameTimer; + m_frameTimer = 0; +} + +void BitmapImage::resetAnimation() +{ + stopAnimation(); + m_currentFrame = 0; + m_repetitionsComplete = 0; + m_animationFinished = false; + int frameSize = m_size.width() * m_size.height() * 4; + + // For extremely large animations, when the animation is reset, we just throw everything away. + if (frameCount() * frameSize > cLargeAnimationCutoff) + destroyDecodedData(); +} + +void BitmapImage::advanceAnimation(Timer<BitmapImage>* timer) +{ + // 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; + + m_currentFrame++; + if (m_currentFrame >= frameCount()) { + m_repetitionsComplete += 1; + if (m_repetitionCount && m_repetitionsComplete >= m_repetitionCount) { + m_animationFinished = true; + m_currentFrame--; + return; + } + m_currentFrame = 0; + } + + // Notify our observer that the animation has advanced. + imageObserver()->animationAdvanced(this); + + // For large animated images, go ahead and throw away frames as we go to save + // footprint. + int frameSize = m_size.width() * m_size.height() * 4; + if (frameCount() * frameSize > cLargeAnimationCutoff) { + // Destroy all of our frames and just redecode every time. + destroyDecodedData(); + + // Go ahead and decode the next frame. + frameAtIndex(m_currentFrame); + } + + // 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 new file mode 100644 index 0000000..0185027 --- /dev/null +++ b/WebCore/platform/graphics/BitmapImage.h @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BitmapImage_h +#define BitmapImage_h + +#include "Image.h" +#include "Color.h" +#include "IntSize.h" + +#if PLATFORM(MAC) +#include <wtf/RetainPtr.h> +#ifdef __OBJC__ +@class NSImage; +#else +class NSImage; +#endif +#endif + +#if PLATFORM(WIN) +typedef struct HBITMAP__ *HBITMAP; +#endif + +namespace WebCore { + struct FrameData; +} + +// This complicated-looking declaration tells the FrameData Vector that it should copy without +// invoking our constructor or destructor. This allows us to have a vector even for a struct +// that's not copyable. +namespace WTF { + template<> class VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits {}; +} + +namespace WebCore { + +template <typename T> class Timer; + +// ================================================ +// FrameData Class +// ================================================ + +struct FrameData : Noncopyable { + FrameData() + : m_frame(0) + , m_duration(0) + , m_hasAlpha(true) + { + } + + ~FrameData() + { + clear(); + } + + void clear(); + + NativeImagePtr m_frame; + float m_duration; + bool m_hasAlpha; +}; + +// ================================================= +// BitmapImage Class +// ================================================= + +class BitmapImage : public Image { + friend class GraphicsContext; +public: +#if PLATFORM(QT) + BitmapImage(const QPixmap &pixmap, ImageObserver* = 0); +#endif + BitmapImage(ImageObserver* = 0); + ~BitmapImage(); + + virtual IntSize size() const; + + virtual bool dataChanged(bool allDataReceived); + + // It may look unusual that there is no start animation call as public API. This is because + // we start and stop animating lazily. Animation begins whenever someone draws the image. It will + // automatically pause once all observers no longer want to render the image anywhere. + virtual void stopAnimation(); + virtual void resetAnimation(); + + virtual unsigned decodedSize() const { return m_decodedSize; } + +#if PLATFORM(MAC) + // Accessors for native image formats. + virtual NSImage* getNSImage(); + virtual CFDataRef getTIFFRepresentation(); +#endif + +#if PLATFORM(CG) + virtual CGImageRef getCGImageRef(); +#endif + +#if PLATFORM(QT) + virtual QPixmap* getPixmap() const; +#endif + +#if PLATFORM(WIN) + virtual bool getHBITMAP(HBITMAP); + virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE); +#endif + + virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); } + +private: +#if PLATFORM(WIN) + virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator); +#endif + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); +#if PLATFORM(QT) || PLATFORM(WX) + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); +#endif + size_t currentFrame() const { return m_currentFrame; } + size_t frameCount(); + NativeImagePtr frameAtIndex(size_t); + 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); + + // Whether or not size is available yet. + bool isSizeAvailable(); + + // Animation. + bool shouldAnimate(); + virtual void startAnimation(); + void advanceAnimation(Timer<BitmapImage>*); + + // Handle platform-specific data + void initPlatformData(); + void invalidatePlatformData(); + + // Checks to see if the image is a 1x1 solid color. We optimize these images and just do a fill rect instead. + void checkForSolidColor(); + + virtual bool mayFillWithSolidColor() const { return m_isSolidColor && m_currentFrame == 0; } + virtual Color solidColor() const { return m_solidColor; } + + ImageSource m_source; + mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image). + + size_t m_currentFrame; // The index of the current frame of animation. + Vector<FrameData> m_frames; // An array of the cached frames of the animation. We have to ref frames to pin them in the cache. + + Timer<BitmapImage>* m_frameTimer; + int m_repetitionCount; // How many total animation loops we should do. + int m_repetitionsComplete; // How many repetitions we've finished. + +#if PLATFORM(MAC) + mutable RetainPtr<NSImage> m_nsImage; // A cached NSImage of frame 0. Only built lazily if someone actually queries for one. + mutable RetainPtr<CFDataRef> m_tiffRep; // Cached TIFF rep for frame 0. Only built lazily if someone queries for one. +#endif + + Color m_solidColor; // If we're a 1x1 solid color, this is the color to use to fill. + bool m_isSolidColor; // Whether or not we are a 1x1 solid image. + + bool m_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. + +#if PLATFORM(QT) + QPixmap *m_pixmap; +#endif + +}; + +} + +#endif diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp new file mode 100644 index 0000000..52d2bd7 --- /dev/null +++ b/WebCore/platform/graphics/Color.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +#include "PlatformString.h" +#include <math.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> + +#include "ColorData.c" + +using namespace std; +using namespace WTF; + +namespace WebCore { + +const RGBA32 lightenedBlack = 0xFF545454; +const RGBA32 darkenedWhite = 0xFFABABAB; + +RGBA32 makeRGB(int r, int g, int b) +{ + return 0xFF000000 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255)); +} + +RGBA32 makeRGBA(int r, int g, int b, int a) +{ + return max(0, min(a, 255)) << 24 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255)); +} + +static double calcHue(double temp1, double temp2, double hueVal) +{ + if (hueVal < 0.0) + hueVal++; + else if (hueVal > 1.0) + hueVal--; + if (hueVal * 6.0 < 1.0) + return temp1 + (temp2 - temp1) * hueVal * 6.0; + if (hueVal * 2.0 < 1.0) + return temp2; + if (hueVal * 3.0 < 2.0) + return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hueVal) * 6.0; + return temp1; +} + +// Explanation of this algorithm can be found in the CSS3 Color Module +// specification at http://www.w3.org/TR/css3-color/#hsl-color with further +// explanation available at http://en.wikipedia.org/wiki/HSL_color_space + +// all values are in the range of 0 to 1.0 +RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double alpha) +{ + const double scaleFactor = nextafter(256.0, 0.0); + + if (!saturation) { + int greyValue = static_cast<int>(lightness * scaleFactor); + return makeRGBA(greyValue, greyValue, greyValue, static_cast<int>(alpha * scaleFactor)); + } + + double temp2 = lightness < 0.5 ? lightness * (1.0 + saturation) : lightness + saturation - lightness * saturation; + double temp1 = 2.0 * lightness - temp2; + + return makeRGBA(static_cast<int>(calcHue(temp1, temp2, hue + 1.0 / 3.0) * scaleFactor), + static_cast<int>(calcHue(temp1, temp2, hue) * scaleFactor), + static_cast<int>(calcHue(temp1, temp2, hue - 1.0 / 3.0) * scaleFactor), + static_cast<int>(alpha * scaleFactor)); +} + +// originally moved here from the CSS parser +bool Color::parseHexColor(const String& name, RGBA32& rgb) +{ + unsigned length = name.length(); + if (length != 3 && length != 6) + return false; + unsigned value = 0; + for (unsigned i = 0; i < length; ++i) { + if (!isASCIIHexDigit(name[i])) + return false; + value <<= 4; + value |= toASCIIHexValue(name[i]); + } + if (length == 6) { + rgb = 0xFF000000 | value; + return true; + } + // #abc converts to #aabbcc + rgb = 0xFF000000 + | (value & 0xF00) << 12 | (value & 0xF00) << 8 + | (value & 0xF0) << 8 | (value & 0xF0) << 4 + | (value & 0xF) << 4 | (value & 0xF); + return true; +} + +int differenceSquared(const Color& c1, const Color& c2) +{ + int dR = c1.red() - c2.red(); + int dG = c1.green() - c2.green(); + int dB = c1.blue() - c2.blue(); + return dR * dR + dG * dG + dB * dB; +} + +Color::Color(const String& name) +{ + if (name.startsWith("#")) + m_valid = parseHexColor(name.substring(1), m_color); + else + setNamedColor(name); +} + +Color::Color(const char* name) +{ + if (name[0] == '#') + m_valid = parseHexColor(&name[1], m_color); + else { + const NamedColor* foundColor = findColor(name, strlen(name)); + m_color = foundColor ? foundColor->RGBValue : 0; + m_color |= 0xFF000000; + m_valid = foundColor; + } +} + +String Color::name() const +{ + if (alpha() < 0xFF) + return String::format("#%02X%02X%02X%02X", red(), green(), blue(), alpha()); + return String::format("#%02X%02X%02X", red(), green(), blue()); +} + +static inline const NamedColor* findNamedColor(const String& name) +{ + char buffer[64]; // easily big enough for the longest color name + unsigned length = name.length(); + if (length > sizeof(buffer) - 1) + return 0; + for (unsigned i = 0; i < length; ++i) { + UChar c = name[i]; + if (!c || c > 0x7F) + return 0; + buffer[i] = toASCIILower(static_cast<char>(c)); + } + buffer[length] = '\0'; + return findColor(buffer, length); +} + +void Color::setNamedColor(const String& name) +{ + const NamedColor* foundColor = findNamedColor(name); + m_color = foundColor ? foundColor->RGBValue : 0; + m_color |= 0xFF000000; + m_valid = foundColor; +} + +Color Color::light() const +{ + // Hardcode this common case for speed. + if (m_color == black) + return lightenedBlack; + + const float scaleFactor = nextafterf(256.0f, 0.0f); + + float r, g, b, a; + getRGBA(r, g, b, a); + + float v = max(r, max(g, b)); + + if (v == 0.0f) + // Lightened black with alpha. + return Color(0x54, 0x54, 0x54, alpha()); + + float multiplier = min(1.0f, v + 0.33f) / v; + + return Color(static_cast<int>(multiplier * r * scaleFactor), + static_cast<int>(multiplier * g * scaleFactor), + static_cast<int>(multiplier * b * scaleFactor), + alpha()); +} + +Color Color::dark() const +{ + // Hardcode this common case for speed. + if (m_color == white) + return darkenedWhite; + + const float scaleFactor = nextafterf(256.0f, 0.0f); + + float r, g, b, a; + getRGBA(r, g, b, a); + + float v = max(r, max(g, b)); + float multiplier = max(0.0f, (v - 0.33f) / v); + + return Color(static_cast<int>(multiplier * r * scaleFactor), + static_cast<int>(multiplier * g * scaleFactor), + static_cast<int>(multiplier * b * scaleFactor), + alpha()); +} + +static int blendComponent(int c, int a) +{ + // We use white. + float alpha = a / 255.0f; + int whiteBlend = 255 - a; + c -= whiteBlend; + return static_cast<int>(c / alpha); +} + +const int cStartAlpha = 153; // 60% +const int cEndAlpha = 204; // 80%; +const int cAlphaIncrement = 17; // Increments in between. + +Color Color::blend(const Color& source) const +{ + if (!alpha() || !source.hasAlpha()) + return source; + + if (!source.alpha()) + return *this; + + int d = 255 * (alpha() + source.alpha()) - alpha() * source.alpha(); + int a = d / 255; + int r = (red() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.red()) / d; + int g = (green() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.green()) / d; + int b = (blue() * alpha() * (255 - source.alpha()) + 255 * source.alpha() * source.blue()) / d; + return Color(r, g, b, a); +} + +Color Color::blendWithWhite() const +{ + // If the color contains alpha already, we leave it alone. + if (hasAlpha()) + return *this; + + Color newColor; + for (int alpha = cStartAlpha; alpha <= cEndAlpha; alpha += cAlphaIncrement) { + // We have a solid color. Convert to an equivalent color that looks the same when blended with white + // at the current alpha. Try using less transparency if the numbers end up being negative. + int r = blendComponent(red(), alpha); + int g = blendComponent(green(), alpha); + int b = blendComponent(blue(), alpha); + + newColor = Color(r, g, b, alpha); + + if (r >= 0 && g >= 0 && b >= 0) + break; + } + return newColor; +} + +void Color::getRGBA(float& r, float& g, float& b, float& a) const +{ + r = red() / 255.0f; + g = green() / 255.0f; + b = blue() / 255.0f; + a = alpha() / 255.0f; +} + +void Color::getRGBA(double& r, double& g, double& b, double& a) const +{ + r = red() / 255.0; + g = green() / 255.0; + b = blue() / 255.0; + a = alpha() / 255.0; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h new file mode 100644 index 0000000..5706c6f --- /dev/null +++ b/WebCore/platform/graphics/Color.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2003-6 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Color_h +#define Color_h + +#include <wtf/Platform.h> + +#if PLATFORM(CG) +typedef struct CGColor* CGColorRef; +#endif + +#if PLATFORM(QT) +class QColor; +#endif + +#if PLATFORM(GTK) +typedef struct _GdkColor GdkColor; +#endif + +#if PLATFORM(WX) +class wxColour; +#endif + +namespace WebCore { + +class String; +class Color; + +typedef unsigned RGBA32; // RGBA quadruplet + +RGBA32 makeRGB(int r, int g, int b); +RGBA32 makeRGBA(int r, int g, int b, int a); +RGBA32 makeRGBAFromHSLA(double h, double s, double l, double a); + +int differenceSquared(const Color&, const Color&); + +class Color { +public: + Color() : m_color(0), m_valid(false) { } + Color(RGBA32 col) : m_color(col), m_valid(true) { } + Color(int r, int g, int b) : m_color(makeRGB(r, g, b)), m_valid(true) { } + Color(int r, int g, int b, int a) : m_color(makeRGBA(r, g, b, a)), m_valid(true) { } + explicit Color(const String&); + explicit Color(const char*); + + String name() const; + void setNamedColor(const String&); + + bool isValid() const { return m_valid; } + + bool hasAlpha() const { return alpha() < 255; } + + int red() const { return (m_color >> 16) & 0xFF; } + int green() const { return (m_color >> 8) & 0xFF; } + int blue() const { return m_color & 0xFF; } + int alpha() const { return (m_color >> 24) & 0xFF; } + + RGBA32 rgb() const { return m_color; } // Preserve the alpha. + void setRGB(int r, int g, int b) { m_color = makeRGB(r, g, b); m_valid = true; } + void setRGB(RGBA32 rgb) { m_color = rgb; m_valid = true; } + void getRGBA(float& r, float& g, float& b, float& a) const; + void getRGBA(double& r, double& g, double& b, double& a) const; + + Color light() const; + Color dark() const; + + Color blend(const Color&) const; + Color blendWithWhite() const; + +#if PLATFORM(QT) + Color(const QColor&); + operator QColor() const; +#endif + +#if PLATFORM(GTK) + Color(const GdkColor&); + // We can't sensibly go back to GdkColor without losing the alpha value +#endif + +#if PLATFORM(WX) + Color(const wxColour&); + operator wxColour() const; +#endif + +#if PLATFORM(CG) + Color(CGColorRef); +#endif + + static bool parseHexColor(const String& name, RGBA32& rgb); + + static const RGBA32 black = 0xFF000000; + static const RGBA32 white = 0xFFFFFFFF; + static const RGBA32 darkGray = 0xFF808080; + static const RGBA32 gray = 0xFFA0A0A0; + static const RGBA32 lightGray = 0xFFC0C0C0; + static const RGBA32 transparent = 0x00000000; + +private: + RGBA32 m_color; + bool m_valid : 1; +}; + +inline bool operator==(const Color& a, const Color& b) +{ + return a.rgb() == b.rgb() && a.isValid() == b.isValid(); +} + +inline bool operator!=(const Color& a, const Color& b) +{ + return !(a == b); +} + +Color focusRingColor(); +void setFocusRingColorChangeFunction(void (*)()); + +#if PLATFORM(CG) +CGColorRef cgColor(const Color&); +#endif + +} // namespace WebCore + +#endif // Color_h diff --git a/WebCore/platform/graphics/FloatPoint.cpp b/WebCore/platform/graphics/FloatPoint.cpp new file mode 100644 index 0000000..3ca0361 --- /dev/null +++ b/WebCore/platform/graphics/FloatPoint.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatPoint.h" + +#include "AffineTransform.h" +#include "FloatConversion.h" +#include "IntPoint.h" + +namespace WebCore { + +FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y()) +{ +} + +FloatPoint FloatPoint::matrixTransform(const AffineTransform& transform) const +{ + double newX, newY; + transform.map(static_cast<double>(m_x), static_cast<double>(m_y), &newX, &newY); + return narrowPrecision(newX, newY); +} + +FloatPoint FloatPoint::narrowPrecision(double x, double y) +{ + return FloatPoint(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)); +} + +} diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h new file mode 100644 index 0000000..7b8ba1d --- /dev/null +++ b/WebCore/platform/graphics/FloatPoint.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FloatPoint_h +#define FloatPoint_h + +#include "FloatSize.h" +#include <wtf/Platform.h> + +#if PLATFORM(CG) +typedef struct CGPoint CGPoint; +#endif + +#if PLATFORM(MAC) +#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES +typedef struct CGPoint NSPoint; +#else +typedef struct _NSPoint NSPoint; +#endif +#endif + +#if PLATFORM(QT) +class QPointF; +#endif + +#if PLATFORM(SYMBIAN) +class TPoint; +#endif + +namespace WebCore { + +class AffineTransform; +class IntPoint; + +class FloatPoint { +public: + FloatPoint() : m_x(0), m_y(0) { } + FloatPoint(float x, float y) : m_x(x), m_y(y) { } + FloatPoint(const IntPoint&); + + static FloatPoint narrowPrecision(double x, double y); + + float x() const { return m_x; } + float y() const { return m_y; } + + void setX(float x) { m_x = x; } + void setY(float y) { m_y = y; } + void move(float dx, float dy) { m_x += dx; m_y += dy; } + +#if PLATFORM(CG) + FloatPoint(const CGPoint&); + operator CGPoint() const; +#endif + +#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) + FloatPoint(const NSPoint&); + operator NSPoint() const; +#endif + +#if PLATFORM(QT) + FloatPoint(const QPointF&); + operator QPointF() const; +#endif + +#if PLATFORM(SYMBIAN) + operator TPoint() const; + FloatPoint(const TPoint& ); +#endif + + FloatPoint matrixTransform(const AffineTransform&) const; + +private: + float m_x, m_y; +}; + + +inline FloatPoint& operator+=(FloatPoint& a, const FloatSize& b) +{ + a.move(b.width(), b.height()); + return a; +} + +inline FloatPoint& operator-=(FloatPoint& a, const FloatSize& b) +{ + a.move(-b.width(), -b.height()); + return a; +} + +inline FloatPoint operator+(const FloatPoint& a, const FloatSize& b) +{ + return FloatPoint(a.x() + b.width(), a.y() + b.height()); +} + +inline FloatSize operator-(const FloatPoint& a, const FloatPoint& b) +{ + return FloatSize(a.x() - b.x(), a.y() - b.y()); +} + +inline FloatPoint operator-(const FloatPoint& a, const FloatSize& b) +{ + return FloatPoint(a.x() - b.width(), a.y() - b.height()); +} + +inline bool operator==(const FloatPoint& a, const FloatPoint& b) +{ + return a.x() == b.x() && a.y() == b.y(); +} + +inline bool operator!=(const FloatPoint& a, const FloatPoint& b) +{ + return a.x() != b.x() || a.y() != b.y(); +} + +} + +#endif diff --git a/WebCore/platform/graphics/FloatPoint3D.cpp b/WebCore/platform/graphics/FloatPoint3D.cpp new file mode 100644 index 0000000..ec52d40 --- /dev/null +++ b/WebCore/platform/graphics/FloatPoint3D.cpp @@ -0,0 +1,85 @@ +/* + Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org> + 2004, 2005 Rob Buis <buis@kde.org> + 2005 Eric Seidel <eric@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(SVG) +#include <math.h> +#include "FloatPoint3D.h" + +namespace WebCore { + +FloatPoint3D::FloatPoint3D() + : m_x(0.f) + , m_y(0.f) + , m_z(0.f) +{ +} + +FloatPoint3D::FloatPoint3D(float x, float y, float z) + : m_x(x) + , m_y(y) + , m_z(z) +{ +} + +float FloatPoint3D::x() const +{ + return m_x; +} + +void FloatPoint3D::setX(float x) +{ + m_x = x; +} + +float FloatPoint3D::y() const +{ + return m_y; +} + +void FloatPoint3D::setY(float y) +{ + m_y = y; +} + +float FloatPoint3D::z() const +{ + return m_z; +} + +void FloatPoint3D::setZ(float z) +{ + m_z = z; +} + +void FloatPoint3D::normalize() +{ + float length = sqrtf(m_x * m_x + m_y * m_y + m_z * m_z); + + m_x /= length; + m_y /= length; + m_z /= length; +} + +} // namespace WebCore + +#endif // ENABLE(SVG) diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h new file mode 100644 index 0000000..55f70e7 --- /dev/null +++ b/WebCore/platform/graphics/FloatPoint3D.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org> + 2004, 2005 Rob Buis <buis@kde.org> + 2005 Eric Seidel <eric@webkit.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef FloatPoint3D_h +#define FloatPoint3D_h + +#if ENABLE(SVG) + +namespace WebCore { + +class FloatPoint3D { +public: + FloatPoint3D(); + FloatPoint3D(float x, float y, float z); + + float x() const; + void setX(float x); + + float y() const; + void setY(float y); + + float z() const; + void setZ(float z); + + void normalize(); + +private: + float m_x; + float m_y; + float m_z; +}; + +} // namespace WebCore + +#endif // ENABLE(SVG) + +#endif // FloatPoint3D_h diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp new file mode 100644 index 0000000..bb604d1 --- /dev/null +++ b/WebCore/platform/graphics/FloatRect.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatRect.h" + +#include "FloatConversion.h" +#include "IntRect.h" +#include <algorithm> + +using std::max; +using std::min; + +namespace WebCore { + +FloatRect::FloatRect(const IntRect& r) : m_location(r.location()), m_size(r.size()) +{ +} + +FloatRect FloatRect::narrowPrecision(double x, double y, double width, double height) +{ + return FloatRect(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y), narrowPrecisionToFloat(width), narrowPrecisionToFloat(height)); +} + +bool FloatRect::intersects(const FloatRect& other) const +{ + // Checking emptiness handles negative widths as well as zero. + return !isEmpty() && !other.isEmpty() + && x() < other.right() && other.x() < right() + && y() < other.bottom() && other.y() < bottom(); +} + +bool FloatRect::contains(const FloatRect& other) const +{ + return x() <= other.x() && right() >= other.right() + && y() <= other.y() && bottom() >= other.bottom(); +} + +void FloatRect::intersect(const FloatRect& other) +{ + float l = max(x(), other.x()); + float t = max(y(), other.y()); + float r = min(right(), other.right()); + float b = min(bottom(), other.bottom()); + + // Return a clean empty rectangle for non-intersecting cases. + if (l >= r || t >= b) { + l = 0; + t = 0; + r = 0; + b = 0; + } + + m_location.setX(l); + m_location.setY(t); + m_size.setWidth(r - l); + m_size.setHeight(b - t); +} + +void FloatRect::unite(const FloatRect& other) +{ + // Handle empty special cases first. + if (other.isEmpty()) + return; + if (isEmpty()) { + *this = other; + return; + } + + float l = min(x(), other.x()); + float t = min(y(), other.y()); + float r = max(right(), other.right()); + float b = max(bottom(), other.bottom()); + + m_location.setX(l); + m_location.setY(t); + m_size.setWidth(r - l); + m_size.setHeight(b - t); +} + +void FloatRect::scale(float s) +{ + m_location.setX(x() * s); + m_location.setY(y() * s); + m_size.setWidth(width() * s); + m_size.setHeight(height() * s); +} + +IntRect enclosingIntRect(const FloatRect& rect) +{ + int l = static_cast<int>(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); + return IntRect(l, t, r - l, b - t); +} + +} diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h new file mode 100644 index 0000000..867813d --- /dev/null +++ b/WebCore/platform/graphics/FloatRect.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FloatRect_h +#define FloatRect_h + +#include "FloatPoint.h" + +#if PLATFORM(CG) +typedef struct CGRect CGRect; +#endif + +#if PLATFORM(MAC) +#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES +typedef struct CGRect NSRect; +#else +typedef struct _NSRect NSRect; +#endif +#endif + +#if PLATFORM(QT) +class QRectF; +#endif + +#if PLATFORM(WX) && USE(WXGC) +class wxRect2DDouble; +#endif + +namespace WebCore { + +class IntRect; + +class FloatRect { +public: + FloatRect() { } + FloatRect(const FloatPoint& location, const FloatSize& size) + : m_location(location), m_size(size) { } + FloatRect(float x, float y, float width, float height) + : m_location(FloatPoint(x, y)), m_size(FloatSize(width, height)) { } + FloatRect(const IntRect&); + + static FloatRect narrowPrecision(double x, double y, double width, double height); + + FloatPoint location() const { return m_location; } + FloatSize size() const { return m_size; } + + void setLocation(const FloatPoint& location) { m_location = location; } + void setSize(const FloatSize& size) { m_size = size; } + + float x() const { return m_location.x(); } + float y() const { return m_location.y(); } + float width() const { return m_size.width(); } + float height() const { return m_size.height(); } + + void setX(float x) { m_location.setX(x); } + void setY(float y) { m_location.setY(y); } + void setWidth(float width) { m_size.setWidth(width); } + void setHeight(float height) { m_size.setHeight(height); } + + bool isEmpty() const { return m_size.isEmpty(); } + + float right() const { return x() + width(); } + float bottom() const { return y() + height(); } + + void move(const FloatSize& delta) { m_location += delta; } + void move(float dx, float dy) { m_location.move(dx, dy); } + + bool intersects(const FloatRect&) const; + bool contains(const FloatRect&) const; + + void intersect(const FloatRect&); + void unite(const FloatRect&); + + // Note, this doesn't match what IntRect::contains(IntPoint&) does; the int version + // is really checking for containment of 1x1 rect, but that doesn't make sense with floats. + bool contains(float px, float py) const + { return px >= x() && px <= right() && py >= y() && py <= bottom(); } + bool contains(const FloatPoint& point) const { return contains(point.x(), point.y()); } + + + void inflateX(float dx) { + m_location.setX(m_location.x() - dx); + m_size.setWidth(m_size.width() + dx + dx); + } + void inflateY(float dy) { + m_location.setY(m_location.y() - dy); + m_size.setHeight(m_size.height() + dy + dy); + } + void inflate(float d) { inflateX(d); inflateY(d); } + void scale(float s); + +#if PLATFORM(CG) + FloatRect(const CGRect&); + operator CGRect() const; +#endif + +#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) + FloatRect(const NSRect&); + operator NSRect() const; +#endif + +#if PLATFORM(QT) + FloatRect(const QRectF&); + operator QRectF() const; +#endif +#if PLATFORM(SYMBIAN) + FloatRect(const TRect&); + operator TRect() const; + TRect rect() const; +#endif + +#if PLATFORM(WX) && USE(WXGC) + FloatRect(const wxRect2DDouble&); + operator wxRect2DDouble() const; +#endif + +private: + FloatPoint m_location; + FloatSize m_size; +}; + +inline FloatRect intersection(const FloatRect& a, const FloatRect& b) +{ + FloatRect c = a; + c.intersect(b); + return c; +} + +inline FloatRect unionRect(const FloatRect& a, const FloatRect& b) +{ + FloatRect c = a; + c.unite(b); + return c; +} + +inline bool operator==(const FloatRect& a, const FloatRect& b) +{ + return a.location() == b.location() && a.size() == b.size(); +} + +inline bool operator!=(const FloatRect& a, const FloatRect& b) +{ + return a.location() != b.location() || a.size() != b.size(); +} + +IntRect enclosingIntRect(const FloatRect&); + +} + +#endif diff --git a/WebCore/platform/graphics/FloatSize.cpp b/WebCore/platform/graphics/FloatSize.cpp new file mode 100644 index 0000000..86fa4c0 --- /dev/null +++ b/WebCore/platform/graphics/FloatSize.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatSize.h" + +#include "FloatConversion.h" +#include "IntSize.h" + +namespace WebCore { + +FloatSize::FloatSize(const IntSize& size) : m_width(size.width()), m_height(size.height()) +{ +} + +FloatSize FloatSize::narrowPrecision(double width, double height) +{ + return FloatSize(narrowPrecisionToFloat(width), narrowPrecisionToFloat(height)); +} + +} diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h new file mode 100644 index 0000000..cf1e1c5 --- /dev/null +++ b/WebCore/platform/graphics/FloatSize.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FloatSize_h +#define FloatSize_h + +#include <wtf/Platform.h> + +#if PLATFORM(CG) +typedef struct CGSize CGSize; +#endif + +#if PLATFORM(MAC) +#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES +typedef struct CGSize NSSize; +#else +typedef struct _NSSize NSSize; +#endif +#endif + +namespace WebCore { + +class IntSize; + +class FloatSize { +public: + FloatSize() : m_width(0), m_height(0) { } + FloatSize(float width, float height) : m_width(width), m_height(height) { } + FloatSize(const IntSize&); + + static FloatSize narrowPrecision(double width, double height); + + float width() const { return m_width; } + float height() const { return m_height; } + + void setWidth(float width) { m_width = width; } + void setHeight(float height) { m_height = height; } + + bool isEmpty() const { return m_width <= 0 || m_height <= 0; } + + FloatSize expandedTo(const FloatSize& other) const + { + return FloatSize(m_width > other.m_width ? m_width : other.m_width, + m_height > other.m_height ? m_height : other.m_height); + } + +#if PLATFORM(CG) + explicit FloatSize(const CGSize&); // don't do this implicitly since it's lossy + operator CGSize() const; +#endif + +#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) + explicit FloatSize(const NSSize &); // don't do this implicitly since it's lossy + operator NSSize() const; +#endif + +private: + float m_width, m_height; +}; + +inline FloatSize& operator+=(FloatSize& a, const FloatSize& b) +{ + a.setWidth(a.width() + b.width()); + a.setHeight(a.height() + b.height()); + return a; +} + +inline FloatSize& operator-=(FloatSize& a, const FloatSize& b) +{ + a.setWidth(a.width() - b.width()); + a.setHeight(a.height() - b.height()); + return a; +} + +inline FloatSize operator+(const FloatSize& a, const FloatSize& b) +{ + return FloatSize(a.width() + b.width(), a.height() + b.height()); +} + +inline FloatSize operator-(const FloatSize& a, const FloatSize& b) +{ + return FloatSize(a.width() - b.width(), a.height() - b.height()); +} + +inline FloatSize operator-(const FloatSize& size) +{ + return FloatSize(-size.width(), -size.height()); +} + +inline bool operator==(const FloatSize& a, const FloatSize& b) +{ + return a.width() == b.width() && a.height() == b.height(); +} + +inline bool operator!=(const FloatSize& a, const FloatSize& b) +{ + return a.width() != b.width() || a.height() != b.height(); +} + +} // namespace WebCore + +#endif // FloatSize_h diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp new file mode 100644 index 0000000..05704d3 --- /dev/null +++ b/WebCore/platform/graphics/Font.cpp @@ -0,0 +1,809 @@ +/** + * 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. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Font.h" + +#include "CharacterNames.h" +#include "FloatRect.h" +#include "FontCache.h" +#include "FontFallbackList.h" +#include "IntPoint.h" +#include "GlyphBuffer.h" +#include <wtf/unicode/Unicode.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 /*?*/, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +Font::CodePath Font::codePath = Auto; + +struct WidthIterator { + WidthIterator(const Font* font, const TextRun& run); + + void 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); + } +} + +void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) +{ + if (offset > m_end) + offset = m_end; + + int currentCharacter = m_currentCharacter; + const UChar* cp = m_run.data(currentCharacter); + + bool rtl = m_run.rtl(); + bool hasExtraSpacing = m_font->letterSpacing() || m_font->wordSpacing() || m_padding; + + float runWidthSoFar = m_runWidthSoFar; + float lastRoundingWidth = m_finalRoundingWidth; + + while (currentCharacter < offset) { + UChar32 c = *cp; + unsigned clusterLength = 1; + if (c >= 0x3041) { + if (c <= 0x30FE) { + // Deal with Hiragana and Katakana voiced and semi-voiced syllables. + // Normalize into composed form, and then look for glyph with base + combined mark. + // Check above for character range to minimize performance impact. + UChar32 normalized = normalizeVoicingMarks(currentCharacter); + if (normalized) { + c = normalized; + clusterLength = 2; + } + } else if (U16_IS_SURROGATE(c)) { + if (!U16_IS_SURROGATE_LEAD(c)) + break; + + // Do we have a surrogate pair? If so, determine the full Unicode (32 bit) + // code point before glyph lookup. + // Make sure we have another character and it's a low surrogate. + if (currentCharacter + 1 >= m_run.length()) + break; + UChar low = cp[1]; + if (!U16_IS_TRAIL(low)) + break; + c = U16_GET_SUPPLEMENTARY(c, low); + clusterLength = 2; + } + } + + const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl); + Glyph glyph = glyphData.glyph; + const SimpleFontData* fontData = glyphData.fontData; + + ASSERT(fontData); + + // Now that we have a glyph and font data, get its width. + float width; + if (c == '\t' && m_run.allowTabs()) { + float tabWidth = m_font->tabWidth(); + width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth); + } else { + width = fontData->widthForGlyph(glyph); + // We special case spaces in two ways when applying word rounding. + // First, we round spaces to an adjusted width in all fonts. + // Second, in fixed-pitch fonts we ensure that all characters that + // match the width of the space character have the same width as the space character. + if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) + width = fontData->m_adjustedSpaceWidth; + } + + if (hasExtraSpacing && !m_run.spacingDisabled()) { + // Account for letter-spacing. + if (width && m_font->letterSpacing()) + width += m_font->letterSpacing(); + + if (Font::treatAsSpace(c)) { + // Account for padding. WebCore uses space padding to justify text. + // We distribute the specified padding over the available spaces in the run. + if (m_padding) { + // Use left over padding if not evenly divisible by number of spaces. + if (m_padding < m_padPerSpace) { + width += m_padding; + m_padding = 0; + } else { + width += m_padPerSpace; + m_padding -= m_padPerSpace; + } + } + + // Account for word spacing. + // We apply additional space between "words" by adding width to the space character. + if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) + width += m_font->wordSpacing(); + } + } + + // Advance past the character we just dealt with. + cp += clusterLength; + currentCharacter += clusterLength; + + // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters + // followed by a character defined by isRoundingHackCharacter()) are always an integer width. + // We adjust the width of the last character of a "word" to ensure an integer width. + // If we move KHTML to floats we can remove this (and related) hacks. + + float oldWidth = width; + + // Force characters that are used to determine word boundaries for the rounding hack + // to be integer width, so following words will start on an integer boundary. + if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) + width = ceilf(width); + + // Check to see if the next character is a "rounding hack character", if so, adjust + // width so that the total run width will be on an integer boundary. + if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp)) + || (m_run.applyRunRounding() && currentCharacter >= m_end)) { + float totalWidth = runWidthSoFar + width; + width += ceilf(totalWidth) - totalWidth; + } + + runWidthSoFar += width; + + if (glyphBuffer) + glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width)); + + lastRoundingWidth = width - oldWidth; + } + + m_currentCharacter = currentCharacter; + m_runWidthSoFar = runWidthSoFar; + m_finalRoundingWidth = lastRoundingWidth; +} + +bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer) +{ + glyphBuffer->clear(); + advance(m_currentCharacter + 1, glyphBuffer); + float w = 0; + for (int i = 0; i < glyphBuffer->size(); ++i) + w += glyphBuffer->advanceAt(i); + width = w; + return !glyphBuffer->isEmpty(); +} + +UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter) +{ + if (currentCharacter + 1 < m_end) { + if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoicingMarksCombiningClass) { +#if USE(ICU_UNICODE) + // Normalize into composed form using 3.2 rules. + UChar normalizedCharacters[2] = { 0, 0 }; + UErrorCode uStatus = U_ZERO_ERROR; + int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2, + UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus); + if (resultLength == 1 && uStatus == 0) + return normalizedCharacters[0]; +#elif USE(QT4_UNICODE) + QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharacter)), 2); + QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Unicode_3_2); + if (res.length() == 1) + return res.at(0).unicode(); +#endif + } + } + return 0; +} + +// ============================================================================================ +// Font Implementation (Cross-Platform Portion) +// ============================================================================================ + +Font::Font() + : m_pageZero(0) + , m_cachedPrimaryFont(0) + , m_letterSpacing(0) + , m_wordSpacing(0) + , m_isPlatformFont(false) +{ +} + +Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing) + : m_fontDescription(fd) + , m_pageZero(0) + , m_cachedPrimaryFont(0) + , m_letterSpacing(letterSpacing) + , m_wordSpacing(wordSpacing) + , m_isPlatformFont(false) +{ +} + +Font::Font(const FontPlatformData& fontData, bool isPrinterFont) + : m_fontList(new FontFallbackList) + , m_pageZero(0) + , m_cachedPrimaryFont(0) + , m_letterSpacing(0) + , m_wordSpacing(0) + , m_isPlatformFont(true) +{ + m_fontDescription.setUsePrinterFont(isPrinterFont); + m_fontList->setPlatformFont(fontData); +} + +Font::Font(const Font& other) + : m_fontDescription(other.m_fontDescription) + , m_fontList(other.m_fontList) + , m_pages(other.m_pages) + , m_pageZero(other.m_pageZero) + , m_cachedPrimaryFont(other.m_cachedPrimaryFont) + , m_letterSpacing(other.m_letterSpacing) + , m_wordSpacing(other.m_wordSpacing) + , m_isPlatformFont(other.m_isPlatformFont) +{ +} + +Font& Font::operator=(const Font& other) +{ + m_fontDescription = other.m_fontDescription; + m_fontList = other.m_fontList; + m_pages = other.m_pages; + m_pageZero = other.m_pageZero; + m_cachedPrimaryFont = other.m_cachedPrimaryFont; + m_letterSpacing = other.m_letterSpacing; + m_wordSpacing = other.m_wordSpacing; + m_isPlatformFont = other.m_isPlatformFont; + return *this; +} + +Font::~Font() +{ +} + +bool Font::operator==(const Font& other) const +{ + // Our FontData don't have to be checked, since checking the font description will be fine. + // FIXME: This does not work if the font was made with the FontPlatformData constructor. + if ((m_fontList && m_fontList->loadingCustomFonts()) || + (other.m_fontList && other.m_fontList->loadingCustomFonts())) + return false; + + FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0; + FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0; + + return first == second + && m_fontDescription == other.m_fontDescription + && m_letterSpacing == other.m_letterSpacing + && m_wordSpacing == other.m_wordSpacing; +} + +const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const +{ + bool useSmallCapsFont = forceSmallCaps; + if (m_fontDescription.smallCaps()) { + UChar32 upperC = Unicode::toUpper(c); + if (upperC != c) { + c = upperC; + useSmallCapsFont = true; + } + } + + if (mirror) + c = mirroredChar(c); + + unsigned pageNumber = (c / GlyphPage::size); + + GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero; + if (!node) { + node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); + if (pageNumber) + m_pages.set(pageNumber, node); + else + m_pageZero = node; + } + + GlyphPage* page; + if (!useSmallCapsFont) { + // Fastest loop, for the common case (not small caps). + while (true) { + page = node->page(); + if (page) { + const GlyphData& data = page->glyphDataForCharacter(c); + if (data.fontData) + return data; + if (node->isSystemFallback()) + break; + } + + // Proceed with the fallback list. + node = node->getChild(fontDataAt(node->level()), pageNumber); + if (pageNumber) + m_pages.set(pageNumber, node); + else + m_pageZero = node; + } + } else { + while (true) { + page = node->page(); + if (page) { + const GlyphData& data = page->glyphDataForCharacter(c); + if (data.fontData) { + // The smallCapsFontData function should not normally return 0. + // But if it does, we will just render the capital letter big. + const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription); + if (!smallCapsFontData) + return data; + + GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); + const GlyphData& data = smallCapsNode->page()->glyphDataForCharacter(c); + if (data.fontData) + return data; + + // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that + // a font has the lowercase character but the small caps font does not have its uppercase version. + return smallCapsFontData->missingGlyphData(); + } + + if (node->isSystemFallback()) + break; + } + + // Proceed with the fallback list. + node = node->getChild(fontDataAt(node->level()), pageNumber); + if (pageNumber) + m_pages.set(pageNumber, node); + else + m_pageZero = node; + } + } + + ASSERT(page); + ASSERT(node->isSystemFallback()); + + // System fallback is character-dependent. When we get here, we + // know that the character in question isn't in the system fallback + // font's glyph page. Try to lazily create it here. + UChar codeUnits[2]; + int codeUnitsLength; + if (c <= 0xFFFF) { + UChar c16 = c; + if (Font::treatAsSpace(c16)) + codeUnits[0] = ' '; + else if (Font::treatAsZeroWidthSpace(c16)) + codeUnits[0] = zeroWidthSpace; + else + codeUnits[0] = c16; + codeUnitsLength = 1; + } else { + codeUnits[0] = U16_LEAD(c); + codeUnits[1] = U16_TRAIL(c); + codeUnitsLength = 2; + } + const SimpleFontData* characterFontData = FontCache::getFontDataForCharacters(*this, codeUnits, codeUnitsLength); + if (useSmallCapsFont) + characterFontData = characterFontData->smallCapsFontData(m_fontDescription); + if (characterFontData) { + // Got the fallback glyph and font. + GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); + const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); + // Cache it so we don't have to do system fallback again next time. + if (!useSmallCapsFont) + page->setGlyphDataForCharacter(c, data.glyph, data.fontData); + return data; + } + + // Even system fallback can fail; use the missing glyph in that case. + // FIXME: It would be nicer to use the missing glyph from the last resort font instead. + const GlyphData& data = primaryFont()->missingGlyphData(); + if (!useSmallCapsFont) + page->setGlyphDataForCharacter(c, data.glyph, data.fontData); + return data; +} + +void Font::cachePrimaryFont() const +{ + ASSERT(m_fontList); + ASSERT(!m_cachedPrimaryFont); + m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' '); +} + +const FontData* Font::fontDataAt(unsigned index) const +{ + ASSERT(m_fontList); + return m_fontList->fontDataAt(this, index); +} + +const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const +{ + ASSERT(m_fontList); + return m_fontList->fontDataForCharacters(this, characters, length); +} + +void Font::update(PassRefPtr<FontSelector> fontSelector) const +{ + // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up + // being reasonably safe (because inherited fonts in the render tree pick up the new + // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and + // won't stick around long enough to get you in trouble). Still, this is pretty disgusting, + // and could eventually be rectified by using RefPtrs for Fonts themselves. + if (!m_fontList) + m_fontList = new FontFallbackList(); + m_fontList->invalidate(fontSelector); + m_cachedPrimaryFont = 0; + m_pageZero = 0; + m_pages.clear(); +} + +int Font::width(const TextRun& run) const +{ + return lroundf(floatWidth(run)); +} + +int Font::ascent() const +{ + return primaryFont()->ascent(); +} + +int Font::descent() const +{ + return primaryFont()->descent(); +} + +int Font::lineSpacing() const +{ + return primaryFont()->lineSpacing(); +} + +float Font::xHeight() const +{ + return primaryFont()->xHeight(); +} + +unsigned Font::unitsPerEm() const +{ + return primaryFont()->unitsPerEm(); +} + +int Font::spaceWidth() const +{ + return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); +} + +bool Font::isFixedPitch() const +{ + ASSERT(m_fontList); + return m_fontList->isFixedPitch(this); +} + +void Font::setCodePath(CodePath p) +{ + codePath = p; +} + +bool Font::canUseGlyphCache(const TextRun& run) const +{ + switch (codePath) { + case Auto: + break; + case Simple: + return true; + case Complex: + return false; + } + + // Start from 0 since drawing and highlighting also measure the characters before run->from + for (int i = 0; i < run.length(); i++) { + const UChar c = run[i]; + if (c < 0x300) // U+0300 through U+036F Combining diacritical marks + continue; + if (c <= 0x36F) + return false; + + if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha + continue; + if (c <= 0x05CF) + return false; + + if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar + continue; + if (c <= 0x1059) + return false; + + if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A) + continue; + if (c <= 0x11FF) + return false; + + if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian + continue; + if (c <= 0x18AF) + return false; + + if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0) + continue; + if (c <= 0x194F) + return false; + + if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols + continue; + if (c <= 0x20FF) + return false; + + if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks + continue; + if (c <= 0xFE2F) + return false; + } + + return true; + +} + +void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + // This glyph buffer holds our glyphs+advances+font data for each glyph. + GlyphBuffer glyphBuffer; + + float startX = point.x(); + WidthIterator it(this, run); + it.advance(from); + float beforeWidth = it.m_runWidthSoFar; + it.advance(to, &glyphBuffer); + + // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) + return; + + float afterWidth = it.m_runWidthSoFar; + + if (run.rtl()) { + float finalRoundingWidth = it.m_finalRoundingWidth; + it.advance(run.length()); + startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth; + } else + startX += beforeWidth; + + // Swap the order of the glyphs if right-to-left. + if (run.rtl()) + for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) + glyphBuffer.swap(i, end); + + // Calculate the starting point of the glyphs to be displayed by adding + // all the advances up to the first glyph. + FloatPoint startPoint(startX, point.y()); + drawGlyphBuffer(context, glyphBuffer, run, startPoint); +} + +void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, + const TextRun& run, const FloatPoint& point) const +{ + // Draw each contiguous run of glyphs that use the same font data. + const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); + FloatSize offset = glyphBuffer.offsetAt(0); + FloatPoint startPoint(point); + float nextX = startPoint.x(); + int lastFrom = 0; + int nextGlyph = 0; + while (nextGlyph < glyphBuffer.size()) { + const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); + FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); + if (nextFontData != fontData || nextOffset != offset) { + drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); + + lastFrom = nextGlyph; + fontData = nextFontData; + offset = nextOffset; + startPoint.setX(nextX); + } + nextX += glyphBuffer.advanceAt(nextGlyph); + nextGlyph++; + } + + drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); +} + +void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + // Don't draw anything while we are using custom fonts that are in the process of loading. + if (m_fontList && m_fontList->loadingCustomFonts()) + return; + + to = (to == -1 ? run.length() : to); + +#if ENABLE(SVG_FONTS) + if (primaryFont()->isSVGFont()) { + drawTextUsingSVGFont(context, run, point, from, to); + return; + } +#endif + + if (canUseGlyphCache(run)) + drawSimpleText(context, run, point, from, to); + else + drawComplexText(context, run, point, from, to); +} + +float Font::floatWidth(const TextRun& run) const +{ +#if ENABLE(SVG_FONTS) + if (primaryFont()->isSVGFont()) + return floatWidthUsingSVGFont(run); +#endif + + if (canUseGlyphCache(run)) + return floatWidthForSimpleText(run, 0); + return floatWidthForComplexText(run); +} + +float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const +{ + WidthIterator it(this, run); + it.advance(run.length(), glyphBuffer); + return it.m_runWidthSoFar; +} + +FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const +{ +#if ENABLE(SVG_FONTS) + if (primaryFont()->isSVGFont()) + return selectionRectForTextUsingSVGFont(run, point, h, from, to); +#endif + + to = (to == -1 ? run.length() : to); + if (canUseGlyphCache(run)) + return selectionRectForSimpleText(run, point, h, from, to); + return selectionRectForComplexText(run, point, h, from, to); +} + +FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const +{ + WidthIterator it(this, run); + it.advance(from); + float beforeWidth = it.m_runWidthSoFar; + it.advance(to); + float afterWidth = it.m_runWidthSoFar; + + // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning + if (run.rtl()) { + it.advance(run.length()); + float totalWidth = it.m_runWidthSoFar; + return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); + } else { + return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); + } +} + +int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const +{ +#if ENABLE(SVG_FONTS) + if (primaryFont()->isSVGFont()) + return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs); +#endif + + if (canUseGlyphCache(run)) + return offsetForPositionForSimpleText(run, x, includePartialGlyphs); + return offsetForPositionForComplexText(run, x, includePartialGlyphs); +} + +int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const +{ + float delta = (float)x; + + WidthIterator it(this, run); + GlyphBuffer localGlyphBuffer; + unsigned offset; + if (run.rtl()) { + delta -= floatWidthForSimpleText(run, 0); + while (1) { + offset = it.m_currentCharacter; + float w; + if (!it.advanceOneCharacter(w, &localGlyphBuffer)) + break; + delta += w; + if (includePartialGlyphs) { + if (delta - w / 2 >= 0) + break; + } else { + if (delta >= 0) + break; + } + } + } else { + while (1) { + offset = it.m_currentCharacter; + float w; + if (!it.advanceOneCharacter(w, &localGlyphBuffer)) + break; + delta -= w; + if (includePartialGlyphs) { + if (delta + w / 2 <= 0) + break; + } else { + if (delta <= 0) + break; + } + } + } + + return offset; +} + +FontSelector* Font::fontSelector() const +{ + return m_fontList ? m_fontList->fontSelector() : 0; +} + +} diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h new file mode 100644 index 0000000..0ea04eb --- /dev/null +++ b/WebCore/platform/graphics/Font.h @@ -0,0 +1,291 @@ +/* + * 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) + * Copyright (C) 2003, 2006, 2007 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Font_h +#define Font_h + +#include "FontDescription.h" +#include <wtf/HashMap.h> + +#if PLATFORM(QT) +#include <QtGui/qfont.h> +#include <QtGui/qfontmetrics.h> +#endif + +namespace WebCore { + +class FloatPoint; +class FloatRect; +class FontData; +class FontFallbackList; +class FontPlatformData; +class FontSelector; +class GlyphBuffer; +class GlyphPageTreeNode; +class GraphicsContext; +class IntPoint; +class RenderObject; +class SimpleFontData; +class SVGPaintServer; + +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(); + Font(const FontDescription&, short letterSpacing, short wordSpacing); +#if !PLATFORM(QT) + Font(const FontPlatformData&, bool isPrinting); // This constructor is only used if the platform wants to start with a native font. +#endif + ~Font(); + + Font(const Font&); + Font& operator=(const Font&); + + bool operator==(const Font& other) const; + bool operator!=(const Font& other) const { + return !(*this == other); + } + + const FontDescription& fontDescription() const { return m_fontDescription; } + + int pixelSize() const { return fontDescription().computedPixelSize(); } + float size() const { return fontDescription().computedSize(); } + + void update(PassRefPtr<FontSelector>) const; + + void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const; + + int width(const TextRun&) const; + float floatWidth(const TextRun&) const; + + int offsetForPosition(const TextRun&, int position, bool includePartialGlyphs) const; + FloatRect selectionRectForText(const TextRun&, const IntPoint&, int h, int from = 0, int to = -1) const; + + bool isSmallCaps() const { return m_fontDescription.smallCaps(); } + + short wordSpacing() const { return m_wordSpacing; } + short letterSpacing() const { return m_letterSpacing; } +#if !PLATFORM(QT) + void setWordSpacing(short s) { m_wordSpacing = s; } + void setLetterSpacing(short s) { m_letterSpacing = s; } +#else + void setWordSpacing(short s); + void setLetterSpacing(short s); +#endif + bool isFixedPitch() const; + bool isPrinterFont() const { return m_fontDescription.usePrinterFont(); } + + FontRenderingMode renderingMode() const { return m_fontDescription.renderingMode(); } + + FontFamily& firstFamily() { return m_fontDescription.firstFamily(); } + const FontFamily& family() const { return m_fontDescription.family(); } + + bool italic() const { return m_fontDescription.italic(); } + unsigned weight() const { return m_fontDescription.weight(); } + bool bold() const { return m_fontDescription.bold(); } + +#if !PLATFORM(QT) + bool isPlatformFont() const { return m_isPlatformFont; } +#endif + +#if PLATFORM(QT) + inline const QFont &font() const { return m_font; } + inline const QFont &scFont() const { return m_scFont; } +#endif + + // Metrics that we query the FontFallbackList for. + int ascent() const; + int descent() const; + int height() const { return ascent() + descent(); } + int lineSpacing() const; + float xHeight() const; + unsigned unitsPerEm() const; + int spaceWidth() const; + int tabWidth() const { return 8 * spaceWidth(); } + +#if !PLATFORM(QT) + const SimpleFontData* primaryFont() const { + if (!m_cachedPrimaryFont) + cachePrimaryFont(); + return m_cachedPrimaryFont; + } + + const FontData* fontDataAt(unsigned) const; + const GlyphData& glyphDataForCharacter(UChar32, bool mirror, bool forceSmallCaps = false) const; + // Used for complex text, and does not utilize the glyph map cache. + const FontData* fontDataForCharacters(const UChar*, int length) const; + +private: + bool canUseGlyphCache(const TextRun&) const; + void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; +#if ENABLE(SVG_FONTS) + void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; + float floatWidthUsingSVGFont(const TextRun&) const; + FloatRect selectionRectForTextUsingSVGFont(const TextRun&, const IntPoint&, int h, int from, int to) const; + int offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const; +#endif + void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const; + void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const TextRun&, const FloatPoint&) const; + void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; + float floatWidthForSimpleText(const TextRun&, GlyphBuffer*) const; + float floatWidthForComplexText(const TextRun&) const; + int offsetForPositionForSimpleText(const TextRun&, int position, bool includePartialGlyphs) const; + int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const; + FloatRect selectionRectForSimpleText(const TextRun&, const IntPoint&, int h, int from, int to) const; + FloatRect selectionRectForComplexText(const TextRun&, const IntPoint&, int h, int from, int to) const; + void cachePrimaryFont() const; +#endif + friend struct WidthIterator; + + // Useful for debugging the different font rendering code paths. +public: +#if !PLATFORM(QT) + enum CodePath { Auto, Simple, Complex }; + static void setCodePath(CodePath); + static CodePath codePath; + + static const uint8_t gRoundingHackCharacterTable[256]; + static bool isRoundingHackCharacter(UChar32 c) + { + return (((c & ~0xFF) == 0 && gRoundingHackCharacterTable[c])); + } + + FontSelector* fontSelector() const; +#endif + static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; } + static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == 0x200e || c == 0x200f || c >= 0x202a && c <= 0x202e; } +private: + FontDescription m_fontDescription; +#if !PLATFORM(QT) + mutable RefPtr<FontFallbackList> m_fontList; + mutable HashMap<int, GlyphPageTreeNode*> m_pages; + mutable GlyphPageTreeNode* m_pageZero; + mutable const SimpleFontData* m_cachedPrimaryFont; +#endif + short m_letterSpacing; + short m_wordSpacing; +#if !PLATFORM(QT) + bool m_isPlatformFont; +#else + QFont m_font; + QFont m_scFont; + int m_spaceWidth; +#endif +}; + +} + +#endif diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp new file mode 100644 index 0000000..6abbb2e --- /dev/null +++ b/WebCore/platform/graphics/FontCache.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontCache.h" + +#include "Font.h" +#include "FontFallbackList.h" +#include "FontPlatformData.h" +#include "FontSelector.h" +#include "StringHash.h" +#include <wtf/HashMap.h> + +namespace WebCore { + +struct FontPlatformDataCacheKey { + FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, bool bold = false, bool italic = false, + bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode) + : m_family(family) + , m_size(size) + , m_bold(bold) + , m_italic(italic) + , m_printerFont(isPrinterFont) + , m_renderingMode(renderingMode) + { + } + + 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_renderingMode == other.m_renderingMode; + } + + AtomicString m_family; + unsigned m_size; + bool m_bold; + bool m_italic; + bool m_printerFont; + FontRenderingMode m_renderingMode; +}; + +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) + }; + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 4 * sizeof(unsigned) / sizeof(UChar)); +} + +struct FontPlatformDataCacheKeyHash { + static unsigned hash(const FontPlatformDataCacheKey& font) + { + return computeHash(font); + } + + static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> { + static const bool emptyValueIsZero = true; + static const bool needsDestruction = false; + static const FontPlatformDataCacheKey& deletedValue() + { + static FontPlatformDataCacheKey key(nullAtom, 0xFFFFFFFFU, false, false); + return key; + } + static const FontPlatformDataCacheKey& emptyValue() + { + static FontPlatformDataCacheKey key(nullAtom, 0, false, false); + return key; + } +}; + +typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache; + +static FontPlatformDataCache* gFontPlatformDataCache = 0; + +static const AtomicString& alternateFamilyName(const AtomicString& familyName) +{ + // Alias Courier <-> Courier New + static AtomicString courier("Courier"), courierNew("Courier New"); + if (equalIgnoringCase(familyName, courier)) + return courierNew; + if (equalIgnoringCase(familyName, courierNew)) + return courier; + + // Alias Times and Times New Roman. + static AtomicString times("Times"), timesNewRoman("Times New Roman"); + if (equalIgnoringCase(familyName, times)) + return timesNewRoman; + if (equalIgnoringCase(familyName, timesNewRoman)) + return times; + + // Alias Arial and Helvetica + static AtomicString arial("Arial"), helvetica("Helvetica"); + if (equalIgnoringCase(familyName, arial)) + return helvetica; + if (equalIgnoringCase(familyName, helvetica)) + return arial; + + return emptyAtom; +} + +FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fontDescription, + const AtomicString& familyName, + bool checkingAlternateName) +{ + if (!gFontPlatformDataCache) { + gFontPlatformDataCache = new FontPlatformDataCache; + platformInit(); + } + + FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.bold(), fontDescription.italic(), + fontDescription.usePrinterFont(), fontDescription.renderingMode()); + FontPlatformData* result = 0; + bool foundResult; + FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key); + if (it == gFontPlatformDataCache->end()) { + result = createFontPlatformData(fontDescription, familyName); + gFontPlatformDataCache->set(key, result); + foundResult = result; + } else { + result = it->second; + foundResult = true; + } + + if (!foundResult && !checkingAlternateName) { + // We were unable to find a font. We have a small set of fonts that we alias to other names, + // e.g., Arial/Helvetica, Courier/Courier New, etc. Try looking up the font under the aliased name. + const AtomicString& alternateName = alternateFamilyName(familyName); + if (!alternateName.isEmpty()) + result = getCachedFontPlatformData(fontDescription, alternateName, true); + if (result) + gFontPlatformDataCache->set(key, new FontPlatformData(*result)); // Cache the result under the old name. + } + + return result; +} + +struct FontDataCacheKeyHash { + static unsigned hash(const FontPlatformData& platformData) + { + return platformData.hash(); + } + + static bool equal(const FontPlatformData& a, const FontPlatformData& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> { + static const bool emptyValueIsZero = true; + static const bool needsDestruction = false; + static const FontPlatformData& deletedValue() + { + static FontPlatformData key = FontPlatformData::Deleted(); + return key; + } + static const FontPlatformData& emptyValue() + { + static FontPlatformData key; + return key; + } +}; + +typedef HashMap<FontPlatformData, SimpleFontData*, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache; + +static FontDataCache* gFontDataCache = 0; + +SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* platformData) +{ + if (!platformData) + return 0; + + if (!gFontDataCache) + gFontDataCache = new FontDataCache; + + SimpleFontData* result = gFontDataCache->get(*platformData); + if (!result) { + result = new SimpleFontData(*platformData); + gFontDataCache->set(*platformData, result); + } + + return result; +} + +const FontData* FontCache::getFontData(const Font& font, int& familyIndex, FontSelector* fontSelector) +{ + FontPlatformData* result = 0; + + int startIndex = familyIndex; + const FontFamily* startFamily = &font.fontDescription().family(); + for (int i = 0; startFamily && i < startIndex; i++) + startFamily = startFamily->next(); + const FontFamily* currFamily = startFamily; + while (currFamily && !result) { + familyIndex++; + if (currFamily->family().length()) { + if (fontSelector) { + FontData* data = fontSelector->getFontData(font.fontDescription(), currFamily->family()); + if (data) + return data; + } + result = getCachedFontPlatformData(font.fontDescription(), currFamily->family()); + } + currFamily = currFamily->next(); + } + + if (!currFamily) + familyIndex = cAllFamiliesScanned; + + if (!result) + // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform. + // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the + // Geeza Pro font. + result = getSimilarFontPlatformData(font); + + if (!result && startIndex == 0) { + // If it's the primary font that we couldn't find, we try the following. In all other cases, we will + // just use per-character system fallback. + + if (fontSelector) { + // Try the user's preferred standard font. + if (FontData* data = fontSelector->getFontData(font.fontDescription(), "-webkit-standard")) + return data; + } + + // Still no result. Hand back our last resort fallback font. + result = getLastResortFallbackFont(font.fontDescription()); + } + + // Now that we have a result, we need to go from FontPlatformData -> FontData. + return getCachedFontData(result); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h new file mode 100644 index 0000000..e1a704b --- /dev/null +++ b/WebCore/platform/graphics/FontCache.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontCache_h +#define FontCache_h + +#include <wtf/unicode/Unicode.h> + +#if PLATFORM(WIN) +#include <objidl.h> +#include <mlang.h> +#endif + +namespace WebCore +{ + +class AtomicString; +class Font; +class FontPlatformData; +class FontData; +class FontDescription; +class FontSelector; +class SimpleFontData; + +class FontCache { +public: + static const FontData* getFontData(const Font&, int& familyIndex, FontSelector*); + + // This method is implemented by the platform. + static const SimpleFontData* getFontDataForCharacters(const Font&, const UChar* characters, int length); + + // Also implemented by the platform. + static void platformInit(); + +#if PLATFORM(WIN) + static IMLangFontLink2* getFontLinkInterface(); +#endif + + static bool fontExists(const FontDescription&, const AtomicString& family); + + static FontPlatformData* getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName = false); + static SimpleFontData* getCachedFontData(const FontPlatformData*); + static FontPlatformData* getLastResortFallbackFont(const FontDescription&); + +private: + // These methods are implemented by each platform. + static FontPlatformData* getSimilarFontPlatformData(const Font&); + static FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family); + + friend class SimpleFontData; + friend class FontFallbackList; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/FontData.cpp b/WebCore/platform/graphics/FontData.cpp new file mode 100644 index 0000000..c40e13c --- /dev/null +++ b/WebCore/platform/graphics/FontData.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontData.h" + +namespace WebCore { + +FontData::~FontData() +{ +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/FontData.h b/WebCore/platform/graphics/FontData.h new file mode 100644 index 0000000..352d965 --- /dev/null +++ b/WebCore/platform/graphics/FontData.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontData_h +#define FontData_h + +#include <wtf/Noncopyable.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class SimpleFontData; + +class FontData : Noncopyable { +public: + virtual ~FontData(); + + virtual const SimpleFontData* fontDataForCharacter(UChar32) const = 0; + virtual bool containsCharacters(const UChar*, int length) const = 0; + virtual bool isCustomFont() const = 0; + virtual bool isLoading() const = 0; + virtual bool isSegmented() const = 0; +}; + +} // namespace WebCore + +#endif // FontData_h diff --git a/WebCore/platform/graphics/FontDescription.h b/WebCore/platform/graphics/FontDescription.h new file mode 100644 index 0000000..6bb232e --- /dev/null +++ b/WebCore/platform/graphics/FontDescription.h @@ -0,0 +1,119 @@ +/* + * 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. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIother.m_ If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USm_ + * + */ + +#ifndef FontDescription_h +#define FontDescription_h + +#include "FontFamily.h" + +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 }; + +class FontDescription { +public: + enum GenericFamilyType { NoFamily, StandardFamily, SerifFamily, SansSerifFamily, + MonospaceFamily, CursiveFamily, FantasyFamily }; + + FontDescription() + : m_specifiedSize(0), m_computedSize(0), + m_italic(false), m_smallCaps(false), m_isAbsoluteSize(false), m_weight(cNormalWeight), + m_genericFamily(NoFamily), m_usePrinterFont(false), m_renderingMode(NormalRenderingMode), m_keywordSize(0) + {} + + bool operator==(const FontDescription&) const; + bool operator!=(const FontDescription& other) const { return !(*this == other); } + + const FontFamily& family() const { return m_familyList; } + FontFamily& firstFamily() { return m_familyList; } + float specifiedSize() const { return m_specifiedSize; } + float computedSize() const { return m_computedSize; } + bool italic() const { return m_italic; } + 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; } + 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; } + + 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 setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; } + void setUsePrinterFont(bool p) { m_usePrinterFont = p; } + void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; } + void setKeywordSize(int s) { m_keywordSize = s; } + +private: + FontFamily m_familyList; // The list of font families to be used. + + float m_specifiedSize; // Specified CSS value. Independent of rendering issues such as integer + // rounding, minimum font sizes, and zooming. + float m_computedSize; // Computed size adjusted for the minimum font size and the zoom factor. + + bool m_italic : 1; + bool m_smallCaps : 1; + bool m_isAbsoluteSize : 1; // Whether or not CSS specified an explicit size + // (logical sizes like "medium" don't count). + unsigned m_weight : 8; + unsigned m_genericFamily : 3; // GenericFamilyType + bool m_usePrinterFont : 1; + + unsigned m_renderingMode : 1; // Used to switch between CG and GDI text on Windows. + + int m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, + // then we can accurately translate across different generic families to adjust for different preference settings + // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>). +}; + +inline bool FontDescription::operator==(const FontDescription& other) const +{ + return m_familyList == other.m_familyList + && m_specifiedSize == other.m_specifiedSize + && m_computedSize == other.m_computedSize + && m_italic == other.m_italic + && m_smallCaps == other.m_smallCaps + && m_isAbsoluteSize == other.m_isAbsoluteSize + && m_weight == other.m_weight + && m_genericFamily == other.m_genericFamily + && m_usePrinterFont == other.m_usePrinterFont + && m_renderingMode == other.m_renderingMode + && m_keywordSize == other.m_keywordSize; +} + +} + +#endif diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp new file mode 100644 index 0000000..0fdd99c --- /dev/null +++ b/WebCore/platform/graphics/FontFallbackList.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontFallbackList.h" + +#include "Font.h" +#include "FontCache.h" +#include "SegmentedFontData.h" + +namespace WebCore { + +FontFallbackList::FontFallbackList() + : RefCounted<FontFallbackList>(0) + , m_familyIndex(0) + , m_pitch(UnknownPitch) + , m_loadingCustomFonts(false) + , m_fontSelector(0) +{ +} + +void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector) +{ + m_fontList.clear(); + m_familyIndex = 0; + m_pitch = UnknownPitch; + m_loadingCustomFonts = false; + m_fontSelector = fontSelector; +} + +void FontFallbackList::determinePitch(const Font* font) const +{ + const FontData* fontData = primaryFont(font); + if (!fontData->isSegmented()) + m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch(); + else { + const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); + unsigned numRanges = segmentedFontData->numRanges(); + if (numRanges == 1) + m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch(); + else + m_pitch = VariablePitch; + } +} + +const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realizedFontIndex) const +{ + if (realizedFontIndex < m_fontList.size()) + return m_fontList[realizedFontIndex]; // This fallback font is already in our list. + + // Make sure we're not passing in some crazy value here. + ASSERT(realizedFontIndex == m_fontList.size()); + + if (m_familyIndex == cAllFamiliesScanned) + return 0; + + // Ask the font cache for the font data. + // We are obtaining this font for the first time. We keep track of the families we've looked at before + // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our + // |m_familyIndex| as it scans for the right font to make. + const FontData* result = FontCache::getFontData(*font, m_familyIndex, m_fontSelector.get()); + if (result) { + m_fontList.append(result); + if (result->isLoading()) + m_loadingCustomFonts = true; + } + return result; +} + +const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const UChar* characters, int length) const +{ + // This method is only called when the primary font does not contain the characters we need. + // Begin our search at position 1. + unsigned realizedFontIndex = 1; + const FontData* fontData = fontDataAt(font, realizedFontIndex); + while (fontData && !fontData->containsCharacters(characters, length)) + fontData = fontDataAt(font, ++realizedFontIndex); + + if (!fontData) + fontData = FontCache::getFontDataForCharacters(*font, characters, length); + + return fontData; +} + +void FontFallbackList::setPlatformFont(const FontPlatformData& platformData) +{ + m_familyIndex = cAllFamiliesScanned; + m_fontList.append(FontCache::getCachedFontData(&platformData)); +} + +} diff --git a/WebCore/platform/graphics/FontFallbackList.h b/WebCore/platform/graphics/FontFallbackList.h new file mode 100644 index 0000000..38128a2 --- /dev/null +++ b/WebCore/platform/graphics/FontFallbackList.h @@ -0,0 +1,72 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +// This file has no guards on purpose in order to detect redundant includes. This is a private header +// and so this may catch someone trying to include this file in public cpp files. + +#include "FontSelector.h" +#include "SimpleFontData.h" +#include <wtf/Forward.h> + +namespace WebCore { + +class Font; +class GraphicsContext; +class IntRect; +class FontDescription; +class FontPlatformData; +class FontSelector; + +const int cAllFamiliesScanned = -1; + +class FontFallbackList : public RefCounted<FontFallbackList> { +public: + FontFallbackList(); + + void invalidate(PassRefPtr<FontSelector>); + + bool isFixedPitch(const Font* f) const { if (m_pitch == UnknownPitch) determinePitch(f); return m_pitch == FixedPitch; }; + void determinePitch(const Font*) const; + + bool loadingCustomFonts() const { return m_loadingCustomFonts; } + + FontSelector* fontSelector() const { return m_fontSelector.get(); } + +private: + 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; + mutable int m_familyIndex; + mutable Pitch m_pitch; + mutable bool m_loadingCustomFonts; + RefPtr<FontSelector> m_fontSelector; + + friend class Font; +}; + +} + diff --git a/WebCore/platform/graphics/FontFamily.cpp b/WebCore/platform/graphics/FontFamily.cpp new file mode 100644 index 0000000..c87c661 --- /dev/null +++ b/WebCore/platform/graphics/FontFamily.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004 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 "FontFamily.h" + +namespace WebCore { + +FontFamily::FontFamily(const FontFamily& other) + : RefCounted<FontFamily>(0) + , m_family(other.m_family) + , m_next(other.m_next) +{ +} + +FontFamily& FontFamily::operator=(const FontFamily& other) +{ + m_family = other.m_family; + m_next = other.m_next; + return *this; +} + +bool FontFamily::operator==(const FontFamily &compareFontFamily) const +{ + if ((!m_next && compareFontFamily.m_next) || + (m_next && !compareFontFamily.m_next) || + ((m_next && compareFontFamily.m_next) && (*m_next != *(compareFontFamily.m_next)))) + return false; + + return m_family == compareFontFamily.m_family; +} + +} diff --git a/WebCore/platform/graphics/FontFamily.h b/WebCore/platform/graphics/FontFamily.h new file mode 100644 index 0000000..7a382cc --- /dev/null +++ b/WebCore/platform/graphics/FontFamily.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontFamily_h +#define FontFamily_h + +#include "AtomicString.h" +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class FontFamily : public RefCounted<FontFamily> { +public: + FontFamily() : RefCounted<FontFamily>(0) { } + + FontFamily(const FontFamily&); + FontFamily& operator=(const FontFamily&); + + void setFamily(const AtomicString& family) { m_family = family; } + const AtomicString& family() const { return m_family; } + bool familyIsEmpty() const { return m_family.isEmpty(); } + + FontFamily* next() { return m_next.get(); } + const FontFamily* next() const { return m_next.get(); } + + void appendFamily(PassRefPtr<FontFamily> family) { m_next = family; } + + bool operator==(const FontFamily&) const; + bool operator!=(const FontFamily& x) const { return !(*this == x); } + +private: + AtomicString m_family; + RefPtr<FontFamily> m_next; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/FontSelector.h b/WebCore/platform/graphics/FontSelector.h new file mode 100644 index 0000000..b0e9dfa --- /dev/null +++ b/WebCore/platform/graphics/FontSelector.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontSelector_h +#define FontSelector_h + +#include <wtf/RefCounted.h> + +namespace WebCore { + +class AtomicString; +class FontData; +class FontDescription; + +class FontSelector : public RefCounted<FontSelector> { +public: + FontSelector() : RefCounted<FontSelector>(0) { } + virtual ~FontSelector() { } + virtual FontData* getFontData(const FontDescription&, const AtomicString& familyName) = 0; +}; + +} // namespace WebCore + +#endif // FontSelector_h diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h new file mode 100644 index 0000000..f65996d --- /dev/null +++ b/WebCore/platform/graphics/GlyphBuffer.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GlyphBuffer_h +#define GlyphBuffer_h + +#include "FloatSize.h" + +#if PLATFORM(CG) +#include <ApplicationServices/ApplicationServices.h> +#elif PLATFORM(CAIRO) +#include <cairo.h> +#endif + +#include <wtf/Vector.h> + +namespace WebCore { + +typedef unsigned short Glyph; +class SimpleFontData; + +#if PLATFORM(CG) +typedef Glyph GlyphBufferGlyph; +typedef CGSize GlyphBufferAdvance; +#elif PLATFORM(CAIRO) +typedef cairo_glyph_t GlyphBufferGlyph; +typedef FloatSize GlyphBufferAdvance; +#elif PLATFORM(WX) +typedef Glyph GlyphBufferGlyph; +typedef FloatSize GlyphBufferAdvance; +#elif PLATFORM(QT) +typedef unsigned short GlyphBufferGlyph; +typedef FloatSize GlyphBufferAdvance; +#endif + +class GlyphBuffer { +public: + bool isEmpty() const { return m_fontData.isEmpty(); } + int size() const { return m_fontData.size(); } + + void clear() + { + m_fontData.clear(); + m_glyphs.clear(); + m_advances.clear(); +#if PLATFORM(WIN) + m_offsets.clear(); +#endif + } + + GlyphBufferGlyph* glyphs(int from) { return m_glyphs.data() + from; } + GlyphBufferAdvance* advances(int from) { return m_advances.data() + from; } + const GlyphBufferGlyph* glyphs(int from) const { return m_glyphs.data() + from; } + const GlyphBufferAdvance* advances(int from) const { return m_advances.data() + from; } + + const SimpleFontData* fontDataAt(int index) const { return m_fontData[index]; } + + void swap(int index1, int index2) + { + const SimpleFontData* f = m_fontData[index1]; + m_fontData[index1] = m_fontData[index2]; + m_fontData[index2] = f; + + GlyphBufferGlyph g = m_glyphs[index1]; + m_glyphs[index1] = m_glyphs[index2]; + m_glyphs[index2] = g; + + GlyphBufferAdvance s = m_advances[index1]; + m_advances[index1] = m_advances[index2]; + m_advances[index2] = s; + +#if PLATFORM(WIN) + FloatSize offset = m_offsets[index1]; + m_offsets[index1] = m_offsets[index2]; + m_offsets[index2] = offset; +#endif + } + + Glyph glyphAt(int index) const + { +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(WX) + return m_glyphs[index]; +#elif PLATFORM(CAIRO) + return m_glyphs[index].index; +#endif + } + + float advanceAt(int index) const + { +#if PLATFORM(CG) + return m_advances[index].width; +#elif PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) + return m_advances[index].width(); +#endif + } + + FloatSize offsetAt(int index) const + { +#if PLATFORM(WIN) + return m_offsets[index]; +#else + return FloatSize(); +#endif + } + + void add(Glyph glyph, const SimpleFontData* font, float width, const FloatSize* offset = 0) + { + m_fontData.append(font); +#if PLATFORM(CG) + m_glyphs.append(glyph); + CGSize advance; + advance.width = width; + advance.height = 0; + m_advances.append(advance); +#elif PLATFORM(CAIRO) + cairo_glyph_t cairoGlyph; + cairoGlyph.index = glyph; + m_glyphs.append(cairoGlyph); + m_advances.append(FloatSize(width, 0)); +#elif PLATFORM(QT) || PLATFORM(WX) + m_glyphs.append(glyph); + m_advances.append(FloatSize(width, 0)); +#endif +#if PLATFORM(WIN) + if (offset) + m_offsets.append(*offset); + else + m_offsets.append(FloatSize()); +#endif + } + +private: + Vector<const SimpleFontData*, 2048> m_fontData; + Vector<GlyphBufferGlyph, 2048> m_glyphs; + Vector<GlyphBufferAdvance, 2048> m_advances; +#if PLATFORM(WIN) + Vector<FloatSize, 2048> m_offsets; +#endif +}; + +} +#endif diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp new file mode 100644 index 0000000..53c94b8 --- /dev/null +++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphPageTreeNode.h" + +#include "CharacterNames.h" +#include "SegmentedFontData.h" +#include "SimpleFontData.h" +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +using std::max; +using std::min; + +HashMap<int, GlyphPageTreeNode*>* GlyphPageTreeNode::roots = 0; +GlyphPageTreeNode* GlyphPageTreeNode::pageZeroRoot = 0; + +GlyphPageTreeNode* GlyphPageTreeNode::getRoot(unsigned pageNumber) +{ + static bool initialized; + if (!initialized) { + initialized = true; + roots = new HashMap<int, GlyphPageTreeNode*>; + pageZeroRoot = new GlyphPageTreeNode; + } + + GlyphPageTreeNode* node = pageNumber ? roots->get(pageNumber) : pageZeroRoot; + if (!node) { + node = new GlyphPageTreeNode; +#ifndef NDEBUG + node->m_pageNumber = pageNumber; +#endif + if (pageNumber) + roots->set(pageNumber, node); + else + pageZeroRoot = node; + } + return node; +} + +void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData) +{ + // Enumerate all the roots and prune any tree that contains our custom font data. + if (roots) { + HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end(); + for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); it != end; ++it) + it->second->pruneCustomFontData(fontData); + } + + if (pageZeroRoot) + pageZeroRoot->pruneCustomFontData(fontData); +} + +GlyphPageTreeNode::~GlyphPageTreeNode() +{ + deleteAllValues(m_children); + delete m_systemFallbackChild; +} + +void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNumber) +{ + ASSERT(!m_page); + + // This function must not be called for the root of the tree, because that + // level does not contain any glyphs. + ASSERT(m_level > 0 && m_parent); + + // The parent's page will be 0 if we are level one or the parent's font data + // did not contain any glyphs for that page. + GlyphPage* parentPage = m_parent->page(); + + // NULL FontData means we're being asked for the system fallback font. + if (fontData) { + if (m_level == 1) { + // Children of the root hold pure pages. These will cover only one + // font data's glyphs, and will have glyph index 0 if the font data does not + // contain the glyph. + unsigned start = pageNumber * GlyphPage::size; + UChar buffer[GlyphPage::size * 2 + 2]; + unsigned bufferLength; + unsigned i; + + // Fill in a buffer with the entire "page" of characters that we want to look up glyphs for. + if (start < 0x10000) { + bufferLength = GlyphPage::size; + for (i = 0; i < GlyphPage::size; i++) + buffer[i] = start + i; + + if (start == 0) { + // Control characters must not render at all. + for (i = 0; i < 0x20; ++i) + buffer[i] = zeroWidthSpace; + for (i = 0x7F; i < 0xA0; i++) + buffer[i] = zeroWidthSpace; + + // \n, \t, and nonbreaking space must render as a space. + buffer[(int)'\n'] = ' '; + buffer[(int)'\t'] = ' '; + buffer[noBreakSpace] = ' '; + } else if (start == (leftToRightMark & ~(GlyphPage::size - 1))) { + // LRM, RLM, LRE, RLE and PDF must not render at all. + buffer[leftToRightMark - start] = zeroWidthSpace; + buffer[rightToLeftMark - start] = zeroWidthSpace; + buffer[leftToRightEmbed - start] = zeroWidthSpace; + buffer[rightToLeftEmbed - start] = zeroWidthSpace; + buffer[leftToRightOverride - start] = zeroWidthSpace; + buffer[rightToLeftOverride - start] = zeroWidthSpace; + buffer[popDirectionalFormatting - start] = zeroWidthSpace; + } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) { + // Object replacement character must not render at all. + buffer[objectReplacementCharacter - start] = zeroWidthSpace; + } + } else { + bufferLength = GlyphPage::size * 2; + for (i = 0; i < GlyphPage::size; i++) { + int c = i + start; + buffer[i * 2] = U16_LEAD(c); + buffer[i * 2 + 1] = U16_TRAIL(c); + } + } + + m_page = new GlyphPage(this); + + // Now that we have a buffer full of characters, we want to get back an array + // of glyph indices. This part involves calling into the platform-specific + // routine of our glyph map for actually filling in the page with the glyphs. + // Success is not guaranteed. For example, Times fails to fill page 260, giving glyph data + // for only 128 out of 256 characters. + bool haveGlyphs; + if (fontData->isSegmented()) { + haveGlyphs = false; + + const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); + unsigned numRanges = segmentedFontData->numRanges(); + bool zeroFilled = false; + 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 (!zeroFilled) { + if (from > 0 || to < static_cast<int>(GlyphPage::size)) { + for (unsigned i = 0; i < GlyphPage::size; i++) + m_page->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()); + } + } + } else + haveGlyphs = m_page->fill(0, GlyphPage::size, buffer, bufferLength, static_cast<const SimpleFontData*>(fontData)); + + if (!haveGlyphs) + m_page = 0; + } else if (parentPage && parentPage->owner() != m_parent) { + // The page we're overriding may not be owned by our parent node. + // This happens when our parent node provides no useful overrides + // and just copies the pointer to an already-existing page (see + // below). + // + // We want our override to be shared by all nodes that reference + // that page to avoid duplication, and so standardize on having the + // page's owner collect all the overrides. Call getChild on the + // page owner with the desired font data (this will populate + // the page) and then reference it. + m_page = parentPage->owner()->getChild(fontData, pageNumber)->page(); + } else { + // Get the pure page for the fallback font (at level 1 with no + // overrides). getRootChild will always create a page if one + // doesn't exist, but the page doesn't necessarily have glyphs + // (this pointer may be 0). + GlyphPage* fallbackPage = getRootChild(fontData, pageNumber)->page(); + if (!parentPage) { + // When the parent has no glyphs for this page, we can easily + // override it just by supplying the glyphs from our font. + m_page = fallbackPage; + } else if (!fallbackPage) { + // When our font has no glyphs for this page, we can just reference the + // parent page. + m_page = parentPage; + } else { + // Combine the parent's glyphs and ours to form a new more complete page. + m_page = new GlyphPage(this); + + // Overlay the parent page on the fallback page. Check if the fallback font + // has added anything. + bool newGlyphs = false; + for (unsigned i = 0; i < GlyphPage::size; i++) { + if (parentPage->m_glyphs[i].glyph) + m_page->m_glyphs[i] = parentPage->m_glyphs[i]; + else if (fallbackPage->m_glyphs[i].glyph) { + m_page->m_glyphs[i] = fallbackPage->m_glyphs[i]; + newGlyphs = true; + } else { + const GlyphData data = { 0, 0 }; + m_page->m_glyphs[i] = data; + } + } + + if (!newGlyphs) + // We didn't override anything, so our override is just the parent page. + m_page = parentPage; + } + } + } else { + m_page = new GlyphPage(this); + // System fallback. Initialized with the parent's page here, as individual + // entries may use different fonts depending on character. If the Font + // ever finds it needs a glyph out of the system fallback page, it will + // ask the system for the best font to use and fill that glyph in for us. + if (parentPage) + memcpy(m_page->m_glyphs, parentPage->m_glyphs, GlyphPage::size * sizeof(m_page->m_glyphs[0])); + else { + const GlyphData data = { 0, 0 }; + for (unsigned i = 0; i < GlyphPage::size; i++) + m_page->m_glyphs[i] = data; + } + } +} + +GlyphPageTreeNode* GlyphPageTreeNode::getChild(const FontData* fontData, unsigned pageNumber) +{ + ASSERT(fontData || !m_isSystemFallback); + ASSERT(pageNumber == m_pageNumber); + + GlyphPageTreeNode* child = fontData ? m_children.get(fontData) : m_systemFallbackChild; + if (!child) { + child = new GlyphPageTreeNode; + child->m_parent = this; + child->m_level = m_level + 1; + if (fontData && fontData->isCustomFont()) { + for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent) + curr->m_customFontCount++; + } + +#ifndef NDEBUG + child->m_pageNumber = m_pageNumber; +#endif + if (fontData) + m_children.set(fontData, child); + else { + m_systemFallbackChild = child; + child->m_isSystemFallback = true; + } + child->initializePage(fontData, pageNumber); + } + return child; +} + +void GlyphPageTreeNode::pruneCustomFontData(const FontData* fontData) +{ + if (!fontData || !m_customFontCount) + return; + + // Prune any branch that contains this FontData. + GlyphPageTreeNode* node = m_children.get(fontData); + if (node) { + m_children.remove(fontData); + unsigned fontCount = node->m_customFontCount + 1; + delete node; + for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent) + curr->m_customFontCount -= fontCount; + } + + // Check any branches that remain that still have custom fonts underneath them. + if (!m_customFontCount) + return; + HashMap<const FontData*, GlyphPageTreeNode*>::iterator end = m_children.end(); + for (HashMap<const FontData*, GlyphPageTreeNode*>::iterator it = m_children.begin(); it != end; ++it) + it->second->pruneCustomFontData(fontData); +} + +} diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.h b/WebCore/platform/graphics/GlyphPageTreeNode.h new file mode 100644 index 0000000..40b8154 --- /dev/null +++ b/WebCore/platform/graphics/GlyphPageTreeNode.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GlyphPageTreeNode_h +#define GlyphPageTreeNode_h + +#include <wtf/RefCounted.h> +#include <wtf/unicode/Unicode.h> +#include <wtf/HashMap.h> + +namespace WebCore { + +class FontData; +class GlyphPageTreeNode; +class SimpleFontData; + +typedef unsigned short Glyph; + +// Holds the glyph index and the corresponding SimpleFontData information for a given +// character. +struct GlyphData { + Glyph glyph; + const SimpleFontData* fontData; +}; + +// A GlyphPage contains a fixed-size set of GlyphData mappings for a contiguous +// range of characters in the Unicode code space. GlyphPages are indexed +// starting from 0 and incrementing for each 256 glyphs. +// +// One page may actually include glyphs from other fonts if the characters are +// missing in the parimary font. It is owned by exactly one GlyphPageTreeNode, +// although multiple nodes may reference it as their "page" if they are supposed +// to be overriding the parent's node, but provide no additional information. +struct GlyphPage : public RefCounted<GlyphPage> { + GlyphPage() + : RefCounted<GlyphPage>(0) + , m_owner(0) + { + } + + GlyphPage(GlyphPageTreeNode* owner) + : RefCounted<GlyphPage>(0) + , m_owner(owner) + { + } + + static const size_t size = 256; // Covers Latin-1 in a single page. + GlyphData m_glyphs[size]; + GlyphPageTreeNode* m_owner; + + const GlyphData& glyphDataForCharacter(UChar32 c) const { return m_glyphs[c % size]; } + void setGlyphDataForCharacter(UChar32 c, Glyph g, const SimpleFontData* f) + { + setGlyphDataForIndex(c % size, g, f); + } + void setGlyphDataForIndex(unsigned index, Glyph g, const SimpleFontData* f) + { + ASSERT(index < size); + m_glyphs[index].glyph = g; + m_glyphs[index].fontData = f; + } + GlyphPageTreeNode* owner() const { return m_owner; } + // Implemented by the platform. + bool fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const SimpleFontData* fontData); +}; + +// The glyph page tree is a data structure that maps (FontData, glyph page number) +// to a GlyphPage. Level 0 (the "root") is special. There is one root +// GlyphPageTreeNode for each glyph page number. The roots do not have a +// GlyphPage associated with them, and their initializePage() function is never +// called to fill the glyphs. +// +// Each root node maps a FontData pointer to another GlyphPageTreeNode at +// level 1 (the "root child") that stores the actual glyphs for a specific font data. +// These nodes will only have a GlyphPage if they have glyphs for that range. +// +// Levels greater than one correspond to subsequent levels of the fallback list +// for that font. These levels override their parent's page of glyphs by +// filling in holes with the new font (thus making a more complete page). +// +// A NULL FontData pointer corresponds to the system fallback +// font. It is tracked separately from the regular pages and overrides so that +// the glyph pages do not get polluted with these last-resort glyphs. The +// system fallback page is not populated at construction like the other pages, +// but on demand for each glyph, because the system may need to use different +// fallback fonts for each. This lazy population is done by the Font. +class GlyphPageTreeNode { +public: + GlyphPageTreeNode() + : m_parent(0) + , m_level(0) + , m_isSystemFallback(false) + , m_systemFallbackChild(0) + , m_customFontCount(0) +#ifndef NDEBUG + , m_pageNumber(0) +#endif + { + } + + ~GlyphPageTreeNode(); + + static HashMap<int, GlyphPageTreeNode*>* roots; + static GlyphPageTreeNode* pageZeroRoot; + + static GlyphPageTreeNode* getRootChild(const FontData* fontData, unsigned pageNumber) + { + return getRoot(pageNumber)->getChild(fontData, pageNumber); + } + + static void pruneTreeCustomFontData(const FontData*); + + void pruneCustomFontData(const FontData*); + + GlyphPageTreeNode* parent() const { return m_parent; } + GlyphPageTreeNode* getChild(const FontData*, unsigned pageNumber); + + // Returns a page of glyphs (or NULL if there are no glyphs in this page's character range). + GlyphPage* page() const { return m_page.get(); } + + // Returns the level of this node. See class-level comment. + unsigned level() const { return m_level; } + + // The system fallback font has special rules (see above). + bool isSystemFallback() const { return m_isSystemFallback; } + +private: + static GlyphPageTreeNode* getRoot(unsigned pageNumber); + void initializePage(const FontData*, unsigned pageNumber); + + GlyphPageTreeNode* m_parent; + RefPtr<GlyphPage> m_page; + unsigned m_level; + bool m_isSystemFallback; + HashMap<const FontData*, GlyphPageTreeNode*> m_children; + GlyphPageTreeNode* m_systemFallbackChild; + unsigned m_customFontCount; + +#ifndef NDEBUG + unsigned m_pageNumber; +#endif +}; + +} // namespace WebCore + +#endif // GlyphPageTreeNode_h diff --git a/WebCore/platform/graphics/GlyphWidthMap.cpp b/WebCore/platform/graphics/GlyphWidthMap.cpp new file mode 100644 index 0000000..6e8d68d --- /dev/null +++ b/WebCore/platform/graphics/GlyphWidthMap.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphWidthMap.h" + +namespace WebCore +{ + +float GlyphWidthMap::widthForGlyph(Glyph g) +{ + unsigned pageNumber = (g / GlyphWidthPage::size); + GlyphWidthPage* page = locatePage(pageNumber); + if (page) + return page->widthForGlyph(g); + return cGlyphWidthUnknown; +} + +void GlyphWidthMap::setWidthForGlyph(Glyph glyph, float width) +{ + unsigned pageNumber = (glyph / GlyphWidthPage::size); + GlyphWidthPage* page = locatePage(pageNumber); + if (page) + page->setWidthForGlyph(glyph, width); +} + +inline GlyphWidthMap::GlyphWidthPage* GlyphWidthMap::locatePage(unsigned pageNumber) +{ + GlyphWidthPage* page; + if (pageNumber == 0) { + if (m_filledPrimaryPage) + return &m_primaryPage; + page = &m_primaryPage; + m_filledPrimaryPage = true; + } else { + if (m_pages) { + GlyphWidthPage* result = m_pages->get(pageNumber); + if (result) + return result; + } + page = new GlyphWidthPage; + if (!m_pages) + m_pages = new HashMap<int, GlyphWidthPage*>; + m_pages->set(pageNumber, page); + } + + // Fill in the whole page with the unknown glyph width value. + for (unsigned i = 0; i < GlyphWidthPage::size; i++) + page->setWidthForIndex(i, cGlyphWidthUnknown); + + return page; +} + +} diff --git a/WebCore/platform/graphics/GlyphWidthMap.h b/WebCore/platform/graphics/GlyphWidthMap.h new file mode 100644 index 0000000..1633769 --- /dev/null +++ b/WebCore/platform/graphics/GlyphWidthMap.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GlyphWidthMap_h +#define GlyphWidthMap_h + +#include <wtf/unicode/Unicode.h> +#include <wtf/Noncopyable.h> +#include <wtf/HashMap.h> + +namespace WebCore { + +typedef unsigned short Glyph; + +const float cGlyphWidthUnknown = -1; + +class GlyphWidthMap : Noncopyable { +public: + GlyphWidthMap() : m_filledPrimaryPage(false), m_pages(0) {} + ~GlyphWidthMap() { if (m_pages) { deleteAllValues(*m_pages); delete m_pages; } } + + float widthForGlyph(Glyph); + void setWidthForGlyph(Glyph, float); + +private: + struct GlyphWidthPage { + static const size_t size = 256; // Usually covers Latin-1 in a single page. + float m_widths[size]; + + float widthForGlyph(Glyph g) const { return m_widths[g % size]; } + void setWidthForGlyph(Glyph g, float w) + { + setWidthForIndex(g % size, w); + } + void setWidthForIndex(unsigned index, float w) + { + m_widths[index] = w; + } + }; + + GlyphWidthPage* locatePage(unsigned page); + + bool m_filledPrimaryPage; + GlyphWidthPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255. + HashMap<int, GlyphWidthPage*>* m_pages; +}; + +} +#endif diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp new file mode 100644 index 0000000..2f2f97e --- /dev/null +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#include "BidiResolver.h" +#include "Font.h" + +using namespace std; + +namespace WebCore { + +class TextRunIterator { +public: + TextRunIterator() + : m_textRun(0) + , m_offset(0) + { + } + + TextRunIterator(const TextRun* textRun, unsigned offset) + : m_textRun(textRun) + , m_offset(offset) + { + } + + TextRunIterator(const TextRunIterator& other) + : m_textRun(other.m_textRun) + , m_offset(other.m_offset) + { + } + + unsigned offset() const { return m_offset; } + void increment(BidiResolver<TextRunIterator, BidiCharacterRun>&) { m_offset++; } + bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); } + UChar current() const { return (*m_textRun)[m_offset]; } + WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); } + + bool operator==(const TextRunIterator& other) + { + return m_offset == other.m_offset && m_textRun == other.m_textRun; + } + + bool operator!=(const TextRunIterator& other) { return !operator==(other); } + +private: + const TextRun* m_textRun; + int m_offset; +}; + +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; +} + +void GraphicsContext::destroyGraphicsContextPrivate(GraphicsContextPrivate* deleteMe) +{ + delete deleteMe; +} + +void GraphicsContext::save() +{ + if (paintingDisabled()) + return; + + m_common->stack.append(m_common->state); + + savePlatformState(); +} + +void GraphicsContext::restore() +{ + if (paintingDisabled()) + return; + + if (m_common->stack.isEmpty()) { + LOG_ERROR("ERROR void GraphicsContext::restore() stack is empty"); + return; + } + m_common->state = m_common->stack.last(); + m_common->stack.removeLast(); + + restorePlatformState(); +} + +const Font& GraphicsContext::font() const +{ + return m_common->state.font; +} + +void GraphicsContext::setFont(const Font& aFont) +{ + m_common->state.font = aFont; + setPlatformFont(aFont); +} + +void GraphicsContext::setStrokeThickness(float thickness) +{ + m_common->state.strokeThickness = thickness; + setPlatformStrokeThickness(thickness); +} + +void GraphicsContext::setStrokeStyle(const StrokeStyle& style) +{ + m_common->state.strokeStyle = style; + setPlatformStrokeStyle(style); +} + +void GraphicsContext::setStrokeColor(const Color& color) +{ + m_common->state.strokeColor = color; + setPlatformStrokeColor(color); +} + +float GraphicsContext::strokeThickness() const +{ + return m_common->state.strokeThickness; +} + +StrokeStyle GraphicsContext::strokeStyle() const +{ + return m_common->state.strokeStyle; +} + +Color GraphicsContext::strokeColor() const +{ + return m_common->state.strokeColor; +} + +void GraphicsContext::setFillColor(const Color& color) +{ + m_common->state.fillColor = color; + setPlatformFillColor(color); +} + +Color GraphicsContext::fillColor() const +{ + return m_common->state.fillColor; +} + +bool GraphicsContext::updatingControlTints() const +{ + return m_common->m_updatingControlTints; +} + +void GraphicsContext::setUpdatingControlTints(bool b) +{ + setPaintingDisabled(b); + m_common->m_updatingControlTints = b; +} + +void GraphicsContext::setPaintingDisabled(bool f) +{ + m_common->state.paintingDisabled = f; +} + +bool GraphicsContext::paintingDisabled() const +{ + return m_common->state.paintingDisabled; +} + +void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op) +{ + drawImage(image, p, IntRect(0, 0, -1, -1), op); +} + +void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, bool useLowQualityScale) +{ + drawImage(image, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); +} + +void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) +{ + drawImage(image, IntRect(dest, srcRect.size()), srcRect, op); +} + +void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) +{ + drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale); +} + +void GraphicsContext::drawText(const TextRun& run, const IntPoint& point, int from, int to) +{ + if (paintingDisabled()) + return; + + font().drawText(this, run, point, from, to); +} + +void GraphicsContext::drawBidiText(const TextRun& run, const IntPoint& point) +{ + if (paintingDisabled()) + return; + + BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; + WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; + + bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); + + bidiResolver.createBidiRunsForLine(TextRunIterator(&run, 0), TextRunIterator(&run, run.length())); + + if (!bidiResolver.runCount()) + return; + + FloatPoint currPoint = point; + BidiCharacterRun* bidiRun = bidiResolver.firstRun(); + while (bidiRun) { + + TextRun subrun = run; + subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start()); + subrun.setRTL(bidiRun->level() % 2); + subrun.setDirectionalOverride(bidiRun->dirOverride(false)); + + font().drawText(this, subrun, currPoint); + + bidiRun = bidiRun->next(); + // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. + if (bidiRun) + currPoint.move(font().floatWidth(subrun), 0.f); + } + + bidiResolver.deleteRuns(); +} + +void GraphicsContext::drawHighlightForText(const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to) +{ + if (paintingDisabled()) + return; + + fillRect(font().selectionRectForText(run, point, h, from, to), backgroundColor); +} + +void GraphicsContext::initFocusRing(int width, int offset) +{ + if (paintingDisabled()) + return; + clearFocusRing(); + + m_common->m_focusRingWidth = width; + m_common->m_focusRingOffset = offset; +} + +void GraphicsContext::clearFocusRing() +{ + m_common->m_focusRingRects.clear(); +} + +IntRect GraphicsContext::focusRingBoundingRect() +{ + IntRect result = IntRect(0, 0, 0, 0); + + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + for (unsigned i = 0; i < rectCount; i++) + result.unite(rects[i]); + + return result; +} + +void GraphicsContext::addFocusRingRect(const IntRect& rect) +{ + if (paintingDisabled() || rect.isEmpty()) + return; + m_common->m_focusRingRects.append(rect); +} + +int GraphicsContext::focusRingWidth() const +{ + return m_common->m_focusRingWidth; +} + +int GraphicsContext::focusRingOffset() const +{ + return m_common->m_focusRingOffset; +} + +const Vector<IntRect>& GraphicsContext::focusRingRects() const +{ + return m_common->m_focusRingRects; +} + +static const int cInterpolationCutoff = 800 * 800; + +void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) +{ + if (paintingDisabled()) + return; + + float tsw = src.width(); + float tsh = src.height(); + float tw = dest.width(); + float th = dest.height(); + + if (tsw == -1) + tsw = image->width(); + if (tsh == -1) + tsh = image->height(); + + if (tw == -1) + tw = image->width(); + if (th == -1) + th = image->height(); + + bool shouldUseLowQualityInterpolation = useLowQualityScale && (tsw != tw || tsh != th) && tsw * tsh > cInterpolationCutoff; + if (shouldUseLowQualityInterpolation) { + save(); + setUseLowQualityImageInterpolation(true); + } + image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op); + if (shouldUseLowQualityInterpolation) + restore(); +} + +void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) +{ + if (paintingDisabled()) + return; + + image->drawTiled(this, rect, srcPoint, tileSize, op); +} + +void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) +{ + if (paintingDisabled()) + return; + + if (hRule == Image::StretchTile && vRule == Image::StretchTile) + // Just do a scale. + return drawImage(image, dest, srcRect); + + image->drawTiled(this, dest, srcRect, hRule, vRule, op); +} + +void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, + const IntSize& bottomLeft, const IntSize& bottomRight) +{ + if (paintingDisabled()) + return; + + clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); +} + +void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, + const IntSize& bottomLeft, const IntSize& bottomRight) +{ + if (paintingDisabled()) + return; + + clipOut(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); +} + +int GraphicsContext::textDrawingMode() +{ + return m_common->state.textDrawingMode; +} + +void GraphicsContext::setTextDrawingMode(int mode) +{ + m_common->state.textDrawingMode = mode; + if (paintingDisabled()) + return; + setPlatformTextDrawingMode(mode); +} + +#if !PLATFORM(CG) +// Implement this if you want to go ahead and push the drawing mode into your native context +// immediately. +void GraphicsContext::setPlatformTextDrawingMode(int mode) +{ +} +#endif + +#if !PLATFORM(QT) && !PLATFORM(CAIRO) +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&) +{ +} +#endif + +#if !PLATFORM(QT) +void GraphicsContext::setPlatformFont(const Font&) +{ +} +#endif + +} diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h new file mode 100644 index 0000000..732c8e3 --- /dev/null +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsContext_h +#define GraphicsContext_h + +#include "FloatRect.h" +#include "Image.h" +#include "IntRect.h" +#include "Path.h" +#include "TextDirection.h" +#include <wtf/Noncopyable.h> +#include <wtf/Platform.h> + +#if PLATFORM(CG) +typedef struct CGContext PlatformGraphicsContext; +#elif PLATFORM(CAIRO) +typedef struct _cairo PlatformGraphicsContext; +#elif PLATFORM(QT) +class QPainter; +typedef QPainter PlatformGraphicsContext; +#elif PLATFORM(WX) +class wxGCDC; +class wxWindowDC; + +// wxGraphicsContext allows us to support Path, etc. +// but on some platforms, e.g. Linux, it requires fairly +// new software. +#if USE(WXGC) +// On OS X, wxGCDC is just a typedef for wxDC, so use wxDC explicitly to make +// the linker happy. +#ifdef __APPLE__ + class wxDC; + typedef wxDC PlatformGraphicsContext; +#else + typedef wxGCDC PlatformGraphicsContext; +#endif +#else + typedef wxWindowDC PlatformGraphicsContext; +#endif +#else +typedef void PlatformGraphicsContext; +#endif + +#if PLATFORM(GTK) +typedef struct _GdkDrawable GdkDrawable; +typedef struct _GdkEventExpose GdkEventExpose; +#endif + +#if PLATFORM(WIN) +typedef struct HDC__* HDC; +#endif + +namespace WebCore { + + const int cMisspellingLineThickness = 3; + const int cMisspellingLinePatternWidth = 4; + const int cMisspellingLinePatternGapWidth = 1; + + class AffineTransform; + class Font; + class GraphicsContextPrivate; + class GraphicsContextPlatformPrivate; + class ImageBuffer; + class KURL; + class Path; + class TextRun; + + // These bits can be ORed together for a total of 8 possible text drawing modes. + const int cTextInvisible = 0; + const int cTextFill = 1; + const int cTextStroke = 2; + const int cTextClip = 4; + + enum StrokeStyle { + NoStroke, + SolidStroke, + DottedStroke, + DashedStroke + }; + + class GraphicsContext : Noncopyable { + public: + GraphicsContext(PlatformGraphicsContext*); + ~GraphicsContext(); + + PlatformGraphicsContext* platformContext() const; + + const Font& font() const; + void setFont(const Font&); + + float strokeThickness() const; + void setStrokeThickness(float); + StrokeStyle strokeStyle() const; + void setStrokeStyle(const StrokeStyle& style); + Color strokeColor() const; + void setStrokeColor(const Color&); + + Color fillColor() const; + void setFillColor(const Color&); + + 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); + + // 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&, const Color&); + 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&, float lineWidth); + + void drawImage(Image*, const IntPoint&, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), + CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(ImageBuffer*, const FloatRect& srcRect, const FloatRect& destRect); + void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, + CompositeOperator = CompositeSourceOver); + void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, + Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile, + CompositeOperator = CompositeSourceOver); + + void paintBuffer(ImageBuffer*, const IntRect&); +#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 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); + + int textDrawingMode(); + void setTextDrawingMode(int); + + void drawText(const TextRun&, const IntPoint&, int from = 0, int to = -1); + void drawBidiText(const TextRun&, const IntPoint&); + void drawHighlightForText(const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1); + + FloatRect roundToDevicePixels(const FloatRect&); + + void drawLineForText(const IntPoint&, int width, bool printing); + void drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar); + + bool paintingDisabled() const; + void setPaintingDisabled(bool); + + bool updatingControlTints() const; + void setUpdatingControlTints(bool); + + void beginTransparencyLayer(float opacity); + void endTransparencyLayer(); + + void setShadow(const IntSize&, int blur, const Color&); + void clearShadow(); + + void initFocusRing(int width, int offset); + void addFocusRingRect(const IntRect&); + void drawFocusRing(const Color&); + void clearFocusRing(); + IntRect focusRingBoundingRect(); + + void setLineCap(LineCap); + void setLineJoin(LineJoin); + void setMiterLimit(float); + + void setAlpha(float); + + void setCompositeOperation(CompositeOperator); + + void beginPath(); + void addPath(const Path&); + + void clip(const Path&); + void clipOut(const Path&); + + void scale(const FloatSize&); + void rotate(float angleInRadians); + void translate(float x, float y); + IntPoint origin(); + + void setURLForRect(const KURL&, const IntRect&); + + void concatCTM(const AffineTransform&); + AffineTransform getCTM() const; + + void setUseAntialiasing(bool = true); + +#if PLATFORM(WIN) + GraphicsContext(HDC); // 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. +#endif + +#if PLATFORM(QT) + void setFillRule(WindRule); + PlatformPath* currentPath(); +#endif + +#if PLATFORM(GTK) + void setGdkExposeEvent(GdkEventExpose*); + GdkDrawable* gdkDrawable() const; + GdkEventExpose* gdkExposeEvent() const; + IntPoint translatePoint(const IntPoint&) const; +#endif + + private: + void savePlatformState(); + void restorePlatformState(); + void setPlatformTextDrawingMode(int); + void setPlatformStrokeColor(const Color&); + void setPlatformStrokeStyle(const StrokeStyle&); + void setPlatformStrokeThickness(float); + void setPlatformFillColor(const Color&); + void setPlatformFont(const Font& font); + + int focusRingWidth() const; + int focusRingOffset() const; + const Vector<IntRect>& focusRingRects() const; + + static GraphicsContextPrivate* createGraphicsContextPrivate(); + static void destroyGraphicsContextPrivate(GraphicsContextPrivate*); + + GraphicsContextPrivate* m_common; + GraphicsContextPlatformPrivate* m_data; + }; + +} // namespace WebCore + +#endif // GraphicsContext_h diff --git a/WebCore/platform/graphics/GraphicsTypes.cpp b/WebCore/platform/graphics/GraphicsTypes.cpp new file mode 100644 index 0000000..736356f --- /dev/null +++ b/WebCore/platform/graphics/GraphicsTypes.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsTypes.h" + +#include "PlatformString.h" +#include <wtf/Assertions.h> + +namespace WebCore { + +static const char* const compositeOperatorNames[] = { + "clear", + "copy", + "source-over", + "source-in", + "source-out", + "source-atop", + "destination-over", + "destination-in", + "destination-out", + "destination-atop", + "xor", + "darker", + "highlight", + "lighter" +}; +const int numCompositeOperatorNames = sizeof(compositeOperatorNames) / sizeof(compositeOperatorNames[0]); + +bool parseCompositeOperator(const String& s, CompositeOperator& op) +{ + for (int i = 0; i < numCompositeOperatorNames; i++) + if (s == compositeOperatorNames[i]) { + op = static_cast<CompositeOperator>(i); + return true; + } + return false; +} + +String compositeOperatorName(CompositeOperator op) +{ + ASSERT(op >= 0); + ASSERT(op < numCompositeOperatorNames); + return compositeOperatorNames[op]; +} + +bool parseLineCap(const String& s, LineCap& cap) +{ + if (s == "butt") { + cap = ButtCap; + return true; + } + if (s == "round") { + cap = RoundCap; + return true; + } + if (s == "square") { + cap = SquareCap; + return true; + } + return false; +} + +String lineCapName(LineCap cap) +{ + ASSERT(cap >= 0); + ASSERT(cap < 3); + const char* const names[3] = { "butt", "round", "square" }; + return names[cap]; +} + +bool parseLineJoin(const String& s, LineJoin& join) +{ + if (s == "miter") { + join = MiterJoin; + return true; + } + if (s == "round") { + join = RoundJoin; + return true; + } + if (s == "bevel") { + join = BevelJoin; + return true; + } + return false; +} + +String lineJoinName(LineJoin join) +{ + ASSERT(join >= 0); + ASSERT(join < 3); + const char* const names[3] = { "miter", "round", "bevel" }; + return names[join]; +} + +} diff --git a/WebCore/platform/graphics/GraphicsTypes.h b/WebCore/platform/graphics/GraphicsTypes.h new file mode 100644 index 0000000..b3ca99a --- /dev/null +++ b/WebCore/platform/graphics/GraphicsTypes.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsTypes_h +#define GraphicsTypes_h + +namespace WebCore { + + class String; + + // Note: These constants exactly match the NSCompositeOperator constants of + // AppKit on Mac OS X Tiger. If these ever change, we'll need to change the + // Mac OS X Tiger platform code to map one to the other. + enum CompositeOperator { + CompositeClear, + CompositeCopy, + CompositeSourceOver, + CompositeSourceIn, + CompositeSourceOut, + CompositeSourceAtop, + CompositeDestinationOver, + CompositeDestinationIn, + CompositeDestinationOut, + CompositeDestinationAtop, + CompositeXOR, + CompositePlusDarker, + CompositeHighlight, + CompositePlusLighter + }; + + enum LineCap { ButtCap, RoundCap, SquareCap }; + + enum LineJoin { MiterJoin, RoundJoin, BevelJoin }; + + enum HorizontalAlignment { AlignLeft, AlignRight, AlignHCenter }; + + String compositeOperatorName(CompositeOperator); + bool parseCompositeOperator(const String&, CompositeOperator&); + + String lineCapName(LineCap); + bool parseLineCap(const String&, LineCap&); + + String lineJoinName(LineJoin); + bool parseLineJoin(const String&, LineJoin&); + +} + +#endif diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h new file mode 100644 index 0000000..310c25a --- /dev/null +++ b/WebCore/platform/graphics/Icon.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Icon_h +#define Icon_h + +#include <wtf/RefCounted.h> +#include <wtf/Forward.h> + +#if PLATFORM(MAC) +#include <wtf/RetainPtr.h> +#ifdef __OBJC__ +@class NSImage; +#else +class NSImage; +#endif +#elif PLATFORM(WIN) +typedef struct HICON__* HICON; +#elif PLATFORM(QT) +#include <QIcon> +#elif PLATFORM(GTK) +#include <gdk/gdk.h> +#endif + +namespace WebCore { + +class GraphicsContext; +class IntRect; +class String; + +class Icon : public RefCounted<Icon> { +public: + Icon(); + ~Icon(); + + static PassRefPtr<Icon> newIconForFile(const String& filename); + + void paint(GraphicsContext*, const IntRect&); + +#if PLATFORM(WIN) + Icon(HICON); +#endif + +private: +#if PLATFORM(MAC) + Icon(NSImage*); +#endif +#if PLATFORM(MAC) + RetainPtr<NSImage> m_nsImage; +#elif PLATFORM(WIN) + HICON m_hIcon; +#elif PLATFORM(QT) + QIcon m_icon; +#elif PLATFORM(GTK) + GdkPixbuf* m_icon; +#endif +}; + +} + +#endif diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp new file mode 100644 index 0000000..8bf7c68 --- /dev/null +++ b/WebCore/platform/graphics/Image.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" + +#include "AffineTransform.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "MIMETypeRegistry.h" + +#include <math.h> + +#if PLATFORM(CG) +#include <CoreFoundation/CoreFoundation.h> +#endif + +namespace WebCore { + +Image::Image(ImageObserver* observer) + : m_imageObserver(observer) +{ +} + +Image::~Image() +{ +} + +bool Image::supportsType(const String& type) +{ + return MIMETypeRegistry::isSupportedImageResourceMIMEType(type); +} + +bool Image::isNull() const +{ + return size().isEmpty(); +} + +bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived) +{ + m_data = data; + if (!m_data.get()) + return true; + + int length = m_data->size(); + if (!length) + return true; + + return dataChanged(allDataReceived); +} + +IntRect Image::rect() const +{ + return IntRect(IntPoint(), size()); +} + +int Image::width() const +{ + return size().width(); +} + +int Image::height() const +{ + return size().height(); +} + +void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op) +{ + if (color.alpha() <= 0) + return; + + ctxt->save(); + ctxt->setCompositeOperation(!color.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); + ctxt->fillRect(dstRect, color); + ctxt->restore(); +} + +static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const FloatRect& srcRect, Image::TileRule hRule, Image::TileRule vRule) +{ + float scaleX = 1.0f, scaleY = 1.0f; + + if (hRule == Image::StretchTile) + scaleX = dstRect.width() / srcRect.width(); + if (vRule == Image::StretchTile) + scaleY = dstRect.height() / srcRect.height(); + + if (hRule == Image::RepeatTile) + scaleX = scaleY; + if (vRule == Image::RepeatTile) + scaleY = scaleX; + + return FloatSize(scaleX, scaleY); +} + + +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op) +{ + if (!nativeImageForCurrentFrame()) + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(ctxt, destRect, solidColor(), op); + return; + } + + FloatSize intrinsicTileSize = size(); + if (hasRelativeWidth()) + intrinsicTileSize.setWidth(scaledTileSize.width()); + if (hasRelativeHeight()) + intrinsicTileSize.setHeight(scaledTileSize.height()); + + FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), + scaledTileSize.height() / intrinsicTileSize.height()); + AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); + + FloatRect oneTileRect; + oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width())); + oneTileRect.setY(destRect.y() + fmodf(fmodf(-srcPoint.y(), scaledTileSize.height()) - scaledTileSize.height(), scaledTileSize.height())); + oneTileRect.setSize(scaledTileSize); + + // Check and see if a single draw of the image can cover the entire area we are supposed to tile. + if (oneTileRect.contains(destRect)) { + FloatRect visibleSrcRect; + visibleSrcRect.setX((destRect.x() - oneTileRect.x()) / scale.width()); + visibleSrcRect.setY((destRect.y() - oneTileRect.y()) / scale.height()); + visibleSrcRect.setWidth(destRect.width() / scale.width()); + visibleSrcRect.setHeight(destRect.height() / scale.height()); + draw(ctxt, destRect, visibleSrcRect, op); + return; + } + + FloatRect tileRect(FloatPoint(), intrinsicTileSize); + drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect); + + startAnimation(); +} + +// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things. +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator op) +{ + if (!nativeImageForCurrentFrame()) + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(ctxt, dstRect, solidColor(), op); + return; + } + + // FIXME: We do not support 'round' yet. For now just map it to 'repeat'. + if (hRule == RoundTile) + hRule = RepeatTile; + if (vRule == RoundTile) + vRule = RepeatTile; + + FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule); + AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); + + // We want to construct the phase such that the pattern is centered (when stretch is not + // set for a particular rule). + float hPhase = scale.width() * srcRect.x(); + float vPhase = scale.height() * srcRect.y(); + if (hRule == Image::RepeatTile) + hPhase -= fmodf(dstRect.width(), scale.width() * srcRect.width()) / 2.0f; + if (vRule == Image::RepeatTile) + vPhase -= fmodf(dstRect.height(), scale.height() * srcRect.height()) / 2.0f; + FloatPoint patternPhase(dstRect.x() - hPhase, dstRect.y() - vPhase); + + drawPattern(ctxt, srcRect, patternTransform, patternPhase, op, dstRect); + + startAnimation(); +} + + +} diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h new file mode 100644 index 0000000..6ffe163 --- /dev/null +++ b/WebCore/platform/graphics/Image.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Image_h +#define Image_h + +#include "Color.h" +#include "GraphicsTypes.h" +#include "ImageSource.h" +#include <wtf/RefPtr.h> +#include <wtf/PassRefPtr.h> +#include "SharedBuffer.h" + +#if PLATFORM(MAC) +#ifdef __OBJC__ +@class NSImage; +#else +class NSImage; +#endif +#endif + +#if PLATFORM(CG) +struct CGContext; +#endif + +#if PLATFORM(WIN) +typedef struct HBITMAP__ *HBITMAP; +#endif + +#if PLATFORM(QT) +#include <QPixmap> +#endif + +namespace WebCore { + +class AffineTransform; +class FloatPoint; +class FloatRect; +class FloatSize; +class GraphicsContext; +class IntRect; +class IntSize; +class SharedBuffer; +class String; + +// This class gets notified when an image creates or destroys decoded frames and when it advances animation frames. +class ImageObserver; + +class Image : Noncopyable { + friend class GraphicsContext; +public: + Image(ImageObserver* = 0); + virtual ~Image(); + + static Image* loadPlatformResource(const char* name); + static bool supportsType(const String&); + + bool isNull() const; + + // These are only used for SVGImage right now + virtual void setContainerSize(const IntSize&) { } + virtual bool usesContainerSize() const { return false; } + virtual bool hasRelativeWidth() const { return false; } + virtual bool hasRelativeHeight() const { return false; } + + virtual IntSize size() const = 0; + IntRect rect() const; + int width() const; + int height() const; + + bool setData(PassRefPtr<SharedBuffer> data, bool allDataReceived); + virtual bool dataChanged(bool allDataReceived) { return false; } + + // 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; } + + SharedBuffer* data() { return m_data.get(); } + + // It may look unusual that there is no start animation call as public API. This is because + // we start and stop animating lazily. Animation begins whenever someone draws the image. It will + // automatically pause once all observers no longer want to render the image anywhere. + virtual void stopAnimation() {} + virtual void resetAnimation() {} + + // Typically the CachedImage that owns us. + ImageObserver* imageObserver() const { return m_imageObserver; } + + enum TileRule { StretchTile, RoundTile, RepeatTile }; + + virtual NativeImagePtr nativeImageForCurrentFrame() { return 0; } + +#if PLATFORM(MAC) + // Accessors for native image formats. + virtual NSImage* getNSImage() { return 0; } + virtual CFDataRef getTIFFRepresentation() { return 0; } +#endif + +#if PLATFORM(CG) + virtual CGImageRef getCGImageRef() { return 0; } +#endif + +#if PLATFORM(QT) + virtual QPixmap* getPixmap() const { return 0; } +#endif + +#if PLATFORM(WIN) + virtual bool getHBITMAP(HBITMAP) { return false; } + virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE) { return false; } +#endif + +protected: + 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 + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator) = 0; + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, CompositeOperator); + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, CompositeOperator); + + // Supporting tiled drawing + virtual bool mayFillWithSolidColor() const { return false; } + virtual Color solidColor() const { return Color(); } + + virtual void startAnimation() { } + + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); +#if PLATFORM(CG) + // These are private to CG. Ideally they would be only in the .cpp file, but the callback requires access + // to the private function nativeImageForCurrentFrame() + static void drawPatternCallback(void* info, CGContext*); +#endif + +protected: + RefPtr<SharedBuffer> m_data; // The encoded raw data for the image. + ImageObserver* m_imageObserver; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h new file mode 100644 index 0000000..2ac2b4e --- /dev/null +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageBuffer_h +#define ImageBuffer_h + +#include "IntSize.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(CAIRO) +typedef struct _cairo_surface cairo_surface_t; +#endif + +namespace WebCore { + + class GraphicsContext; + class ImageData; + class IntPoint; + class IntRect; + class RenderObject; + + class ImageBuffer : Noncopyable { + public: + static std::auto_ptr<ImageBuffer> create(const IntSize&, bool grayScale); + ~ImageBuffer(); + + 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 + + PassRefPtr<ImageData> getImageData(const IntRect& rect) const; + void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint); + + private: + void* m_data; + IntSize m_size; + + OwnPtr<GraphicsContext> m_context; + +#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 + }; +} + +#endif diff --git a/WebCore/platform/graphics/ImageObserver.h b/WebCore/platform/graphics/ImageObserver.h new file mode 100644 index 0000000..4be83bd --- /dev/null +++ b/WebCore/platform/graphics/ImageObserver.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageObserver_h +#define ImageObserver_h + +namespace WebCore { + +class Image; + +// Interface for notification about changes to an image, including decoding, +// drawing, and animating. +class ImageObserver { +protected: + virtual ~ImageObserver() {} +public: + virtual void decodedSizeChanged(const Image*, int delta) = 0; + virtual void didDraw(const Image*) = 0; + + virtual bool shouldPauseAnimation(const Image*) = 0; + virtual void animationAdvanced(const Image*) = 0; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h new file mode 100644 index 0000000..8db5cd4 --- /dev/null +++ b/WebCore/platform/graphics/ImageSource.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageSource_h +#define ImageSource_h + +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +#if PLATFORM(WX) +class wxBitmap; +#elif PLATFORM(CG) +typedef struct CGImageSource* CGImageSourceRef; +typedef struct CGImage* CGImageRef; +typedef const struct __CFData* CFDataRef; +#elif PLATFORM(QT) +class QPixmap; +#elif PLATFORM(CAIRO) +struct _cairo_surface; +typedef struct _cairo_surface cairo_surface_t; +#endif + +namespace WebCore { + +class IntSize; +class SharedBuffer; + +#if PLATFORM(WX) +class ImageDecoder; +typedef ImageDecoder* NativeImageSourcePtr; +typedef const Vector<char>* NativeBytePtr; +typedef wxBitmap* NativeImagePtr; +#elif PLATFORM(CG) +typedef CGImageSourceRef NativeImageSourcePtr; +typedef CGImageRef NativeImagePtr; +#elif PLATFORM(QT) +class ImageDecoderQt; +typedef ImageDecoderQt* NativeImageSourcePtr; +typedef QPixmap* NativeImagePtr; +#else +class ImageDecoder; +typedef ImageDecoder* NativeImageSourcePtr; +typedef cairo_surface_t* NativeImagePtr; +#endif + +const int cAnimationLoopOnce = -1; +const int cAnimationNone = -2; + +class ImageSource : Noncopyable { +public: + ImageSource(); + ~ImageSource(); + + void clear(); + + bool initialized() const; + + void setData(SharedBuffer* data, bool allDataReceived); + + bool isSizeAvailable(); + IntSize size() const; + + int repetitionCount(); + + size_t frameCount() const; + + NativeImagePtr createFrameAtIndex(size_t); + + float frameDurationAtIndex(size_t); + bool frameHasAlphaAtIndex(size_t); // Whether or not the frame actually used any alpha. + bool frameIsCompleteAtIndex(size_t); // Whether or not the frame is completely decoded. + +private: + NativeImageSourcePtr m_decoder; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h new file mode 100644 index 0000000..bd34d2a --- /dev/null +++ b/WebCore/platform/graphics/IntPoint.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IntPoint_h +#define IntPoint_h + +#include "IntSize.h" +#include <wtf/Platform.h> + +#if PLATFORM(CG) +typedef struct CGPoint CGPoint; +#endif + +#if PLATFORM(MAC) +#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES +typedef struct CGPoint NSPoint; +#else +typedef struct _NSPoint NSPoint; +#endif +#endif + +#if PLATFORM(WIN) +typedef struct tagPOINT POINT; +typedef struct tagPOINTS POINTS; +#elif PLATFORM(QT) +class QPoint; +#elif PLATFORM(GTK) +typedef struct _GdkPoint GdkPoint; +#endif +#if PLATFORM(SYMBIAN) +class TPoint; +#endif + +#if PLATFORM(WX) +class wxPoint; +#endif + +namespace WebCore { + +class IntPoint { +public: + IntPoint() : m_x(0), m_y(0) { } + IntPoint(int x, int y) : m_x(x), m_y(y) { } + + int x() const { return m_x; } + int y() const { return m_y; } + + void setX(int x) { m_x = x; } + void setY(int y) { m_y = y; } + + void move(int dx, int dy) { m_x += dx; m_y += dy; } + +#if PLATFORM(CG) + explicit IntPoint(const CGPoint&); // don't do this implicitly since it's lossy + operator CGPoint() const; +#endif + +#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) + explicit IntPoint(const NSPoint&); // don't do this implicitly since it's lossy + operator NSPoint() const; +#endif + +#if PLATFORM(WIN) + IntPoint(const POINT&); + operator POINT() const; + IntPoint(const POINTS&); + operator POINTS() const; +#elif PLATFORM(QT) + IntPoint(const QPoint&); + operator QPoint() const; +#elif PLATFORM(GTK) + IntPoint(const GdkPoint&); + operator GdkPoint() const; +#endif +#if PLATFORM(SYMBIAN) + IntPoint(const TPoint&); + operator TPoint() const; +#endif + +#if PLATFORM(WX) + IntPoint(const wxPoint&); + operator wxPoint() const; +#endif + +private: + int m_x, m_y; +}; + +inline IntPoint& operator+=(IntPoint& a, const IntSize& b) +{ + a.move(b.width(), b.height()); + return a; +} + +inline IntPoint& operator-=(IntPoint& a, const IntSize& b) +{ + a.move(-b.width(), -b.height()); + return a; +} + +inline IntPoint operator+(const IntPoint& a, const IntSize& b) +{ + return IntPoint(a.x() + b.width(), a.y() + b.height()); +} + +inline IntSize operator-(const IntPoint& a, const IntPoint& b) +{ + return IntSize(a.x() - b.x(), a.y() - b.y()); +} + +inline IntPoint operator-(const IntPoint& a, const IntSize& b) +{ + return IntPoint(a.x() - b.width(), a.y() - b.height()); +} + +inline bool operator==(const IntPoint& a, const IntPoint& b) +{ + return a.x() == b.x() && a.y() == b.y(); +} + +inline bool operator!=(const IntPoint& a, const IntPoint& b) +{ + return a.x() != b.x() || a.y() != b.y(); +} + +} // namespace WebCore + +#endif // IntPoint_h diff --git a/WebCore/platform/graphics/IntRect.cpp b/WebCore/platform/graphics/IntRect.cpp new file mode 100644 index 0000000..622e525 --- /dev/null +++ b/WebCore/platform/graphics/IntRect.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntRect.h" + +#include "FloatRect.h" +#include <algorithm> + +using std::max; +using std::min; + +namespace WebCore { + +IntRect::IntRect(const FloatRect& r) + : m_location(IntPoint(static_cast<int>(r.x()), static_cast<int>(r.y()))) + , m_size(IntSize(static_cast<int>(r.width()), static_cast<int>(r.height()))) +{ +} + +bool IntRect::intersects(const IntRect& other) const +{ + // Checking emptiness handles negative widths as well as zero. + return !isEmpty() && !other.isEmpty() + && x() < other.right() && other.x() < right() + && y() < other.bottom() && other.y() < bottom(); +} + +bool IntRect::contains(const IntRect& other) const +{ + return x() <= other.x() && right() >= other.right() + && y() <= other.y() && bottom() >= other.bottom(); +} + +void IntRect::intersect(const IntRect& other) +{ + int l = max(x(), other.x()); + int t = max(y(), other.y()); + int r = min(right(), other.right()); + int b = min(bottom(), other.bottom()); + + // Return a clean empty rectangle for non-intersecting cases. + if (l >= r || t >= b) { + l = 0; + t = 0; + r = 0; + b = 0; + } + + m_location.setX(l); + m_location.setY(t); + m_size.setWidth(r - l); + m_size.setHeight(b - t); +} + +void IntRect::unite(const IntRect& other) +{ + // Handle empty special cases first. + if (other.isEmpty()) + return; + if (isEmpty()) { + *this = other; + return; + } + + int l = min(x(), other.x()); + int t = min(y(), other.y()); + int r = max(right(), other.right()); + int b = max(bottom(), other.bottom()); + + m_location.setX(l); + m_location.setY(t); + m_size.setWidth(r - l); + m_size.setHeight(b - t); +} + +void IntRect::scale(float s) +{ + m_location.setX((int)(x() * s)); + m_location.setY((int)(y() * s)); + m_size.setWidth((int)(width() * s)); + m_size.setHeight((int)(height() * s)); +} + +} diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h new file mode 100644 index 0000000..84adf20 --- /dev/null +++ b/WebCore/platform/graphics/IntRect.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IntRect_h +#define IntRect_h + +#include "IntPoint.h" +#include <wtf/Platform.h> + +#if PLATFORM(CG) +typedef struct CGRect CGRect; +#endif + +#if PLATFORM(MAC) +#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES +typedef struct CGRect NSRect; +#else +typedef struct _NSRect NSRect; +#endif +#endif + +#if PLATFORM(WIN) +typedef struct tagRECT RECT; +#elif PLATFORM(QT) +class QRect; +#elif PLATFORM(GTK) +typedef struct _GdkRectangle GdkRectangle; +#endif +#if PLATFORM(SYMBIAN) +class TRect; +#endif + +#if PLATFORM(WX) +class wxRect; +#endif + +namespace WebCore { + +class FloatRect; + +class IntRect { +public: + IntRect() { } + IntRect(const IntPoint& location, const IntSize& size) + : m_location(location), m_size(size) { } + IntRect(int x, int y, int width, int height) + : m_location(IntPoint(x, y)), m_size(IntSize(width, height)) { } + + explicit IntRect(const FloatRect& rect); // don't do this implicitly since it's lossy + + IntPoint location() const { return m_location; } + IntSize size() const { return m_size; } + + void setLocation(const IntPoint& location) { m_location = location; } + void setSize(const IntSize& size) { m_size = size; } + + int x() const { return m_location.x(); } + int y() const { return m_location.y(); } + int width() const { return m_size.width(); } + int height() const { return m_size.height(); } + + void setX(int x) { m_location.setX(x); } + void setY(int y) { m_location.setY(y); } + void setWidth(int width) { m_size.setWidth(width); } + void setHeight(int height) { m_size.setHeight(height); } + + // Be careful with these functions. The point is considered to be to the right and below. These are not + // substitutes for right() and bottom(). + IntPoint topLeft() const { return m_location; } + IntPoint topRight() const { return IntPoint(right() - 1, y()); } + IntPoint bottomLeft() const { return IntPoint(x(), bottom() - 1); } + IntPoint bottomRight() const { return IntPoint(right() - 1, bottom() - 1); } + + bool isEmpty() const { return m_size.isEmpty(); } + + int right() const { return x() + width(); } + int bottom() const { return y() + height(); } + + void move(const IntSize& s) { m_location += s; } + void move(int dx, int dy) { m_location.move(dx, dy); } + + bool intersects(const IntRect&) const; + bool contains(const IntRect&) const; + + // This checks to see if the rect contains x,y in the traditional sense. + // Equivalent to checking if the rect contains a 1x1 rect below and to the right of (px,py). + bool contains(int px, int py) const + { return px >= x() && px < right() && py >= y() && py < bottom(); } + bool contains(const IntPoint& point) const { return contains(point.x(), point.y()); } + + void intersect(const IntRect&); + void unite(const IntRect&); + + void inflateX(int dx) + { + m_location.setX(m_location.x() - dx); + m_size.setWidth(m_size.width() + dx + dx); + } + void inflateY(int dy) + { + m_location.setY(m_location.y() - dy); + m_size.setHeight(m_size.height() + dy + dy); + } + void inflate(int d) { inflateX(d); inflateY(d); } + void scale(float s); + +#if PLATFORM(WX) + IntRect(const wxRect&); + operator wxRect() const; +#endif + +#if PLATFORM(WIN) + IntRect(const RECT&); + operator RECT() const; +#elif PLATFORM(QT) + IntRect(const QRect&); + operator QRect() const; +#elif PLATFORM(GTK) + IntRect(const GdkRectangle&); + operator GdkRectangle() const; +#endif +#if PLATFORM(SYMBIAN) + IntRect(const TRect&); + operator TRect() const; + TRect Rect() const; +#endif + +#if PLATFORM(CG) + operator CGRect() const; +#endif + +#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) + operator NSRect() const; +#endif + +private: + IntPoint m_location; + IntSize m_size; +}; + +inline IntRect intersection(const IntRect& a, const IntRect& b) +{ + IntRect c = a; + c.intersect(b); + return c; +} + +inline IntRect unionRect(const IntRect& a, const IntRect& b) +{ + IntRect c = a; + c.unite(b); + return c; +} + +inline bool operator==(const IntRect& a, const IntRect& b) +{ + return a.location() == b.location() && a.size() == b.size(); +} + +inline bool operator!=(const IntRect& a, const IntRect& b) +{ + return a.location() != b.location() || a.size() != b.size(); +} + +#if PLATFORM(CG) +IntRect enclosingIntRect(const CGRect&); +#endif + +#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +IntRect enclosingIntRect(const NSRect&); +#endif + +} // namespace WebCore + +#endif // IntRect_h diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h new file mode 100644 index 0000000..faf58c6 --- /dev/null +++ b/WebCore/platform/graphics/IntSize.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef IntSize_h +#define IntSize_h + +#include <wtf/Platform.h> + +#if PLATFORM(CG) +typedef struct CGSize CGSize; +#endif + +#if PLATFORM(MAC) +#ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES +typedef struct CGSize NSSize; +#else +typedef struct _NSSize NSSize; +#endif +#endif + +#if PLATFORM(WIN) +typedef struct tagSIZE SIZE; +#elif PLATFORM(QT) +class QSize; +#endif +#if PLATFORM(SYMBIAN) +class TSize; +#endif + +namespace WebCore { + +class IntSize { +public: + IntSize() : m_width(0), m_height(0) { } + IntSize(int width, int height) : m_width(width), m_height(height) { } + + int width() const { return m_width; } + int height() const { return m_height; } + + void setWidth(int width) { m_width = width; } + void setHeight(int height) { m_height = height; } + + bool isEmpty() const { return m_width <= 0 || m_height <= 0; } + + IntSize expandedTo(const IntSize& other) const + { + return IntSize(m_width > other.m_width ? m_width : other.m_width, + m_height > other.m_height ? m_height : other.m_height); + } + + IntSize shrunkTo(const IntSize& other) const + { + return IntSize(m_width < other.m_width ? m_width : other.m_width, + m_height < other.m_height ? m_height : other.m_height); + } + + void clampNegativeToZero() + { + *this = expandedTo(IntSize()); + } + +#if PLATFORM(CG) + explicit IntSize(const CGSize&); // don't do this implicitly since it's lossy + operator CGSize() const; +#endif + +#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) + explicit IntSize(const NSSize &); // don't do this implicitly since it's lossy + operator NSSize() const; +#endif + +#if PLATFORM(WIN) + IntSize(const SIZE&); + operator SIZE() const; +#endif + +#if PLATFORM(QT) + IntSize(const QSize&); + operator QSize() const; +#endif +#if PLATFORM(SYMBIAN) + IntSize(const TSize&); + operator TSize() const; +#endif + + +private: + int m_width, m_height; +}; + +inline IntSize& operator+=(IntSize& a, const IntSize& b) +{ + a.setWidth(a.width() + b.width()); + a.setHeight(a.height() + b.height()); + return a; +} + +inline IntSize& operator-=(IntSize& a, const IntSize& b) +{ + a.setWidth(a.width() - b.width()); + a.setHeight(a.height() - b.height()); + return a; +} + +inline IntSize operator+(const IntSize& a, const IntSize& b) +{ + return IntSize(a.width() + b.width(), a.height() + b.height()); +} + +inline IntSize operator-(const IntSize& a, const IntSize& b) +{ + return IntSize(a.width() - b.width(), a.height() - b.height()); +} + +inline IntSize operator-(const IntSize& size) +{ + return IntSize(-size.width(), -size.height()); +} + +inline bool operator==(const IntSize& a, const IntSize& b) +{ + return a.width() == b.width() && a.height() == b.height(); +} + +inline bool operator!=(const IntSize& a, const IntSize& b) +{ + return a.width() != b.width() || a.height() != b.height(); +} + +} // namespace WebCore + +#endif // IntSize_h diff --git a/WebCore/platform/graphics/IntSizeHash.h b/WebCore/platform/graphics/IntSizeHash.h new file mode 100644 index 0000000..142533e --- /dev/null +++ b/WebCore/platform/graphics/IntSizeHash.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ +#ifndef IntSizeHash_h +#define IntSizeHash_h + +#include "IntSize.h" +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> + +using WebCore::IntSize; + +namespace WTF { + + template<> struct IntHash<IntSize> { + static unsigned hash(const IntSize& key) { return intHash((static_cast<uint64_t>(key.width()) << 32 | key.height())); } + static bool equal(const IntSize& a, const IntSize& b) { return a == b; } + + static const bool safeToCompareToEmptyOrDeleted = true; + }; + template<> struct DefaultHash<IntSize> { typedef IntHash<IntSize> Hash; }; + + template<> struct HashTraits<IntSize> : GenericHashTraits<IntSize> { + static const bool emptyValueIsZero = true; + static const bool needsDestruction = false; + static const bool needsRef = false; + static IntSize deletedValue() { return IntSize(-1, -1); } + }; +} // namespace WTF + +#endif diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp new file mode 100644 index 0000000..82e9950 --- /dev/null +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(VIDEO) +#include "MediaPlayer.h" + +#include "IntRect.h" +#include "MIMETypeRegistry.h" + +#if PLATFORM(MAC) +#include "MediaPlayerPrivateQTKit.h" +#elif PLATFORM(WIN) +#include "MediaPlayerPrivateQuickTimeWin.h" +#elif PLATFORM(GTK) +#include "MediaPlayerPrivateGStreamer.h" +#endif + +namespace WebCore { + + MediaPlayer::MediaPlayer(MediaPlayerClient* client) + : m_mediaPlayerClient(client) + , m_private(new MediaPlayerPrivate(this)) + , m_parentWidget(0) + , m_visible(false) + , m_rate(1.0f) + , m_volume(0.5f) +{ +} + +MediaPlayer::~MediaPlayer() +{ + delete m_private; +} + +void MediaPlayer::load(String url) +{ + m_private->load(url); +} + +void MediaPlayer::cancelLoad() +{ + m_private->cancelLoad(); +} + +void MediaPlayer::play() +{ + m_private->play(); +} + +void MediaPlayer::pause() +{ + m_private->pause(); +} + +float MediaPlayer::duration() const +{ + return m_private->duration(); +} + +float MediaPlayer::currentTime() const +{ + return m_private->currentTime(); +} + +void MediaPlayer::seek(float time) +{ + m_private->seek(time); +} + +bool MediaPlayer::paused() const +{ + return m_private->paused(); +} + +bool MediaPlayer::seeking() const +{ + return m_private->seeking(); +} + +IntSize MediaPlayer::naturalSize() +{ + return m_private->naturalSize(); +} + +bool MediaPlayer::hasVideo() +{ + return m_private->hasVideo(); +} + +MediaPlayer::NetworkState MediaPlayer::networkState() +{ + return m_private->networkState(); +} + +MediaPlayer::ReadyState MediaPlayer::readyState() +{ + return m_private->readyState(); +} + +float MediaPlayer::volume() const +{ + return m_volume; +} + +void MediaPlayer::setVolume(float volume) +{ + if (volume != m_volume) { + m_volume = volume; + m_private->setVolume(volume); + } +} + +float MediaPlayer::rate() const +{ + return m_rate; +} + +void MediaPlayer::setRate(float rate) +{ + if (rate == m_rate) + return; + m_rate = rate; + m_private->setRate(rate); +} + +int MediaPlayer::dataRate() const +{ + return m_private->dataRate(); +} + +void MediaPlayer::setEndTime(float time) +{ + m_private->setEndTime(time); +} + +float MediaPlayer::maxTimeBuffered() +{ + return m_private->maxTimeBuffered(); +} + +float MediaPlayer::maxTimeSeekable() +{ + return m_private->maxTimeSeekable(); +} + +unsigned MediaPlayer::bytesLoaded() +{ + return m_private->bytesLoaded(); +} + +bool MediaPlayer::totalBytesKnown() +{ + return m_private->totalBytesKnown(); +} + +unsigned MediaPlayer::totalBytes() +{ + return m_private->totalBytes(); +} + +void MediaPlayer::setRect(const IntRect& r) +{ + if (m_rect == r) + return; + m_rect = r; + m_private->setRect(r); +} + +bool MediaPlayer::visible() const +{ + return m_visible; +} + +void MediaPlayer::setVisible(bool b) +{ + if (m_visible == b) + return; + m_visible = b; + m_private->setVisible(b); +} + +void MediaPlayer::paint(GraphicsContext* p, const IntRect& r) +{ + m_private->paint(p, r); +} + +void MediaPlayer::getSupportedTypes(HashSet<String>& types) +{ + MediaPlayerPrivate::getSupportedTypes(types); +} + +bool MediaPlayer::isAvailable() +{ + static bool availabityKnown = false; + static bool isAvailable; + if (!availabityKnown) { + isAvailable = MediaPlayerPrivate::isAvailable(); + availabityKnown = true; + } + return isAvailable; +} + +void MediaPlayer::networkStateChanged() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerNetworkStateChanged(this); +} + +void MediaPlayer::readyStateChanged() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerReadyStateChanged(this); +} + +void MediaPlayer::volumeChanged() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerVolumeChanged(this); +} + +void MediaPlayer::timeChanged() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerTimeChanged(this); +} + +void MediaPlayer::repaint() +{ + if (m_mediaPlayerClient) + m_mediaPlayerClient->mediaPlayerRepaint(this); +} + +} +#endif diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h new file mode 100644 index 0000000..2c78664 --- /dev/null +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayer_h +#define MediaPlayer_h + +#if ENABLE(VIDEO) + +#include "IntRect.h" +#include "StringHash.h" +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class GraphicsContext; +class IntSize; +class MediaPlayer; +class MediaPlayerPrivate; +class String; +class Widget; + +class MediaPlayerClient +{ +public: + virtual ~MediaPlayerClient() { } + virtual void mediaPlayerNetworkStateChanged(MediaPlayer*) { } + virtual void mediaPlayerReadyStateChanged(MediaPlayer*) { } + virtual void mediaPlayerVolumeChanged(MediaPlayer*) { } + virtual void mediaPlayerTimeChanged(MediaPlayer*) { } + virtual void mediaPlayerRepaint(MediaPlayer*) { } +}; + +class MediaPlayer : Noncopyable { +public: + MediaPlayer(MediaPlayerClient*); + virtual ~MediaPlayer(); + + static bool isAvailable(); + static void getSupportedTypes(HashSet<String>&); + + IntSize naturalSize(); + bool hasVideo(); + + Widget* parentWidget() const { return m_parentWidget; } + void setParentWidget(Widget* parent) { m_parentWidget = parent; } + + IntRect rect() const { return m_rect; } + void setRect(const IntRect& r); + + void load(String url); + void cancelLoad(); + + bool visible() const; + void setVisible(bool); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + + void setEndTime(float time); + + float rate() const; + void setRate(float); + + float maxTimeBuffered(); + float maxTimeSeekable(); + + unsigned bytesLoaded(); + bool totalBytesKnown(); + unsigned totalBytes(); + + float volume() const; + void setVolume(float); + + int dataRate() const; + + void paint(GraphicsContext*, const IntRect&); + + enum NetworkState { Empty, LoadFailed, Loading, LoadedMetaData, LoadedFirstFrame, Loaded }; + NetworkState networkState(); + + enum ReadyState { DataUnavailable, CanShowCurrentFrame, CanPlay, CanPlayThrough }; + ReadyState readyState(); + + void networkStateChanged(); + void readyStateChanged(); + void volumeChanged(); + void timeChanged(); + + void repaint(); + +private: + + friend class MediaPlayerPrivate; + + MediaPlayerClient* m_mediaPlayerClient; + MediaPlayerPrivate* m_private; + Widget* m_parentWidget; + IntRect m_rect; + bool m_visible; + float m_rate; + float m_volume; +}; + +} + +#endif +#endif diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp new file mode 100644 index 0000000..f3450be --- /dev/null +++ b/WebCore/platform/graphics/Path.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * 2006 Rob Buis <buis@kde.org> + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" +#include "Path.h" + +#include "FloatPoint.h" +#include "FloatRect.h" +#include "PathTraversalState.h" +#include <math.h> +#include <wtf/MathExtras.h> + +const float QUARTER = 0.552f; // approximation of control point positions on a bezier + // to simulate a quarter of a circle. +namespace WebCore { + +static void pathLengthApplierFunction(void* info, const PathElement* element) +{ + PathTraversalState& traversalState = *static_cast<PathTraversalState*>(info); + if (traversalState.m_success) + return; + traversalState.m_previous = traversalState.m_current; + FloatPoint* points = element->points; + float segmentLength = 0.0f; + switch (element->type) { + case PathElementMoveToPoint: + segmentLength = traversalState.moveTo(points[0]); + break; + case PathElementAddLineToPoint: + segmentLength = traversalState.lineTo(points[0]); + break; + case PathElementAddQuadCurveToPoint: + segmentLength = traversalState.quadraticBezierTo(points[0], points[1]); + break; + case PathElementAddCurveToPoint: + segmentLength = traversalState.cubicBezierTo(points[0], points[1], points[2]); + break; + case PathElementCloseSubpath: + segmentLength = traversalState.closeSubpath(); + break; + } + traversalState.m_totalLength += segmentLength; + if ((traversalState.m_action == PathTraversalState::TraversalPointAtLength || + traversalState.m_action == PathTraversalState::TraversalNormalAngleAtLength) && + (traversalState.m_totalLength >= traversalState.m_desiredLength)) { + FloatSize change = traversalState.m_current - traversalState.m_previous; + float slope = atan2f(change.height(), change.width()); + + if (traversalState.m_action == PathTraversalState::TraversalPointAtLength) { + float offset = traversalState.m_desiredLength - traversalState.m_totalLength; + traversalState.m_current.move(offset * cosf(slope), offset * sinf(slope)); + } else { + static const float rad2deg = 180.0f / piFloat; + traversalState.m_normalAngle = slope * rad2deg; + } + + traversalState.m_success = true; + } +} + +float Path::length() +{ + PathTraversalState traversalState(PathTraversalState::TraversalTotalLength); + apply(&traversalState, pathLengthApplierFunction); + return traversalState.m_totalLength; +} + +FloatPoint Path::pointAtLength(float length, bool& ok) +{ + PathTraversalState traversalState(PathTraversalState::TraversalPointAtLength); + traversalState.m_desiredLength = length; + apply(&traversalState, pathLengthApplierFunction); + ok = traversalState.m_success; + return traversalState.m_current; +} + +float Path::normalAngleAtLength(float length, bool& ok) +{ + PathTraversalState traversalState(PathTraversalState::TraversalNormalAngleAtLength); + traversalState.m_desiredLength = length; + apply(&traversalState, pathLengthApplierFunction); + ok = traversalState.m_success; + return traversalState.m_normalAngle; +} + +Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& roundingRadii) +{ + Path path; + float x = rectangle.x(); + float y = rectangle.y(); + float width = rectangle.width(); + float height = rectangle.height(); + float rx = roundingRadii.width(); + float ry = roundingRadii.height(); + if (width <= 0.0f || height <= 0.0f) + return path; + + float dx = rx, dy = ry; + // If rx is greater than half of the width of the rectangle + // then set rx to half of the width (required in SVG spec) + if (dx > width * 0.5f) + dx = width * 0.5f; + + // If ry is greater than half of the height of the rectangle + // then set ry to half of the height (required in SVG spec) + if (dy > height * 0.5f) + dy = height * 0.5f; + + path.moveTo(FloatPoint(x + dx, y)); + + if (dx < width * 0.5f) + path.addLineTo(FloatPoint(x + width - rx, y)); + + path.addBezierCurveTo(FloatPoint(x + width - dx * (1 - QUARTER), y), FloatPoint(x + width, y + dy * (1 - QUARTER)), FloatPoint(x + width, y + dy)); + + if (dy < height * 0.5) + path.addLineTo(FloatPoint(x + width, y + height - dy)); + + path.addBezierCurveTo(FloatPoint(x + width, y + height - dy * (1 - QUARTER)), FloatPoint(x + width - dx * (1 - QUARTER), y + height), FloatPoint(x + width - dx, y + height)); + + if (dx < width * 0.5) + path.addLineTo(FloatPoint(x + dx, y + height)); + + path.addBezierCurveTo(FloatPoint(x + dx * (1 - QUARTER), y + height), FloatPoint(x, y + height - dy * (1 - QUARTER)), FloatPoint(x, y + height - dy)); + + if (dy < height * 0.5) + path.addLineTo(FloatPoint(x, y + dy)); + + path.addBezierCurveTo(FloatPoint(x, y + dy * (1 - QUARTER)), FloatPoint(x + dx * (1 - QUARTER), y), FloatPoint(x + dx, y)); + + path.closeSubpath(); + + return path; +} + +Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius) +{ + Path path; + + float width = rectangle.width(); + float height = rectangle.height(); + if (width <= 0.0 || height <= 0.0) + return path; + + if (width < topLeftRadius.width() + topRightRadius.width() + || width < bottomLeftRadius.width() + bottomRightRadius.width() + || height < topLeftRadius.height() + bottomLeftRadius.height() + || height < topRightRadius.height() + bottomRightRadius.height()) + // If all the radii cannot be accommodated, return a rect. + return createRectangle(rectangle); + + float x = rectangle.x(); + float y = rectangle.y(); + + path.moveTo(FloatPoint(x + topLeftRadius.width(), y)); + + path.addLineTo(FloatPoint(x + width - topRightRadius.width(), y)); + + path.addBezierCurveTo(FloatPoint(x + width - topRightRadius.width() * (1 - QUARTER), y), FloatPoint(x + width, y + topRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width, y + topRightRadius.height())); + + path.addLineTo(FloatPoint(x + width, y + height - bottomRightRadius.height())); + + path.addBezierCurveTo(FloatPoint(x + width, y + height - bottomRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width - bottomRightRadius.width() * (1 - QUARTER), y + height), FloatPoint(x + width - bottomRightRadius.width(), y + height)); + + path.addLineTo(FloatPoint(x + bottomLeftRadius.width(), y + height)); + + path.addBezierCurveTo(FloatPoint(x + bottomLeftRadius.width() * (1 - QUARTER), y + height), FloatPoint(x, y + height - bottomLeftRadius.height() * (1 - QUARTER)), FloatPoint(x, y + height - bottomLeftRadius.height())); + + path.addLineTo(FloatPoint(x, y + topLeftRadius.height())); + + path.addBezierCurveTo(FloatPoint(x, y + topLeftRadius.height() * (1 - QUARTER)), FloatPoint(x + topLeftRadius.width() * (1 - QUARTER), y), FloatPoint(x + topLeftRadius.width(), y)); + + path.closeSubpath(); + + return path; +} + +Path Path::createRectangle(const FloatRect& rectangle) +{ + Path path; + float x = rectangle.x(); + float y = rectangle.y(); + float width = rectangle.width(); + float height = rectangle.height(); + if (width <= 0.0f || height <= 0.0f) + return path; + + path.moveTo(FloatPoint(x, y)); + path.addLineTo(FloatPoint(x + width, y)); + path.addLineTo(FloatPoint(x + width, y + height)); + path.addLineTo(FloatPoint(x, y + height)); + path.closeSubpath(); + + return path; +} + +Path Path::createEllipse(const FloatPoint& center, float rx, float ry) +{ + float cx = center.x(); + float cy = center.y(); + Path path; + if (rx <= 0.0f || ry <= 0.0f) + return path; + + float x = cx; + float y = cy; + + unsigned step = 0, num = 100; + bool running = true; + while (running) + { + if (step == num) + { + running = false; + break; + } + + float angle = static_cast<float>(step) / static_cast<float>(num) * 2.0f * piFloat; + x = cx + cosf(angle) * rx; + y = cy + sinf(angle) * ry; + + step++; + if (step == 1) + path.moveTo(FloatPoint(x, y)); + else + path.addLineTo(FloatPoint(x, y)); + } + + path.closeSubpath(); + + return path; +} + +Path Path::createCircle(const FloatPoint& center, float r) +{ + return createEllipse(center, r, r); +} + +Path Path::createLine(const FloatPoint& start, const FloatPoint& end) +{ + Path path; + if (start.x() == end.x() && start.y() == end.y()) + return path; + + path.moveTo(start); + path.addLineTo(end); + + return path; +} + +} diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h new file mode 100644 index 0000000..5150649 --- /dev/null +++ b/WebCore/platform/graphics/Path.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * 2006 Rob Buis <buis@kde.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Path_h +#define Path_h + +#if PLATFORM(CG) +typedef struct CGPath PlatformPath; +#elif PLATFORM(QT) +class QPainterPath; +typedef QPainterPath PlatformPath; +#elif PLATFORM(WX) && USE(WXGC) +class wxGraphicsPath; +typedef wxGraphicsPath PlatformPath; +#elif PLATFORM(CAIRO) +namespace WebCore { + struct CairoPath; +} +typedef WebCore::CairoPath PlatformPath; +#else +typedef void PlatformPath; +#endif + +namespace WebCore { + + class AffineTransform; + class FloatPoint; + class FloatSize; + class FloatRect; + class String; + + enum WindRule { + RULE_NONZERO = 0, + RULE_EVENODD = 1 + }; + + enum PathElementType { + PathElementMoveToPoint, + PathElementAddLineToPoint, + PathElementAddQuadCurveToPoint, + PathElementAddCurveToPoint, + PathElementCloseSubpath + }; + + struct PathElement { + PathElementType type; + FloatPoint* points; + }; + + typedef void (*PathApplierFunction) (void* info, const PathElement*); + + class Path { + public: + Path(); + ~Path(); + + Path(const Path&); + Path& operator=(const Path&); + + bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const; + FloatRect boundingRect() const; + + float length(); + FloatPoint pointAtLength(float length, bool& ok); + float normalAngleAtLength(float length, bool& ok); + + void clear(); + bool isEmpty() const; + + void moveTo(const FloatPoint&); + void addLineTo(const FloatPoint&); + void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point); + void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint&); + void addArcTo(const FloatPoint&, const FloatPoint&, float radius); + void closeSubpath(); + + void addArc(const FloatPoint&, float radius, float startAngle, float endAngle, bool anticlockwise); + void addRect(const FloatRect&); + void addEllipse(const FloatRect&); + + void translate(const FloatSize&); + + void setWindingRule(WindRule rule) { m_rule = rule; } + WindRule windingRule() const { return m_rule; } + + String debugString() const; + + PlatformPath* platformPath() const { return m_path; } + + static Path createRoundedRectangle(const FloatRect&, const FloatSize& roundingRadii); + static Path createRoundedRectangle(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); + static Path createRectangle(const FloatRect&); + static Path createEllipse(const FloatPoint& center, float rx, float ry); + static Path createCircle(const FloatPoint& center, float r); + static Path createLine(const FloatPoint&, const FloatPoint&); + + void apply(void* info, PathApplierFunction) const; + void transform(const AffineTransform&); + + private: + PlatformPath* m_path; + WindRule m_rule; + }; + +} + +#endif diff --git a/WebCore/platform/graphics/PathTraversalState.cpp b/WebCore/platform/graphics/PathTraversalState.cpp new file mode 100644 index 0000000..d202649 --- /dev/null +++ b/WebCore/platform/graphics/PathTraversalState.cpp @@ -0,0 +1,207 @@ +/* + * This file is part of the WebKit open source project. + * + * Copyright (C) 2006, 2007 Eric Seidel (eric@webkit.org) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "PathTraversalState.h" + +#include "Path.h" + +#include <math.h> + +namespace WebCore { + +static const float kPathSegmentLengthTolerance = 0.00001f; + +static inline FloatPoint midPoint(const FloatPoint& first, const FloatPoint& second) +{ + return FloatPoint((first.x() + second.x()) / 2.0f, (first.y() + second.y()) / 2.0f); +} + +static inline float distanceLine(const FloatPoint& start, const FloatPoint& end) +{ + return sqrtf((end.x() - start.x()) * (end.x() - start.x()) + (end.y() - start.y()) * (end.y() - start.y())); +} + +struct QuadraticBezier { + QuadraticBezier() { } + QuadraticBezier(const FloatPoint& s, const FloatPoint& c, const FloatPoint& e) + : start(s) + , control(c) + , end(e) + { + } + + float approximateDistance() const + { + return distanceLine(start, control) + distanceLine(control, end); + } + + void split(QuadraticBezier& left, QuadraticBezier& right) const + { + left.control = midPoint(start, control); + right.control = midPoint(control, end); + + FloatPoint leftControlToRightControl = midPoint(left.control, right.control); + left.end = leftControlToRightControl; + right.start = leftControlToRightControl; + + left.start = start; + right.end = end; + } + + FloatPoint start; + FloatPoint control; + FloatPoint end; +}; + +struct CubicBezier { + CubicBezier() { } + CubicBezier(const FloatPoint& s, const FloatPoint& c1, const FloatPoint& c2, const FloatPoint& e) + : start(s) + , control1(c1) + , control2(c2) + , end(e) + { + } + + float approximateDistance() const + { + return distanceLine(start, control1) + distanceLine(control1, control2) + distanceLine(control2, end); + } + + void split(CubicBezier& left, CubicBezier& right) const + { + FloatPoint startToControl1 = midPoint(control1, control2); + + left.start = start; + left.control1 = midPoint(start, control1); + left.control2 = midPoint(left.control1, startToControl1); + + right.control2 = midPoint(control2, end); + right.control1 = midPoint(right.control2, startToControl1); + right.end = end; + + FloatPoint leftControl2ToRightControl1 = midPoint(left.control2, right.control1); + left.end = leftControl2ToRightControl1; + right.start = leftControl2ToRightControl1; + } + + FloatPoint start; + FloatPoint control1; + FloatPoint control2; + FloatPoint end; +}; + +// FIXME: This function is possibly very slow due to the ifs required for proper path measuring +// A simple speed-up would be to use an additional boolean template parameter to control whether +// to use the "fast" version of this function with no PathTraversalState updating, vs. the slow +// version which does update the PathTraversalState. We'll have to shark it to see if that's necessary. +// Another check which is possible up-front (to send us down the fast path) would be to check if +// approximateDistance() + current total distance > desired distance +template<class CurveType> +static float curveLength(PathTraversalState& traversalState, CurveType curve) +{ + Vector<CurveType> curveStack; + curveStack.append(curve); + + float totalLength = 0.0f; + do { + float length = curve.approximateDistance(); + if ((length - distanceLine(curve.start, curve.end)) > kPathSegmentLengthTolerance) { + CurveType left, right; + curve.split(left, right); + curve = left; + curveStack.append(right); + } else { + totalLength += length; + if (traversalState.m_action == PathTraversalState::TraversalPointAtLength + || traversalState.m_action == PathTraversalState::TraversalNormalAngleAtLength) { + traversalState.m_previous = curve.start; + traversalState.m_current = curve.end; + if (traversalState.m_totalLength + totalLength > traversalState.m_desiredLength) + return totalLength; + } + curve = curveStack.last(); + curveStack.removeLast(); + } + } while (!curveStack.isEmpty()); + + return totalLength; +} + +PathTraversalState::PathTraversalState(PathTraversalAction action) + : m_action(action) + , m_success(false) + , m_totalLength(0.0f) + , m_segmentIndex(0) + , m_desiredLength(0.0f) + , m_normalAngle(0.0f) +{ +} + +float PathTraversalState::closeSubpath() +{ + float distance = distanceLine(m_current, m_start); + m_start = m_control1 = m_control2 = m_current; + return distance; +} + +float PathTraversalState::moveTo(const FloatPoint& point) +{ + m_current = m_start = m_control1 = m_control2 = point; + return 0.0f; +} + +float PathTraversalState::lineTo(const FloatPoint& point) +{ + float distance = distanceLine(m_current, point); + m_current = m_control1 = m_control2 = point; + return distance; +} + +float PathTraversalState::quadraticBezierTo(const FloatPoint& newControl, const FloatPoint& newEnd) +{ + float distance = curveLength<QuadraticBezier>(*this, QuadraticBezier(m_current, newControl, newEnd)); + + m_control1 = newControl; + m_control2 = newEnd; + + if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength) + m_current = newEnd; + + return distance; +} + +float PathTraversalState::cubicBezierTo(const FloatPoint& newControl1, const FloatPoint& newControl2, const FloatPoint& newEnd) +{ + float distance = curveLength<CubicBezier>(*this, CubicBezier(m_current, newControl1, newControl2, newEnd)); + + m_control1 = newEnd; + m_control2 = newControl2; + + if (m_action != TraversalPointAtLength && m_action != TraversalNormalAngleAtLength) + m_current = newEnd; + + return distance; +} + +} + diff --git a/WebCore/platform/graphics/PathTraversalState.h b/WebCore/platform/graphics/PathTraversalState.h new file mode 100644 index 0000000..5b75767 --- /dev/null +++ b/WebCore/platform/graphics/PathTraversalState.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006, 2007 Eric Seidel <eric@webkit.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PathTraversalState_h +#define PathTraversalState_h + +#include "FloatPoint.h" +#include <wtf/Vector.h> + +namespace WebCore { + + class Path; + + class PathTraversalState { + public: + enum PathTraversalAction { + TraversalTotalLength, + TraversalPointAtLength, + TraversalSegmentAtLength, + TraversalNormalAngleAtLength + }; + + PathTraversalState(PathTraversalAction); + + float closeSubpath(); + float moveTo(const FloatPoint&); + float lineTo(const FloatPoint&); + float quadraticBezierTo(const FloatPoint& newControl, const FloatPoint& newEnd); + float cubicBezierTo(const FloatPoint& newControl1, const FloatPoint& newControl2, const FloatPoint& newEnd); + + public: + PathTraversalAction m_action; + bool m_success; + + FloatPoint m_current; + FloatPoint m_start; + FloatPoint m_control1; + FloatPoint m_control2; + + float m_totalLength; + unsigned m_segmentIndex; + float m_desiredLength; + + // For normal calculations + FloatPoint m_previous; + float m_normalAngle; // degrees + }; +} + +#endif diff --git a/WebCore/platform/graphics/Pen.cpp b/WebCore/platform/graphics/Pen.cpp new file mode 100644 index 0000000..a3dcb86 --- /dev/null +++ b/WebCore/platform/graphics/Pen.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Pen.h" + +namespace WebCore { + +Pen::Pen(const Color &color, unsigned width, PenStyle style) : m_style(style), m_width(width), m_color(color) +{ +} + +const Color &Pen::color() const +{ + return m_color; +} + +unsigned Pen::width() const +{ + return m_width; +} + +Pen::PenStyle Pen::style() const +{ + return m_style; +} + +void Pen::setColor(const Color &color) +{ + m_color = color; +} + +void Pen::setWidth(unsigned width) +{ + m_width = width; +} + +void Pen::setStyle(PenStyle style) +{ + m_style = style; +} + +bool Pen::operator==(const Pen &compareTo) const +{ + return (m_width == compareTo.m_width) && + (m_style == compareTo.m_style) && + (m_color == compareTo.m_color); +} + +bool Pen::operator!=(const Pen &compareTo) const +{ + return !(*this == compareTo); +} + +} diff --git a/WebCore/platform/graphics/Pen.h b/WebCore/platform/graphics/Pen.h new file mode 100644 index 0000000..cb45a2e --- /dev/null +++ b/WebCore/platform/graphics/Pen.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2003-6 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Pen_h +#define Pen_h + +#include "Color.h" + +#if PLATFORM(WX) +class wxPen; +#endif + +namespace WebCore { + +class Pen { +public: + enum PenStyle { + NoPen, + SolidLine, + DotLine, + DashLine + }; + + Pen(const Color &c = Color::black, unsigned w = 0, PenStyle ps = SolidLine); + + const Color &color() const; + unsigned width() const; + PenStyle style() const; + + void setColor(const Color &); + void setWidth(unsigned); + void setStyle(PenStyle); + + bool operator==(const Pen &) const; + bool operator!=(const Pen &) const; + +#if PLATFORM(WX) + Pen(const wxPen&); + operator wxPen() const; +#endif + +private: + PenStyle m_style; + unsigned m_width; + Color m_color; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/SegmentedFontData.cpp b/WebCore/platform/graphics/SegmentedFontData.cpp new file mode 100644 index 0000000..ceefe4f --- /dev/null +++ b/WebCore/platform/graphics/SegmentedFontData.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SegmentedFontData.h" + +#include "SimpleFontData.h" +#include <wtf/Assertions.h> + +namespace WebCore { + +SegmentedFontData::~SegmentedFontData() +{ +} + +const SimpleFontData* SegmentedFontData::fontDataForCharacter(UChar32 c) const +{ + Vector<FontDataRange>::const_iterator end = m_ranges.end(); + for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) { + if (it->from() <= c && it->to() >= c) + return it->fontData(); + } + return m_ranges[0].fontData(); +} + +bool SegmentedFontData::containsCharacters(const UChar* characters, int length) const +{ + Vector<FontDataRange>::const_iterator end = m_ranges.end(); + for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) { + if (it->from() <= characters[0] && it->to() >= characters[0]) + return true; + } + return false; +} + +bool SegmentedFontData::isCustomFont() const +{ + // All segmented fonts are custom fonts. + return true; +} + +bool SegmentedFontData::isLoading() const +{ + Vector<FontDataRange>::const_iterator end = m_ranges.end(); + for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) { + if (it->fontData()->isLoading()) + return true; + } + return false; +} + +bool SegmentedFontData::isSegmented() const +{ + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/SegmentedFontData.h b/WebCore/platform/graphics/SegmentedFontData.h new file mode 100644 index 0000000..1adec15 --- /dev/null +++ b/WebCore/platform/graphics/SegmentedFontData.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SegmentedFontData_h +#define SegmentedFontData_h + +#include "FontData.h" +#include <wtf/Vector.h> + +namespace WebCore { + +class SimpleFontData; + +struct FontDataRange { + FontDataRange(UChar32 from, UChar32 to, const SimpleFontData* fontData) + : m_from(from) + , m_to(to) + , m_fontData(fontData) + { + } + + UChar32 from() const { return m_from; } + UChar32 to() const { return m_to; } + const SimpleFontData* fontData() const { return m_fontData; } + +private: + UChar32 m_from; + UChar32 m_to; + const SimpleFontData* m_fontData; +}; + +class SegmentedFontData : public FontData { +public: + virtual ~SegmentedFontData(); + + virtual const SimpleFontData* fontDataForCharacter(UChar32) const; + virtual bool containsCharacters(const UChar*, int length) const; + + virtual bool isCustomFont() const; + virtual bool isLoading() const; + virtual bool isSegmented() const; + + void appendRange(const FontDataRange& range) { m_ranges.append(range); } + unsigned numRanges() const { return m_ranges.size(); } + const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; } + +private: + Vector<FontDataRange, 1> m_ranges; +}; + +} // namespace WebCore + +#endif // SegmentedFontData_h diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp new file mode 100644 index 0000000..24812f7 --- /dev/null +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2005, 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#if ENABLE(SVG_FONTS) +#include "SVGFontData.h" +#include "SVGFontFaceElement.h" +#endif + +#include <wtf/MathExtras.h> + +namespace WebCore { + +SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) + : m_font(f) + , m_treatAsFixedPitch(false) +#if ENABLE(SVG_FONTS) + , m_svgFontData(svgFontData) +#endif + , m_isCustomFont(customFont) + , m_isLoading(loading) + , m_smallCapsFontData(0) +{ +#if ENABLE(SVG_FONTS) && !PLATFORM(QT) + if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) { + m_unitsPerEm = svgFontFaceElement->unitsPerEm(); + + double scale = f.size(); + if (m_unitsPerEm) + scale /= m_unitsPerEm; + + m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); + m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); + m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); + m_lineGap = 0.1f * f.size(); + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + m_spaceGlyph = 0; + m_spaceWidth = 0; + m_adjustedSpaceWidth = 0; + determinePitch(); + m_missingGlyphData.fontData = this; + m_missingGlyphData.glyph = 0; + return; + } +#endif + + platformInit(); + + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + if (!glyphPageZero) { + LOG_ERROR("Failed to get glyph page zero."); + m_spaceGlyph = 0; + m_spaceWidth = 0; + m_adjustedSpaceWidth = 0; + determinePitch(); + m_missingGlyphData.fontData = this; + m_missingGlyphData.glyph = 0; + return; + } + + // Nasty hack to determine if we should round or ceil space widths. + // If the font is monospace or fake monospace we ceil to ensure that + // every character and the space are the same width. Otherwise we round. + m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph; + float width = widthForGlyph(m_spaceGlyph); + m_spaceWidth = width; + determinePitch(); + m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width); + + // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE. + // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph. + // See <http://bugs.webkit.org/show_bug.cgi?id=13178> + // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0, + // are mapped to the ZERO WIDTH SPACE glyph. + Glyph zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph; + if (zeroWidthSpaceGlyph) { + if (zeroWidthSpaceGlyph != m_spaceGlyph) + m_glyphToWidthMap.setWidthForGlyph(zeroWidthSpaceGlyph, 0); + else + LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width not overridden."); + } + + m_missingGlyphData.fontData = this; + m_missingGlyphData.glyph = 0; +} + +SimpleFontData::~SimpleFontData() +{ +#if 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 +{ + float width = m_glyphToWidthMap.widthForGlyph(glyph); + if (width != cGlyphWidthUnknown) + return width; + + width = platformWidthForGlyph(glyph); + m_glyphToWidthMap.setWidthForGlyph(glyph, width); + + return width; +} + +const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const +{ + return this; +} + +bool SimpleFontData::isSegmented() const +{ + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h new file mode 100644 index 0000000..c444a6f --- /dev/null +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -0,0 +1,184 @@ +/* + * This file is part of the internal font implementation. + * + * Copyright (C) 2006, 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. + * + */ + +#ifndef SimpleFontData_h +#define SimpleFontData_h + +#include "FontData.h" +#include "FontPlatformData.h" +#include "GlyphPageTreeNode.h" +#include "GlyphWidthMap.h" +#include <wtf/OwnPtr.h> + +#if PLATFORM(MAC) +typedef struct OpaqueATSUStyle* ATSUStyle; +#endif + +#if PLATFORM(WIN) +#include <usp10.h> +#endif + +#if PLATFORM(CAIRO) +#include <cairo.h> +#endif + +namespace WebCore { + +class FontDescription; +class FontPlatformData; +class SharedBuffer; +class SVGFontData; +class WidthMap; + +enum Pitch { UnknownPitch, FixedPitch, VariablePitch }; + +class SimpleFontData : public FontData { +public: + SimpleFontData(const FontPlatformData&, bool customFont = false, bool loading = false, SVGFontData* data = 0); + virtual ~SimpleFontData(); + +public: + const FontPlatformData& platformData() const { return m_font; } + SimpleFontData* smallCapsFontData(const FontDescription& fontDescription) const; + + // vertical metrics + int ascent() const { return m_ascent; } + int descent() const { return m_descent; } + int lineSpacing() const { return m_lineSpacing; } + int lineGap() const { return m_lineGap; } + float xHeight() const { return m_xHeight; } + unsigned unitsPerEm() const { return m_unitsPerEm; } + + float widthForGlyph(Glyph) const; + float platformWidthForGlyph(Glyph) const; + + virtual const SimpleFontData* fontDataForCharacter(UChar32) const; + virtual bool containsCharacters(const UChar*, int length) const; + + void determinePitch(); + Pitch pitch() const { return m_treatAsFixedPitch ? FixedPitch : VariablePitch; } + +#if ENABLE(SVG_FONTS) + SVGFontData* svgFontData() const { return m_svgFontData.get(); } + bool isSVGFont() const { return m_svgFontData; } +#else + bool isSVGFont() const { return false; } +#endif + + virtual bool isCustomFont() const { return m_isCustomFont; } + virtual bool isLoading() const { return m_isLoading; } + virtual bool isSegmented() const; + + const GlyphData& missingGlyphData() const { return m_missingGlyphData; } + +#if PLATFORM(MAC) + NSFont* getNSFont() const { return m_font.font(); } + void checkShapesArabic() const; + bool shapesArabic() const + { + if (!m_checkedShapesArabic) + checkShapesArabic(); + return m_shapesArabic; + } +#endif + +#if PLATFORM(WIN) + bool isSystemFont() const { return m_isSystemFont; } + SCRIPT_FONTPROPERTIES* scriptFontProperties() const; + SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; } + + static void setShouldApplyMacAscentHack(bool); + static bool shouldApplyMacAscentHack(); +#endif + +#if PLATFORM(CAIRO) + void setFont(cairo_t*) const; +#endif + +#if PLATFORM(WX) + wxFont getWxFont() const { return m_font.font(); } +#endif + +private: + void platformInit(); + void platformDestroy(); + + void commonInit(); + +#if PLATFORM(WIN) + void initGDIFont(); + void platformCommonDestroy(); + float widthForGDIGlyph(Glyph glyph) const; +#endif + +public: + int m_ascent; + int m_descent; + int m_lineSpacing; + int m_lineGap; + float m_xHeight; + unsigned m_unitsPerEm; + + FontPlatformData m_font; + + mutable GlyphWidthMap m_glyphToWidthMap; + + bool m_treatAsFixedPitch; + +#if ENABLE(SVG_FONTS) + OwnPtr<SVGFontData> m_svgFontData; +#endif + + bool m_isCustomFont; // Whether or not we are custom font loaded via @font-face + bool m_isLoading; // Whether or not this custom font is still in the act of loading. + + Glyph m_spaceGlyph; + float m_spaceWidth; + float m_adjustedSpaceWidth; + + GlyphData m_missingGlyphData; + + mutable SimpleFontData* m_smallCapsFontData; + +#if PLATFORM(CG) + float m_syntheticBoldOffset; +#endif + +#if PLATFORM(MAC) + void* m_styleGroup; + mutable ATSUStyle m_ATSUStyle; + mutable bool m_ATSUStyleInitialized; + mutable bool m_ATSUMirrors; + mutable bool m_checkedShapesArabic; + mutable bool m_shapesArabic; +#endif + +#if PLATFORM(WIN) + bool m_isSystemFont; + mutable SCRIPT_CACHE m_scriptCache; + mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties; +#endif +}; + +} // namespace WebCore + +#endif // SimpleFontData_h diff --git a/WebCore/platform/graphics/StringTruncator.cpp b/WebCore/platform/graphics/StringTruncator.cpp new file mode 100644 index 0000000..0490a9f --- /dev/null +++ b/WebCore/platform/graphics/StringTruncator.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "StringTruncator.h" + +#include "CharacterNames.h" +#include "Font.h" +#include "FontPlatformData.h" +#include "TextBreakIterator.h" +#include <wtf/Assertions.h> +#include <wtf/Vector.h> + +namespace WebCore { + +#define STRING_BUFFER_SIZE 2048 + +typedef unsigned TruncationFunction(const String&, unsigned length, unsigned keepCount, UChar* buffer); + +static inline int textBreakAtOrPreceding(TextBreakIterator* it, int offset) +{ + if (isTextBreak(it, offset)) + return offset; + + int result = textBreakPreceding(it, offset); + return result == TextBreakDone ? 0 : result; +} + +static inline int boundedTextBreakFollowing(TextBreakIterator* it, int offset, int length) +{ + int result = textBreakFollowing(it, offset); + return result == TextBreakDone ? length : result; +} + +static unsigned centerTruncateToBuffer(const String& string, unsigned length, unsigned keepCount, UChar* buffer) +{ + ASSERT(keepCount < length); + ASSERT(keepCount < STRING_BUFFER_SIZE); + + unsigned omitStart = (keepCount + 1) / 2; + TextBreakIterator* it = characterBreakIterator(string.characters(), length); + unsigned omitEnd = boundedTextBreakFollowing(it, omitStart + (length - keepCount) - 1, length); + omitStart = textBreakAtOrPreceding(it, omitStart); + + unsigned truncatedLength = omitStart + 1 + (length - omitEnd); + ASSERT(truncatedLength <= length); + + memcpy(buffer, string.characters(), sizeof(UChar) * omitStart); + buffer[omitStart] = horizontalEllipsis; + memcpy(&buffer[omitStart + 1], &string.characters()[omitEnd], sizeof(UChar) * (length - omitEnd)); + + return truncatedLength; +} + +static unsigned rightTruncateToBuffer(const String& string, unsigned length, unsigned keepCount, UChar* buffer) +{ + ASSERT(keepCount < length); + ASSERT(keepCount < STRING_BUFFER_SIZE); + + TextBreakIterator* it = characterBreakIterator(string.characters(), length); + unsigned keepLength = textBreakAtOrPreceding(it, keepCount); + unsigned truncatedLength = keepLength + 1; + + memcpy(buffer, string.characters(), sizeof(UChar) * keepLength); + buffer[keepLength] = horizontalEllipsis; + + return truncatedLength; +} + +static float stringWidth(const Font& renderer, const UChar* characters, unsigned length, bool disableRoundingHacks) +{ + TextRun run(characters, length); + if (disableRoundingHacks) + run.disableRoundingHacks(); + return renderer.floatWidth(run); +} + +static String truncateString(const String& string, float maxWidth, const Font& font, TruncationFunction truncateToBuffer, bool disableRoundingHacks) +{ + if (string.isEmpty()) + return string; + + ASSERT(maxWidth >= 0); + + float currentEllipsisWidth = stringWidth(font, &horizontalEllipsis, 1, disableRoundingHacks); + + UChar stringBuffer[STRING_BUFFER_SIZE]; + unsigned truncatedLength; + unsigned keepCount; + unsigned length = string.length(); + + if (length > STRING_BUFFER_SIZE) { + keepCount = STRING_BUFFER_SIZE - 1; // need 1 character for the ellipsis + truncatedLength = centerTruncateToBuffer(string, length, keepCount, stringBuffer); + } else { + keepCount = length; + memcpy(stringBuffer, string.characters(), sizeof(UChar) * length); + truncatedLength = length; + } + + float width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks); + if (width <= maxWidth) + return string; + + unsigned keepCountForLargestKnownToFit = 0; + float widthForLargestKnownToFit = currentEllipsisWidth; + + unsigned keepCountForSmallestKnownToNotFit = keepCount; + float widthForSmallestKnownToNotFit = width; + + if (currentEllipsisWidth >= maxWidth) { + keepCountForLargestKnownToFit = 1; + keepCountForSmallestKnownToNotFit = 2; + } + + while (keepCountForLargestKnownToFit + 1 < keepCountForSmallestKnownToNotFit) { + ASSERT(widthForLargestKnownToFit <= maxWidth); + ASSERT(widthForSmallestKnownToNotFit > maxWidth); + + float ratio = (keepCountForSmallestKnownToNotFit - keepCountForLargestKnownToFit) + / (widthForSmallestKnownToNotFit - widthForLargestKnownToFit); + keepCount = static_cast<unsigned>(maxWidth * ratio); + + if (keepCount <= keepCountForLargestKnownToFit) { + keepCount = keepCountForLargestKnownToFit + 1; + } else if (keepCount >= keepCountForSmallestKnownToNotFit) { + keepCount = keepCountForSmallestKnownToNotFit - 1; + } + + ASSERT(keepCount < length); + ASSERT(keepCount > 0); + ASSERT(keepCount < keepCountForSmallestKnownToNotFit); + ASSERT(keepCount > keepCountForLargestKnownToFit); + + truncatedLength = truncateToBuffer(string, length, keepCount, stringBuffer); + + width = stringWidth(font, stringBuffer, truncatedLength, disableRoundingHacks); + if (width <= maxWidth) { + keepCountForLargestKnownToFit = keepCount; + widthForLargestKnownToFit = width; + } else { + keepCountForSmallestKnownToNotFit = keepCount; + widthForSmallestKnownToNotFit = width; + } + } + + if (keepCountForLargestKnownToFit == 0) { + keepCountForLargestKnownToFit = 1; + } + + if (keepCount != keepCountForLargestKnownToFit) { + keepCount = keepCountForLargestKnownToFit; + truncatedLength = truncateToBuffer(string, length, keepCount, stringBuffer); + } + + return String(stringBuffer, truncatedLength); +} + +String StringTruncator::centerTruncate(const String& string, float maxWidth, const Font& font, bool disableRoundingHacks) +{ + return truncateString(string, maxWidth, font, centerTruncateToBuffer, disableRoundingHacks); +} + +String StringTruncator::rightTruncate(const String& string, float maxWidth, const Font& font, bool disableRoundingHacks) +{ + return truncateString(string, maxWidth, font, rightTruncateToBuffer, disableRoundingHacks); +} + +float StringTruncator::width(const String& string, const Font& font, bool disableRoundingHacks) +{ + return stringWidth(font, string.characters(), string.length(), disableRoundingHacks); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/StringTruncator.h b/WebCore/platform/graphics/StringTruncator.h new file mode 100644 index 0000000..0a8532b --- /dev/null +++ b/WebCore/platform/graphics/StringTruncator.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef StringTruncator_h +#define StringTruncator_h + +namespace WebCore { + + class Font; + class String; + + class StringTruncator { + public: + static String centerTruncate(const String&, float maxWidth, const Font&, bool disableRoundingHacks = true); + static String rightTruncate(const String&, float maxWidth, const Font&, bool disableRoundingHacks = true); + static float width(const String&, const Font&, bool disableRoundingHacks = true); + }; + +} // namespace WebCore + +#endif // !defined(StringTruncator_h) diff --git a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp b/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp new file mode 100644 index 0000000..1080d2d --- /dev/null +++ b/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp @@ -0,0 +1,281 @@ +/* + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AffineTransform.h" + +#include "IntRect.h" +#include "FloatRect.h" + +#include <cairo.h> + +namespace WebCore { + +static const double deg2rad = 0.017453292519943295769; // pi/180 + +AffineTransform::AffineTransform() +{ + cairo_matrix_init_identity(&m_transform); +} + +AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) +{ + cairo_matrix_init(&m_transform, a, c, b, d, tx, ty); +} + +AffineTransform::AffineTransform(const cairo_matrix_t &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); +} + +void AffineTransform::map(double x, double y, double* x2, double* y2) const +{ + *x2 = x; + *y2 = y; + cairo_matrix_transform_point(&m_transform, x2, y2); +} + +IntRect AffineTransform::mapRect(const IntRect &rect) const +{ + FloatRect floatRect(rect); + FloatRect enclosingFloatRect = this->mapRect(floatRect); + + return enclosingIntRect(enclosingFloatRect); +} + +FloatRect AffineTransform::mapRect(const FloatRect &rect) const +{ + double rectMinX = rect.x(); + double rectMaxX = rect.x() + rect.width(); + double rectMinY = rect.y(); + double rectMaxY = rect.y() + rect.height(); + + double px = rectMinX; + double py = rectMinY; + cairo_matrix_transform_point(&m_transform, &px, &py); + + double enclosingRectMinX = px; + double enclosingRectMinY = py; + double enclosingRectMaxX = px; + double enclosingRectMaxY = py; + + px = rectMaxX; + py = rectMinY; + cairo_matrix_transform_point(&m_transform, &px, &py); + if (px < enclosingRectMinX) + enclosingRectMinX = px; + else if (px > enclosingRectMaxX) + enclosingRectMaxX = px; + if (py < enclosingRectMinY) + enclosingRectMinY = py; + else if (py > enclosingRectMaxY) + enclosingRectMaxY = py; + + px = rectMaxX; + py = rectMaxY; + cairo_matrix_transform_point(&m_transform, &px, &py); + if (px < enclosingRectMinX) + enclosingRectMinX = px; + else if (px > enclosingRectMaxX) + enclosingRectMaxX = px; + if (py < enclosingRectMinY) + enclosingRectMinY = py; + else if (py > enclosingRectMaxY) + enclosingRectMaxY = py; + + px = rectMinX; + py = rectMaxY; + cairo_matrix_transform_point(&m_transform, &px, &py); + if (px < enclosingRectMinX) + enclosingRectMinX = px; + else if (px > enclosingRectMaxX) + enclosingRectMaxX = px; + if (py < enclosingRectMinY) + enclosingRectMinY = py; + else if (py > enclosingRectMaxY) + enclosingRectMaxY = py; + + + double enclosingRectWidth = enclosingRectMaxX - enclosingRectMinX; + double enclosingRectHeight = enclosingRectMaxY - enclosingRectMinY; + + return FloatRect(enclosingRectMinX, enclosingRectMinY, enclosingRectWidth, enclosingRectHeight); +} + +bool AffineTransform::isIdentity() const +{ + return ((m_transform.xx == 1) && (m_transform.yy == 1) + && (m_transform.xy == 0) && (m_transform.yx == 0) + && (m_transform.x0 == 0) && (m_transform.y0 == 0)); +} + +double AffineTransform::a() const +{ + return m_transform.xx; +} + +void AffineTransform::setA(double a) +{ + m_transform.xx = a; +} + +double AffineTransform::b() const +{ + return m_transform.xy; +} + +void AffineTransform::setB(double b) +{ + m_transform.xy = b; +} + +double AffineTransform::c() const +{ + return m_transform.yx; +} + +void AffineTransform::setC(double c) +{ + m_transform.yx = c; +} + +double AffineTransform::d() const +{ + return m_transform.yy; +} + +void AffineTransform::setD(double d) +{ + m_transform.yy = d; +} + +double AffineTransform::e() const +{ + return m_transform.x0; +} + +void AffineTransform::setE(double e) +{ + m_transform.x0 = e; +} + +double AffineTransform::f() const +{ + return m_transform.y0; +} + +void AffineTransform::setF(double f) +{ + m_transform.y0 = f; +} + +void AffineTransform::reset() +{ + cairo_matrix_init_identity(&m_transform); +} + +AffineTransform &AffineTransform::scale(double sx, double sy) +{ + cairo_matrix_scale(&m_transform, sx, sy); + return *this; +} + +AffineTransform &AffineTransform::rotate(double d) +{ + cairo_matrix_rotate(&m_transform, d * deg2rad); + return *this; +} + +AffineTransform &AffineTransform::translate(double tx, double ty) +{ + cairo_matrix_translate(&m_transform, tx, ty); + return *this; +} + +AffineTransform &AffineTransform::shear(double sx, double sy) +{ + cairo_matrix_t shear; + cairo_matrix_init(&shear, 1, sy, sx, 1, 0, 0); + + cairo_matrix_t result; + cairo_matrix_multiply(&result, &shear, &m_transform); + m_transform = result; + + return *this; +} + +double AffineTransform::det() const +{ + return m_transform.xx * m_transform.yy - m_transform.xy * m_transform.yx; +} + +AffineTransform AffineTransform::inverse() const +{ + if (!isInvertible()) return AffineTransform(); + + cairo_matrix_t result = m_transform; + cairo_matrix_invert(&result); + return AffineTransform(result); +} + +AffineTransform::operator cairo_matrix_t() const +{ + return m_transform; +} + +bool AffineTransform::operator== (const AffineTransform &m2) const +{ + return ((m_transform.xx == m2.m_transform.xx) + && (m_transform.yy == m2.m_transform.yy) + && (m_transform.xy == m2.m_transform.xy) + && (m_transform.yx == m2.m_transform.yx) + && (m_transform.x0 == m2.m_transform.x0) + && (m_transform.y0 == m2.m_transform.y0)); + +} + +AffineTransform &AffineTransform::operator*= (const AffineTransform &m2) +{ + cairo_matrix_t result; + cairo_matrix_multiply(&result, &m_transform, &m2.m_transform); + m_transform = result; + + return *this; +} + +AffineTransform AffineTransform::operator* (const AffineTransform &m2) +{ + cairo_matrix_t result; + cairo_matrix_multiply(&result, &m_transform, &m2.m_transform); + return result; +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/cairo/CairoPath.h b/WebCore/platform/graphics/cairo/CairoPath.h new file mode 100644 index 0000000..b761ce6 --- /dev/null +++ b/WebCore/platform/graphics/cairo/CairoPath.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef CairoPath_h +#define CairoPath_h + +#include <cairo.h> + +namespace WebCore { + + // This is necessary since cairo_path_fixed_t isn't exposed in Cairo's public API. + struct CairoPath { + cairo_t* m_cr; + + CairoPath() + { + static cairo_surface_t* pathSurface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1); + m_cr = cairo_create(pathSurface); + } + + ~CairoPath() + { + cairo_destroy(m_cr); + } + }; + +} // namespace WebCore + +#endif // CairoPath_h diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp new file mode 100644 index 0000000..06e926f --- /dev/null +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -0,0 +1,65 @@ +/* + * 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* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, + int from, int numGlyphs, const FloatPoint& point) const +{ + cairo_t* cr = graphicsContext->platformContext(); + cairo_save(cr); + + // 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); + + 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); + } + cairo_show_glyphs(cr, glyphs, numGlyphs); + + cairo_restore(cr); +} + +} diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp new file mode 100644 index 0000000..90e34e9 --- /dev/null +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -0,0 +1,930 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#if PLATFORM(CAIRO) + +#include "AffineTransform.h" +#include "CairoPath.h" +#include "FloatRect.h" +#include "Font.h" +#include "ImageBuffer.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "Path.h" +#include "SimpleFontData.h" +#include <cairo.h> +#include <math.h> +#include <stdio.h> +#include <wtf/MathExtras.h> + +#if PLATFORM(GTK) +#include <gdk/gdk.h> +#include <pango/pango.h> +#elif PLATFORM(WIN) +#include <cairo-win32.h> +#endif +#include "GraphicsContextPlatformPrivateCairo.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace WebCore { + +static inline void setColor(cairo_t* cr, const Color& col) +{ + float red, green, blue, alpha; + col.getRGBA(red, green, blue, alpha); + cairo_set_source_rgba(cr, red, green, blue, alpha); +} + +// A fillRect helper +static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col) +{ + setColor(cr, col); + cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_fill(cr); +} + +GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate) +{ + m_data->cr = cairo_reference(cr); + setPaintingDisabled(!cr); +} + +GraphicsContext::~GraphicsContext() +{ + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +AffineTransform GraphicsContext::getCTM() const +{ + cairo_t* cr = platformContext(); + cairo_matrix_t m; + cairo_get_matrix(cr, &m); + return m; +} + +cairo_t* GraphicsContext::platformContext() const +{ + return m_data->cr; +} + +void GraphicsContext::savePlatformState() +{ + cairo_save(m_data->cr); + m_data->save(); +} + +void GraphicsContext::restorePlatformState() +{ + cairo_restore(m_data->cr); + m_data->restore(); +} + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_save(cr); + + if (fillColor().alpha()) + fillRectSourceOver(cr, rect, fillColor()); + + if (strokeStyle() != NoStroke) { + setColor(cr, strokeColor()); + FloatRect r(rect); + r.inflate(-.5f); + cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); + cairo_set_line_width(cr, 1.0); + cairo_stroke(cr); + } + + cairo_restore(cr); +} + +// FIXME: Now that this is refactored, it should be shared by all contexts. +static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle style) +{ + // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic + // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., + // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave + // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. + if (style == DottedStroke || style == DashedStroke) { + if (p1.x() == p2.x()) { + p1.setY(p1.y() + strokeWidth); + p2.setY(p2.y() - strokeWidth); + } + else { + p1.setX(p1.x() + strokeWidth); + p2.setX(p2.x() - strokeWidth); + } + } + + if (static_cast<int>(strokeWidth) % 2) { + if (p1.x() == p2.x()) { + // We're a vertical line. Adjust our x. + p1.setX(p1.x() + 0.5); + p2.setX(p2.x() + 0.5); + } + else { + // We're a horizontal line. Adjust our y. + p1.setY(p1.y() + 0.5); + p2.setY(p2.y() + 0.5); + } + } +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + StrokeStyle style = strokeStyle(); + if (style == NoStroke) + return; + + cairo_t* cr = m_data->cr; + cairo_save(cr); + + float width = strokeThickness(); + if (width < 1) + width = 1; + + FloatPoint p1 = point1; + FloatPoint p2 = point2; + bool isVerticalLine = (p1.x() == p2.x()); + + adjustLineToPixelBoundaries(p1, p2, width, style); + cairo_set_line_width(cr, width); + + int patWidth = 0; + switch (style) { + case NoStroke: + case SolidStroke: + break; + case DottedStroke: + patWidth = static_cast<int>(width); + break; + case DashedStroke: + patWidth = 3*static_cast<int>(width); + break; + } + + setColor(cr, strokeColor()); + + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + + if (patWidth) { + // Do a rect fill of our endpoints. This ensures we always have the + // appearance of being a border. We then draw the actual dotted/dashed line. + if (isVerticalLine) { + fillRectSourceOver(cr, FloatRect(p1.x() - width/2, p1.y() - width, width, width), strokeColor()); + fillRectSourceOver(cr, FloatRect(p2.x() - width/2, p2.y(), width, width), strokeColor()); + } else { + fillRectSourceOver(cr, FloatRect(p1.x() - width, p1.y() - width/2, width, width), strokeColor()); + fillRectSourceOver(cr, FloatRect(p2.x(), p2.y() - width/2, width, width), strokeColor()); + } + + // Example: 80 pixels with a width of 30 pixels. + // Remainder is 20. The maximum pixels of line we could paint + // will be 50 pixels. + int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*static_cast<int>(width); + int remainder = distance%patWidth; + int coverage = distance-remainder; + int numSegments = coverage/patWidth; + + float patternOffset = 0; + // Special case 1px dotted borders for speed. + if (patWidth == 1) + patternOffset = 1.0; + else { + bool evenNumberOfSegments = numSegments%2 == 0; + if (remainder) + evenNumberOfSegments = !evenNumberOfSegments; + if (evenNumberOfSegments) { + if (remainder) { + patternOffset += patWidth - remainder; + patternOffset += remainder/2; + } + else + patternOffset = patWidth/2; + } + else if (!evenNumberOfSegments) { + if (remainder) + patternOffset = (patWidth - remainder)/2; + } + } + + double dash = patWidth; + cairo_set_dash(cr, &dash, 1, patternOffset); + } + + cairo_move_to(cr, p1.x(), p1.y()); + cairo_line_to(cr, p2.x(), p2.y()); + + cairo_stroke(cr); + cairo_restore(cr); +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_save(cr); + float yRadius = .5 * rect.height(); + float xRadius = .5 * rect.width(); + cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius); + cairo_scale(cr, xRadius, yRadius); + cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI); + cairo_restore(cr); + + if (fillColor().alpha()) { + setColor(cr, fillColor()); + cairo_fill_preserve(cr); + } + + if (strokeStyle() != NoStroke) { + setColor(cr, strokeColor()); + cairo_set_line_width(cr, strokeThickness()); + cairo_stroke(cr); + } + + cairo_new_path(cr); +} + +// 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) + 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 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); + setColor(cr, strokeColor()); + cairo_set_line_width(cr, strokeThickness()); + cairo_stroke(cr); + cairo_restore(cr); +} + +void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + if (npoints <= 1) + return; + + cairo_t* cr = m_data->cr; + + cairo_save(cr); + cairo_set_antialias(cr, shouldAntialias ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); + cairo_move_to(cr, points[0].x(), points[0].y()); + for (size_t i = 1; i < npoints; i++) + cairo_line_to(cr, points[i].x(), points[i].y()); + cairo_close_path(cr); + + if (fillColor().alpha()) { + setColor(cr, fillColor()); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill_preserve(cr); + } + + if (strokeStyle() != NoStroke) { + setColor(cr, strokeColor()); + cairo_set_line_width(cr, strokeThickness()); + cairo_stroke(cr); + } + + cairo_new_path(cr); + cairo_restore(cr); +} + +void GraphicsContext::fillRect(const IntRect& rect, const Color& color) +{ + if (paintingDisabled()) + return; + + if (color.alpha()) + fillRectSourceOver(m_data->cr, rect, color); +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +{ + if (paintingDisabled()) + return; + + if (color.alpha()) + fillRectSourceOver(m_data->cr, rect, color); +} + +void GraphicsContext::clip(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); + cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); + cairo_clip(cr); + cairo_set_fill_rule(cr, savedFillRule); + m_data->clip(rect); +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + 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()); + + // 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_restore(cr); +} + +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +{ + if (paintingDisabled()) + return; + + // This is a workaround for http://bugs.webkit.org/show_bug.cgi?id=15659 + StrokeStyle savedStrokeStyle = strokeStyle(); + setStrokeStyle(SolidStroke); + + IntPoint endPoint = origin + IntSize(width, 0); + drawLine(origin, endPoint); + + setStrokeStyle(savedStrokeStyle); +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_save(cr); + + // Convention is green for grammar, red for spelling + // These need to become configurable + if (grammar) + cairo_set_source_rgb(cr, 0, 1, 0); + else + cairo_set_source_rgb(cr, 1, 0, 0); + +#if PLATFORM(GTK) + // We ignore most of the provided constants in favour of the platform style + pango_cairo_show_error_underline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness); +#else + notImplemented(); +#endif + + cairo_restore(cr); +} + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +{ + FloatRect result; + double x = frect.x(); + double y = frect.y(); + cairo_t* cr = m_data->cr; + cairo_user_to_device(cr, &x, &y); + x = round(x); + y = round(y); + cairo_device_to_user(cr, &x, &y); + result.setX(static_cast<float>(x)); + result.setY(static_cast<float>(y)); + x = frect.width(); + y = frect.height(); + cairo_user_to_device_distance(cr, &x, &y); + x = round(x); + y = round(y); + cairo_device_to_user_distance(cr, &x, &y); + result.setWidth(static_cast<float>(x)); + result.setHeight(static_cast<float>(y)); + return result; +} + +void GraphicsContext::translate(float x, float y) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_translate(cr, x, y); + m_data->translate(x, y); +} + +IntPoint GraphicsContext::origin() +{ + cairo_matrix_t matrix; + cairo_t* cr = m_data->cr; + cairo_get_matrix(cr, &matrix); + return IntPoint(static_cast<int>(matrix.x0), static_cast<int>(matrix.y0)); +} + +void GraphicsContext::setPlatformFillColor(const Color& col) +{ + // FIXME: this is probably a no-op but I'm not sure + // notImplemented(); // commented-out because it's chatty and clutters output +} + +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 +} + +void GraphicsContext::setPlatformStrokeThickness(float strokeThickness) +{ + if (paintingDisabled()) + return; + + cairo_set_line_width(m_data->cr, strokeThickness); +} + +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) +{ + static double dashPattern[] = {5.0, 5.0}; + static double dotPattern[] = {1.0, 1.0}; + + if (paintingDisabled()) + return; + + switch (strokeStyle) { + case NoStroke: + // FIXME: is it the right way to emulate NoStroke? + cairo_set_line_width(m_data->cr, 0); + break; + case SolidStroke: + cairo_set_dash(m_data->cr, 0, 0, 0); + break; + case DottedStroke: + cairo_set_dash(m_data->cr, dotPattern, 2, 0); + break; + case DashedStroke: + cairo_set_dash(m_data->cr, dashPattern, 2, 0); + break; + default: + notImplemented(); + break; + } +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ + notImplemented(); +} + +void GraphicsContext::concatCTM(const AffineTransform& transform) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform); + cairo_transform(cr, matrix); + m_data->concatCTM(transform); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + if (paintingDisabled()) + return; + + clip(rect); + + Path p; + FloatRect r(rect); + // Add outer ellipse + p.addEllipse(r); + // Add inner ellipse + r.inflate(-thickness); + p.addEllipse(r); + addPath(p); + + cairo_t* cr = m_data->cr; + cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_clip(cr); + cairo_set_fill_rule(cr, savedFillRule); +} + + +void GraphicsContext::setShadow(IntSize const&, int, Color const&) +{ + notImplemented(); +} + +void GraphicsContext::clearShadow() +{ + notImplemented(); +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_push_group(cr); + m_data->layers.append(opacity); + m_data->beginTransparencyLayer(); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + + cairo_pop_group_to_source(cr); + cairo_paint_with_alpha(cr, m_data->layers.last()); + m_data->layers.removeLast(); + m_data->endTransparencyLayer(); +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + + cairo_save(cr); + cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_fill(cr); + cairo_restore(cr); +} + +void GraphicsContext::strokeRect(const FloatRect& rect, float width) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_save(cr); + cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); + setColor(cr, strokeColor()); + cairo_set_line_width(cr, width); + cairo_stroke(cr); + cairo_restore(cr); +} + +void GraphicsContext::setLineCap(LineCap lineCap) +{ + if (paintingDisabled()) + return; + + cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT; + switch (lineCap) { + case ButtCap: + // no-op + break; + case RoundCap: + cairoCap = CAIRO_LINE_CAP_ROUND; + break; + case SquareCap: + cairoCap = CAIRO_LINE_CAP_SQUARE; + break; + } + cairo_set_line_cap(m_data->cr, cairoCap); +} + +void GraphicsContext::setLineJoin(LineJoin lineJoin) +{ + if (paintingDisabled()) + return; + + cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER; + switch (lineJoin) { + case MiterJoin: + // no-op + break; + case RoundJoin: + cairoJoin = CAIRO_LINE_JOIN_ROUND; + break; + case BevelJoin: + cairoJoin = CAIRO_LINE_JOIN_BEVEL; + break; + } + cairo_set_line_join(m_data->cr, cairoJoin); +} + +void GraphicsContext::setMiterLimit(float miter) +{ + if (paintingDisabled()) + return; + + cairo_set_miter_limit(m_data->cr, miter); +} + +void GraphicsContext::setAlpha(float) +{ + notImplemented(); +} + +static inline cairo_operator_t toCairoOperator(CompositeOperator op) +{ + switch (op) { + case CompositeClear: + return CAIRO_OPERATOR_CLEAR; + case CompositeCopy: + return CAIRO_OPERATOR_SOURCE; + case CompositeSourceOver: + return CAIRO_OPERATOR_OVER; + case CompositeSourceIn: + return CAIRO_OPERATOR_IN; + case CompositeSourceOut: + return CAIRO_OPERATOR_OUT; + case CompositeSourceAtop: + return CAIRO_OPERATOR_ATOP; + case CompositeDestinationOver: + return CAIRO_OPERATOR_DEST_OVER; + case CompositeDestinationIn: + return CAIRO_OPERATOR_DEST_IN; + case CompositeDestinationOut: + return CAIRO_OPERATOR_DEST_OUT; + case CompositeDestinationAtop: + return CAIRO_OPERATOR_DEST_ATOP; + case CompositeXOR: + return CAIRO_OPERATOR_XOR; + case CompositePlusDarker: + return CAIRO_OPERATOR_SATURATE; + case CompositeHighlight: + // There is no Cairo equivalent for CompositeHighlight. + return CAIRO_OPERATOR_OVER; + case CompositePlusLighter: + return CAIRO_OPERATOR_ADD; + default: + return CAIRO_OPERATOR_SOURCE; + } +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + + cairo_set_operator(m_data->cr, toCairoOperator(op)); +} + +void GraphicsContext::beginPath() +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_new_path(cr); +} + +void GraphicsContext::addPath(const Path& path) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_path_t* p = cairo_copy_path(path.platformPath()->m_cr); + cairo_append_path(cr, p); + cairo_path_destroy(p); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_path_t* p = cairo_copy_path(path.platformPath()->m_cr); + cairo_append_path(cr, p); + cairo_path_destroy(p); + cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); + cairo_clip(cr); + cairo_set_fill_rule(cr, savedFillRule); + m_data->clip(path); +} + +void GraphicsContext::clipOut(const Path& path) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + double x1, y1, x2, y2; + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); + addPath(path); + + cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_clip(cr); + cairo_set_fill_rule(cr, savedFillRule); +} + +void GraphicsContext::rotate(float radians) +{ + if (paintingDisabled()) + return; + + cairo_rotate(m_data->cr, radians); + m_data->rotate(radians); +} + +void GraphicsContext::scale(const FloatSize& size) +{ + if (paintingDisabled()) + return; + + cairo_scale(m_data->cr, size.width(), size.height()); + m_data->scale(size); +} + +void GraphicsContext::clipOut(const IntRect& r) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + double x1, y1, x2, y2; + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + cairo_rectangle(cr, x1, x2, x2 - x1, y2 - y1); + cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); + cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_clip(cr); + cairo_set_fill_rule(cr, savedFillRule); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& r) +{ + if (paintingDisabled()) + return; + + Path p; + p.addEllipse(r); + clipOut(p); +} + +void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_save(cr); + beginPath(); + addPath(Path::createRoundedRectangle(r, topLeft, topRight, bottomLeft, bottomRight)); + setColor(cr, color); + cairo_fill(cr); + cairo_restore(cr); +} + +#if PLATFORM(GTK) +void GraphicsContext::setGdkExposeEvent(GdkEventExpose* expose) +{ + m_data->expose = expose; +} + +GdkEventExpose* GraphicsContext::gdkExposeEvent() const +{ + return m_data->expose; +} + +GdkDrawable* GraphicsContext::gdkDrawable() const +{ + if (!m_data->expose) + return 0; + + return GDK_DRAWABLE(m_data->expose->window); +} + +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) +{ + if (paintingDisabled()) + return; + + // When true, use the default Cairo backend antialias mode (usually this + // enables standard 'grayscale' antialiasing); false to explicitly disable + // antialiasing. This is the same strategy as used in drawConvexPolygon(). + cairo_set_antialias(m_data->cr, enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); +} + +void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r) +{ + if (paintingDisabled()) + return; + cairo_surface_t* image = buffer->surface(); + if (!image) + return; + cairo_surface_flush(image); + cairo_surface_reference(image); + cairo_t* cr = platformContext(); + cairo_save(cr); + cairo_translate(cr, r.x(), r.y()); + cairo_set_source_surface(cr, image, 0, 0); + cairo_surface_destroy(image); + cairo_rectangle(cr, 0, 0, r.width(), r.height()); + cairo_fill(cr); + cairo_restore(cr); +} + +void GraphicsContext::drawImage(ImageBuffer* buffer, const FloatRect& srcRect, const FloatRect& dstRect) +{ + cairo_surface_flush(buffer->surface()); + cairo_save(platformContext()); + cairo_set_source_surface(platformContext(), buffer->surface(), srcRect.x(), srcRect.y()); + cairo_rectangle(platformContext(), dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height()); + cairo_fill(platformContext()); + cairo_restore(platformContext()); +} + +} // namespace WebCore + +#endif // PLATFORM(CAIRO) diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h new file mode 100644 index 0000000..26db336 --- /dev/null +++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Brent Fulgham <bfulgham@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "GraphicsContext.h" + +#include <cairo.h> +#include <math.h> +#include <stdio.h> +#include <wtf/MathExtras.h> + +#if PLATFORM(GTK) +#include <gdk/gdk.h> +#include <pango/pango.h> +#elif PLATFORM(WIN) +#include <cairo-win32.h> +#endif + +namespace WebCore { + +class GraphicsContextPlatformPrivate { +public: + GraphicsContextPlatformPrivate() + : cr(0) +#if PLATFORM(GTK) + , expose(0) +#elif PLATFORM(WIN) + // NOTE: These may note be needed: review and remove once Cairo implementation is complete + , m_hdc(0) + , m_transparencyCount(0) +#endif + { + } + + ~GraphicsContextPlatformPrivate() + { + cairo_destroy(cr); + } + +#if PLATFORM(WIN) + // On Windows, we need to update the HDC for form controls to draw in the right place. + void save(); + void restore(); + void clip(const IntRect&); + 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 IntRect&) {} + void clip(const Path&) {} + void scale(const FloatSize&) {} + void rotate(float) {} + void translate(float, float) {} + void concatCTM(const AffineTransform&) {} + void beginTransparencyLayer() {} + void endTransparencyLayer() {} +#endif + + cairo_t* cr; + Vector<float> layers; + +#if PLATFORM(GTK) + GdkEventExpose* expose; +#elif PLATFORM(WIN) + HDC m_hdc; + unsigned m_transparencyCount; +#endif +}; + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp new file mode 100644 index 0000000..392e9df --- /dev/null +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Holger Hans Peter Freyther <zecke@selfish.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageBuffer.h" + +#include "GraphicsContext.h" +#include "ImageData.h" +#include "NotImplemented.h" + +#include <cairo.h> + +using namespace std; + +namespace WebCore { + +auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool) +{ + 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) +{ + cairo_t* cr = cairo_create(m_surface); + m_context.set(new GraphicsContext(cr)); + + /* + * The context is now owned by the GraphicsContext + */ + cairo_destroy(cr); +} + +ImageBuffer::~ImageBuffer() +{ + cairo_surface_destroy(m_surface); +} + +GraphicsContext* ImageBuffer::context() const +{ + return m_context.get(); +} + +cairo_surface_t* ImageBuffer::surface() const +{ + return m_surface; +} + +PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&) +{ + notImplemented(); +} + +} diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp new file mode 100644 index 0000000..4faa512 --- /dev/null +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BitmapImage.h" + +#if PLATFORM(CAIRO) + +#include "AffineTransform.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "ImageObserver.h" +#include <cairo.h> +#include <math.h> + +namespace WebCore { + +void FrameData::clear() +{ + if (m_frame) { + cairo_surface_destroy(m_frame); + m_frame = 0; + m_duration = 0.; + m_hasAlpha = true; + } +} + +void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +{ + if (!m_source.initialized()) + return; + + FloatRect srcRect(src); + FloatRect dstRect(dst); + + cairo_surface_t* image = frameAtIndex(m_currentFrame); + if (!image) // If it's too early we won't have an image yet. + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(context, dstRect, solidColor(), op); + return; + } + + IntSize selfSize = size(); + + cairo_t* cr = context->platformContext(); + cairo_save(cr); + + // Set the compositing operation. + if (op == CompositeSourceOver && !frameHasAlphaAtIndex(m_currentFrame)) + context->setCompositeOperation(CompositeCopy); + else + context->setCompositeOperation(op); + + // If we're drawing a sub portion of the image or scaling then create + // a pattern transformation on the image and draw the transformed pattern. + // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html + cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); + + // To avoid the unwanted gradient effect (#14017) we use + // CAIRO_FILTER_NEAREST now, but the real fix will be to have + // CAIRO_EXTEND_PAD implemented for surfaces in Cairo allowing us to still + // use bilinear filtering + cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); + + float scaleX = srcRect.width() / dstRect.width(); + float scaleY = srcRect.height() / dstRect.height(); + cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() }; + cairo_pattern_set_matrix(pattern, &matrix); + + // Draw the image. + cairo_translate(cr, dstRect.x(), dstRect.y()); + cairo_set_source(cr, pattern); + cairo_pattern_destroy(pattern); + cairo_rectangle(cr, 0, 0, dstRect.width(), dstRect.height()); + cairo_fill(cr); + + cairo_restore(cr); + + startAnimation(); + + if (imageObserver()) + imageObserver()->didDraw(this); +} + +void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + cairo_surface_t* image = nativeImageForCurrentFrame(); + if (!image) // If it's too early we won't have an image yet. + return; + + cairo_t* cr = context->platformContext(); + context->save(); + + // TODO: Make use of tileRect. + + cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + + // Workaround to avoid the unwanted gradient effect (#14017) + cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); + + cairo_matrix_t pattern_matrix = cairo_matrix_t(patternTransform); + cairo_matrix_t phase_matrix = {1, 0, 0, 1, phase.x(), phase.y()}; + cairo_matrix_t combined; + cairo_matrix_multiply(&combined, &pattern_matrix, &phase_matrix); + cairo_matrix_invert(&combined); + cairo_pattern_set_matrix(pattern, &combined); + + context->setCompositeOperation(op); + cairo_set_source(cr, pattern); + cairo_pattern_destroy(pattern); + cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height()); + cairo_fill(cr); + + context->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); +} + +void BitmapImage::checkForSolidColor() +{ + // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1. + m_isSolidColor = false; +} + +} + +#endif // PLATFORM(CAIRO) diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp new file mode 100644 index 0000000..66e39ba --- /dev/null +++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageSource.h" + +#if PLATFORM(CAIRO) + +#include "BMPImageDecoder.h" +#include "GIFImageDecoder.h" +#include "ICOImageDecoder.h" +#include "JPEGImageDecoder.h" +#include "PNGImageDecoder.h" +#include "SharedBuffer.h" +#include <cairo.h> + +#if !PLATFORM(WIN) +#include "XBMImageDecoder.h" +#endif + +namespace WebCore { + +ImageDecoder* createDecoder(const Vector<char>& data) +{ + // We need at least 4 bytes to figure out what kind of image we're dealing with. + int length = data.size(); + if (length < 4) + return 0; + + const unsigned char* uContents = (const unsigned char*)data.data(); + const char* contents = data.data(); + + // GIFs begin with GIF8(7 or 9). + if (strncmp(contents, "GIF8", 4) == 0) + return new GIFImageDecoder(); + + // Test for PNG. + if (uContents[0]==0x89 && + uContents[1]==0x50 && + uContents[2]==0x4E && + uContents[3]==0x47) + return new PNGImageDecoder(); + + // JPEG + if (uContents[0]==0xFF && + uContents[1]==0xD8 && + uContents[2]==0xFF) + return new JPEGImageDecoder(); + + // BMP + if (strncmp(contents, "BM", 2) == 0) + return new BMPImageDecoder(); + + // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. + // CURs begin with 2-byte 0 followed by 2-byte 2. + if (!memcmp(contents, "\000\000\001\000", 4) || + !memcmp(contents, "\000\000\002\000", 4)) + return new ICOImageDecoder(); + +#if !PLATFORM(WIN) + // XBMs require 8 bytes of info. + if (length >= 8 && strncmp(contents, "#define ", 8) == 0) + return new XBMImageDecoder(); +#endif + + // Give up. We don't know what the heck this is. + return 0; +} + +ImageSource::ImageSource() + : m_decoder(0) +{ +} + +ImageSource::~ImageSource() +{ + clear(); +} + +void ImageSource::clear() +{ + delete m_decoder; + m_decoder = 0; +} + +bool ImageSource::initialized() const +{ + return m_decoder; +} + +void ImageSource::setData(SharedBuffer* data, bool allDataReceived) +{ + // Make the decoder by sniffing the bytes. + // This method will examine the data and instantiate an instance of the appropriate decoder plugin. + // If insufficient bytes are available to determine the image type, no decoder plugin will be + // made. + if (!m_decoder) + m_decoder = createDecoder(data->buffer()); + + if (!m_decoder) + return; + + m_decoder->setData(data, allDataReceived); +} + +bool ImageSource::isSizeAvailable() +{ + if (!m_decoder) + return false; + + return m_decoder->isSizeAvailable(); +} + +IntSize ImageSource::size() const +{ + if (!m_decoder) + return IntSize(); + + return m_decoder->size(); +} + +int ImageSource::repetitionCount() +{ + if (!m_decoder) + return cAnimationNone; + + return m_decoder->repetitionCount(); +} + +size_t ImageSource::frameCount() const +{ + return m_decoder ? m_decoder->frameCount() : 0; +} + +NativeImagePtr ImageSource::createFrameAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) + return 0; + + // Cairo does not like zero height images. + // If we have a zero height image, just pretend we don't have enough data yet. + if (!buffer->height()) + return 0; + + return cairo_image_surface_create_for_data((unsigned char*)buffer->bytes().data(), + CAIRO_FORMAT_ARGB32, + size().width(), + buffer->height(), + size().width()*4); +} + +bool ImageSource::frameIsCompleteAtIndex(size_t index) +{ + if (!m_decoder) + return false; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + return buffer && buffer->status() == RGBA32Buffer::FrameComplete; +} + +float ImageSource::frameDurationAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) + return 0; + + // Many annoying ads specify a 0 duration to make an image flash as quickly + // as possible. We follow WinIE's behavior and use a duration of 100 ms + // for any frames that specify a duration of <= 50 ms. See + // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for + // more. + const float duration = buffer->duration() / 1000.0f; + return (duration < 0.051f) ? 0.100f : duration; +} + +bool ImageSource::frameHasAlphaAtIndex(size_t index) +{ + // When a frame has not finished decoding, always mark it as having alpha, + // so we don't get a black background for the undecoded sections. + // TODO: A better solution is probably to have the underlying buffer's + // hasAlpha() return true in these cases, since it is, in fact, technically + // true. + if (!frameIsCompleteAtIndex(index)) + return true; + + return m_decoder->frameBufferAtIndex(index)->hasAlpha(); +} + +} + +#endif // PLATFORM(CAIRO) diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp new file mode 100644 index 0000000..8d17567 --- /dev/null +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -0,0 +1,280 @@ +/* + Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com> + Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <wildfox@kde.org> + 2004, 2005, 2006 Rob Buis <buis@kde.org> + 2005, 2007 Apple Inc. All Rights reserved. + 2007 Alp Toker <alp@atoker.com> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + aint with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "Path.h" + +#include "AffineTransform.h" +#include "CairoPath.h" +#include "FloatRect.h" +#include "NotImplemented.h" +#include "PlatformString.h" + +#include <cairo.h> +#include <math.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +Path::Path() + : m_path(new CairoPath()) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path::Path(const Path& other) + : m_path(new CairoPath()) +{ + cairo_t* cr = platformPath()->m_cr; + cairo_path_t* p = cairo_copy_path(other.platformPath()->m_cr); + cairo_append_path(cr, p); + cairo_path_destroy(p); +} + +Path& Path::operator=(const Path& other) +{ + if (&other == this) + return *this; + + clear(); + cairo_t* cr = platformPath()->m_cr; + cairo_path_t* p = cairo_copy_path(other.platformPath()->m_cr); + cairo_append_path(cr, p); + cairo_path_destroy(p); + return *this; +} + +void Path::clear() +{ + cairo_t* cr = platformPath()->m_cr; + cairo_new_path(cr); +} + +bool Path::isEmpty() const +{ + cairo_t* cr = platformPath()->m_cr; +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,5,10) + return !cairo_has_current_point(cr); +#else + cairo_path_t* p = cairo_copy_path(cr); + bool hasData = p->num_data; + cairo_path_destroy(p); + return !hasData; +#endif +} + +void Path::translate(const FloatSize& p) +{ + cairo_t* cr = platformPath()->m_cr; + cairo_translate(cr, p.width(), p.height()); +} + +void Path::moveTo(const FloatPoint& p) +{ + cairo_t* cr = platformPath()->m_cr; + cairo_move_to(cr, p.x(), p.y()); +} + +void Path::addLineTo(const FloatPoint& p) +{ + cairo_t* cr = platformPath()->m_cr; + cairo_line_to(cr, p.x(), p.y()); +} + +void Path::addRect(const FloatRect& rect) +{ + cairo_t* cr = platformPath()->m_cr; + cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); +} + +/* + * inspired by libsvg-cairo + */ +void Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point) +{ + cairo_t* cr = platformPath()->m_cr; + double x, y; + double x1 = controlPoint.x(); + double y1 = controlPoint.y(); + double x2 = point.x(); + double y2 = point.y(); + cairo_get_current_point(cr, &x, &y); + cairo_curve_to(cr, + x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y), + x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2), + x2, y2); +} + +void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& controlPoint3) +{ + cairo_t* cr = platformPath()->m_cr; + cairo_curve_to(cr, controlPoint1.x(), controlPoint1.y(), + controlPoint2.x(), controlPoint2.y(), + controlPoint3.x(), controlPoint3.y()); +} + +void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise) +{ + // http://bugs.webkit.org/show_bug.cgi?id=16449 + // cairo_arc() functions hang or crash when passed inf as radius or start/end angle + if (!isfinite(r) || !isfinite(sa) || !isfinite(ea)) + return; + + cairo_t* cr = platformPath()->m_cr; + if (anticlockwise) + cairo_arc_negative(cr, p.x(), p.y(), r, sa, ea); + else + cairo_arc(cr, p.x(), p.y(), r, sa, ea); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + // FIXME: cairo_arc_to not yet in cairo see cairo.h + // cairo_arc_to(m_cr, p1.x(), p1.y(), p2.x(), p2.y()); + notImplemented(); +} + +void Path::addEllipse(const FloatRect& rect) +{ + cairo_t* cr = platformPath()->m_cr; + cairo_save(cr); + float yRadius = .5 * rect.height(); + float xRadius = .5 * rect.width(); + cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius); + cairo_scale(cr, xRadius, yRadius); + cairo_arc(cr, 0., 0., 1., 0., 2 * piDouble); + cairo_restore(cr); +} + +void Path::closeSubpath() +{ + cairo_t* cr = platformPath()->m_cr; + cairo_close_path(cr); +} + +FloatRect Path::boundingRect() const +{ + cairo_t* cr = platformPath()->m_cr; + double x0, x1, y0, y1; + cairo_fill_extents(cr, &x0, &y0, &x1, &y1); + return FloatRect(x0, y0, x1 - x0, y1 - y0); +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + if (!boundingRect().contains(point)) + return false; + + cairo_t* cr = platformPath()->m_cr; + cairo_fill_rule_t cur = cairo_get_fill_rule(cr); + cairo_set_fill_rule(cr, rule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); + bool contains = cairo_in_fill(cr, point.x(), point.y()); + cairo_set_fill_rule(cr, cur); + return contains; +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + cairo_t* cr = platformPath()->m_cr; + cairo_path_t* path = cairo_copy_path(cr); + cairo_path_data_t* data; + PathElement pelement; + FloatPoint points[3]; + pelement.points = points; + + for (int i = 0; i < path->num_data; i += path->data[i].header.length) { + data = &path->data[i]; + switch (data->header.type) { + case CAIRO_PATH_MOVE_TO: + pelement.type = PathElementMoveToPoint; + pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y); + function(info, &pelement); + break; + case CAIRO_PATH_LINE_TO: + pelement.type = PathElementAddLineToPoint; + pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y); + function(info, &pelement); + break; + case CAIRO_PATH_CURVE_TO: + pelement.type = PathElementAddCurveToPoint; + pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y); + pelement.points[1] = FloatPoint(data[2].point.x,data[2].point.y); + pelement.points[2] = FloatPoint(data[3].point.x,data[3].point.y); + function(info, &pelement); + break; + case CAIRO_PATH_CLOSE_PATH: + pelement.type = PathElementCloseSubpath; + function(info, &pelement); + break; + } + } + cairo_path_destroy(path); +} + +void Path::transform(const AffineTransform& trans) +{ + cairo_t* m_cr = platformPath()->m_cr; + cairo_matrix_t c_matrix = cairo_matrix_t(trans); + cairo_transform(m_cr, &c_matrix); +} + +String Path::debugString() const +{ + String string = ""; + cairo_path_t* path = cairo_copy_path(platformPath()->m_cr); + cairo_path_data_t* data; + + if (!path->num_data ) + string = "EMPTY"; + + for (int i = 0; i < path->num_data; i += path->data[i].header.length) { + data = &path->data[i]; + switch (data->header.type) { + case CAIRO_PATH_MOVE_TO: + string += String::format("M %.2f,%.2f", + data[1].point.x, data[1].point.y); + break; + case CAIRO_PATH_LINE_TO: + string += String::format("L %.2f,%.2f", + data[1].point.x, data[1].point.y); + break; + case CAIRO_PATH_CURVE_TO: + string += String::format("C %.2f,%.2f,%.2f,%.2f,%.2f,%.2f", + data[1].point.x, data[1].point.y, + data[2].point.x, data[2].point.y, + data[3].point.x, data[3].point.y); + break; + case CAIRO_PATH_CLOSE_PATH: + string += "X"; + break; + } + } + cairo_path_destroy(path); + return string; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/cairo/rgb24-hacks.txt b/WebCore/platform/graphics/cairo/rgb24-hacks.txt new file mode 100644 index 0000000..59f8070 --- /dev/null +++ b/WebCore/platform/graphics/cairo/rgb24-hacks.txt @@ -0,0 +1,32 @@ +Index: cairo/src/cairo-win32-surface.c +=================================================================== +--- cairo/src/cairo-win32-surface.c (revision 14498) ++++ cairo/src/cairo-win32-surface.c (working copy) +@@ -824,8 +824,13 @@ + * to figure out when we can use GDI. We don't have that checking + * anywhere at the moment, so just bail and use the fallback + * paths. */ +- if (surface->format != CAIRO_FORMAT_RGB24) +- return CAIRO_INT_STATUS_UNSUPPORTED; ++ //if (surface->format != CAIRO_FORMAT_RGB24) ++ // return CAIRO_INT_STATUS_UNSUPPORTED; ++ // FIXME: We'll go ahead and optimize this now and just assume we're ok if ++ // the color has no alpha. Probably need to check various composite operators to ++ // get this exactly right. ++ if (color->alpha != 1.0) ++ return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all + * surfaces with alpha.) +@@ -1016,8 +1021,9 @@ + + /* We can only handle operator SOURCE or OVER with the destination + * having no alpha */ +- if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) || +- (dst->format != CAIRO_FORMAT_RGB24)) ++ if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER)) ++ // FIXME: It's not clear why ExtTextOut can't be called when the ++ // destination has alpha. Remove the RGB24 restriction. || (dst->format != CAIRO_FORMAT_RGB24)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* If we have a fallback mask clip set on the dst, we have diff --git a/WebCore/platform/graphics/cairo/scale-removal.txt b/WebCore/platform/graphics/cairo/scale-removal.txt new file mode 100644 index 0000000..47c0d70 --- /dev/null +++ b/WebCore/platform/graphics/cairo/scale-removal.txt @@ -0,0 +1,13 @@ +Index: cairo/src/cairo-win32-private.h +=================================================================== +--- cairo/src/cairo-win32-private.h (revision 14582) ++++ cairo/src/cairo-win32-private.h (working copy) +@@ -39,7 +39,7 @@ + #include <cairo-win32.h> + #include <cairoint.h> + +-#define WIN32_FONT_LOGICAL_SCALE 32 ++#define WIN32_FONT_LOGICAL_SCALE 1 + + typedef struct _cairo_win32_surface { + cairo_surface_t base; diff --git a/WebCore/platform/graphics/cg/AffineTransformCG.cpp b/WebCore/platform/graphics/cg/AffineTransformCG.cpp new file mode 100644 index 0000000..8fdd1e6 --- /dev/null +++ b/WebCore/platform/graphics/cg/AffineTransformCG.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AffineTransform.h" + +#if PLATFORM(CG) + +#include "FloatConversion.h" +#include "FloatRect.h" +#include "IntRect.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +AffineTransform::AffineTransform() +{ + m_transform = CGAffineTransformIdentity; +} + +AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) +{ + m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a), + narrowPrecisionToCGFloat(b), + narrowPrecisionToCGFloat(c), + narrowPrecisionToCGFloat(d), + narrowPrecisionToCGFloat(tx), + narrowPrecisionToCGFloat(ty)); +} + +AffineTransform::AffineTransform(CGAffineTransform t) +{ + m_transform = t; +} + +void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty) +{ + m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a), + narrowPrecisionToCGFloat(b), + narrowPrecisionToCGFloat(c), + narrowPrecisionToCGFloat(d), + narrowPrecisionToCGFloat(tx), + narrowPrecisionToCGFloat(ty)); +} + +void AffineTransform::map(double x, double y, double *x2, double *y2) const +{ + CGPoint result = CGPointApplyAffineTransform(CGPointMake(narrowPrecisionToCGFloat(x), narrowPrecisionToCGFloat(y)), m_transform); + *x2 = result.x; + *y2 = result.y; +} + +IntRect AffineTransform::mapRect(const IntRect &rect) const +{ + return enclosingIntRect(CGRectApplyAffineTransform(CGRect(rect), m_transform)); +} + +FloatRect AffineTransform::mapRect(const FloatRect &rect) const +{ + return FloatRect(CGRectApplyAffineTransform(CGRect(rect), m_transform)); +} + +bool AffineTransform::isIdentity() const +{ + return CGAffineTransformIsIdentity(m_transform); +} + +double AffineTransform::a() const +{ + return m_transform.a; +} + +void AffineTransform::setA(double a) +{ + m_transform.a = narrowPrecisionToCGFloat(a); +} + +double AffineTransform::b() const +{ + return m_transform.b; +} + +void AffineTransform::setB(double b) +{ + m_transform.b = narrowPrecisionToCGFloat(b); +} + +double AffineTransform::c() const +{ + return m_transform.c; +} + +void AffineTransform::setC(double c) +{ + m_transform.c = narrowPrecisionToCGFloat(c); +} + +double AffineTransform::d() const +{ + return m_transform.d; +} + +void AffineTransform::setD(double d) +{ + m_transform.d = narrowPrecisionToCGFloat(d); +} + +double AffineTransform::e() const +{ + return m_transform.tx; +} + +void AffineTransform::setE(double e) +{ + m_transform.tx = narrowPrecisionToCGFloat(e); +} + +double AffineTransform::f() const +{ + return m_transform.ty; +} + +void AffineTransform::setF(double f) +{ + m_transform.ty = narrowPrecisionToCGFloat(f); +} + +void AffineTransform::reset() +{ + m_transform = CGAffineTransformIdentity; +} + +AffineTransform &AffineTransform::scale(double sx, double sy) +{ + m_transform = CGAffineTransformScale(m_transform, narrowPrecisionToCGFloat(sx), narrowPrecisionToCGFloat(sy)); + return *this; +} + +AffineTransform &AffineTransform::rotate(double d) +{ + m_transform = CGAffineTransformRotate(m_transform, narrowPrecisionToCGFloat(deg2rad(d))); + return *this; +} + +AffineTransform &AffineTransform::translate(double tx, double ty) +{ + m_transform = CGAffineTransformTranslate(m_transform, narrowPrecisionToCGFloat(tx), narrowPrecisionToCGFloat(ty)); + return *this; +} + +AffineTransform &AffineTransform::shear(double sx, double sy) +{ + CGAffineTransform shear = CGAffineTransformMake(1.0f, narrowPrecisionToCGFloat(sy), narrowPrecisionToCGFloat(sx), 1.0f, 0.0f, 0.0f); + m_transform = CGAffineTransformConcat(shear, m_transform); + return *this; +} + +double AffineTransform::det() const +{ + return m_transform.a * m_transform.d - m_transform.b * m_transform.c; +} + +AffineTransform AffineTransform::inverse() const +{ + if (isInvertible()) + return AffineTransform(CGAffineTransformInvert(m_transform)); + return AffineTransform(); +} + +AffineTransform::operator CGAffineTransform() const +{ + return m_transform; +} + +bool AffineTransform::operator== (const AffineTransform &m2) const +{ + return CGAffineTransformEqualToTransform(m_transform, CGAffineTransform(m2)); +} + +AffineTransform &AffineTransform::operator*= (const AffineTransform &m2) +{ + m_transform = CGAffineTransformConcat(m_transform, CGAffineTransform(m2)); + return *this; +} + +AffineTransform AffineTransform::operator* (const AffineTransform &m2) +{ + return CGAffineTransformConcat(m_transform, CGAffineTransform(m2)); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp new file mode 100644 index 0000000..48ce9f2 --- /dev/null +++ b/WebCore/platform/graphics/cg/ColorCG.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +#if PLATFORM(CG) + +#include <wtf/Assertions.h> +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +Color::Color(CGColorRef color) +{ + if (!color) { + m_color = 0; + m_valid = false; + return; + } + + size_t numComponents = CGColorGetNumberOfComponents(color); + const CGFloat* components = CGColorGetComponents(color); + + float r = 0; + float g = 0; + float b = 0; + float a = 0; + + switch (numComponents) { + case 2: + r = g = b = components[0]; + a = components[1]; + break; + case 4: + r = components[0]; + g = components[1]; + b = components[2]; + a = components[3]; + break; + default: + ASSERT_NOT_REACHED(); + } + + m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255); +} + +#if !PLATFORM(MAC) + +CGColorRef cgColor(const Color& c) +{ + CGColorRef color = NULL; + CMProfileRef prof = NULL; + CMGetSystemProfile(&prof); + + CGColorSpaceRef rgbSpace = CGColorSpaceCreateWithPlatformColorSpace(prof); + + if (rgbSpace != NULL) + { + float components[4] = {c.red() / 255.0f, c.green() / 255.0f, c.blue() / 255.0f, c.alpha() / 255.0f}; + color = CGColorCreate(rgbSpace, components); + CGColorSpaceRelease(rgbSpace); + } + + CMCloseProfile(prof); + + return color; +} + +#endif // !PLATFORM(MAC) + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/FloatPointCG.cpp b/WebCore/platform/graphics/cg/FloatPointCG.cpp new file mode 100644 index 0000000..f9c3353 --- /dev/null +++ b/WebCore/platform/graphics/cg/FloatPointCG.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatPoint.h" + +#if PLATFORM(CG) + +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +FloatPoint::FloatPoint(const CGPoint& p) : m_x(p.x), m_y(p.y) +{ +} + +FloatPoint::operator CGPoint() const +{ + return CGPointMake(m_x, m_y); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/FloatRectCG.cpp b/WebCore/platform/graphics/cg/FloatRectCG.cpp new file mode 100644 index 0000000..a1ce367 --- /dev/null +++ b/WebCore/platform/graphics/cg/FloatRectCG.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatRect.h" + +#if PLATFORM(CG) + +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +FloatRect::FloatRect(const CGRect& r) : m_location(r.origin), m_size(r.size) +{ +} + +FloatRect::operator CGRect() const +{ + return CGRectMake(x(), y(), width(), height()); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/FloatSizeCG.cpp b/WebCore/platform/graphics/cg/FloatSizeCG.cpp new file mode 100644 index 0000000..383af21 --- /dev/null +++ b/WebCore/platform/graphics/cg/FloatSizeCG.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatSize.h" + +#if PLATFORM(CG) + +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +FloatSize::FloatSize(const CGSize& s) : m_width(s.width), m_height(s.height) +{ +} + +FloatSize::operator CGSize() const +{ + return CGSizeMake(m_width, m_height); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp new file mode 100644 index 0000000..de546ac --- /dev/null +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -0,0 +1,976 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define _USE_MATH_DEFINES 1 +#include "config.h" +#include "GraphicsContext.h" + +#include "AffineTransform.h" +#include "FloatConversion.h" +#include "GraphicsContextPlatformPrivateCG.h" +#include "ImageBuffer.h" +#include "KURL.h" +#include "Path.h" +#include <CoreGraphics/CGBitmapContext.h> +#include <CoreGraphics/CGPDFContext.h> +#include <wtf/MathExtras.h> +#include <wtf/OwnArrayPtr.h> +#include <wtf/RetainPtr.h> + +using namespace std; + +namespace WebCore { + +static void setCGFillColor(CGContextRef context, const Color& color) +{ + CGFloat red, green, blue, alpha; + color.getRGBA(red, green, blue, alpha); + CGContextSetRGBFillColor(context, red, green, blue, alpha); +} + +static void setCGStrokeColor(CGContextRef context, const Color& color) +{ + CGFloat red, green, blue, alpha; + color.getRGBA(red, green, blue, alpha); + CGContextSetRGBStrokeColor(context, red, green, blue, alpha); +} + +GraphicsContext::GraphicsContext(CGContextRef cgContext) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate(cgContext)) +{ + setPaintingDisabled(!cgContext); + if (cgContext) { + // Make sure the context starts in sync with our state. + setPlatformFillColor(fillColor()); + setPlatformStrokeColor(strokeColor()); + } +} + +GraphicsContext::~GraphicsContext() +{ + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +CGContextRef GraphicsContext::platformContext() const +{ + ASSERT(!paintingDisabled()); + ASSERT(m_data->m_cgContext); + return m_data->m_cgContext; +} + +void GraphicsContext::savePlatformState() +{ + // Note: Do not use this function within this class implementation, since we want to avoid the extra + // save of the secondary context (in GraphicsContextPlatformPrivateCG.h). + CGContextSaveGState(platformContext()); + m_data->save(); +} + +void GraphicsContext::restorePlatformState() +{ + // Note: Do not use this function within this class implementation, since we want to avoid the extra + // restore of the secondary context (in GraphicsContextPlatformPrivateCG.h). + CGContextRestoreGState(platformContext()); + m_data->restore(); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + CGContextRef context = platformContext(); + + if (fillColor().alpha()) + CGContextFillRect(context, rect); + + if (strokeStyle() != NoStroke && strokeColor().alpha()) { + // We do a fill of four rects to simulate the stroke of a border. + Color oldFillColor = fillColor(); + if (oldFillColor != strokeColor()) + setCGFillColor(context, strokeColor()); + CGRect rects[4] = { + FloatRect(rect.x(), rect.y(), rect.width(), 1), + FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1), + FloatRect(rect.x(), rect.y() + 1, 1, rect.height() - 2), + FloatRect(rect.right() - 1, rect.y() + 1, 1, rect.height() - 2) + }; + CGContextFillRects(context, rects, 4); + if (oldFillColor != strokeColor()) + setCGFillColor(context, oldFillColor); + } +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + if (strokeStyle() == NoStroke || !strokeColor().alpha()) + return; + + float width = strokeThickness(); + + FloatPoint p1 = point1; + FloatPoint p2 = point2; + bool isVerticalLine = (p1.x() == p2.x()); + + // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic + // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., + // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave + // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. + if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { + if (isVerticalLine) { + p1.move(0, width); + p2.move(0, -width); + } else { + p1.move(width, 0); + p2.move(-width, 0); + } + } + + if (((int)width) % 2) { + if (isVerticalLine) { + // We're a vertical line. Adjust our x. + p1.move(0.5f, 0.0f); + p2.move(0.5f, 0.0f); + } else { + // We're a horizontal line. Adjust our y. + p1.move(0.0f, 0.5f); + p2.move(0.0f, 0.5f); + } + } + + int patWidth = 0; + switch (strokeStyle()) { + case NoStroke: + case SolidStroke: + break; + case DottedStroke: + patWidth = (int)width; + break; + case DashedStroke: + patWidth = 3 * (int)width; + break; + } + + CGContextRef context = platformContext(); + CGContextSaveGState(context); + + CGContextSetShouldAntialias(context, false); + + if (patWidth) { + // Do a rect fill of our endpoints. This ensures we always have the + // appearance of being a border. We then draw the actual dotted/dashed line. + setCGFillColor(context, strokeColor()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. + if (isVerticalLine) { + CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width)); + CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width)); + } else { + CGContextFillRect(context, FloatRect(p1.x() - width, p1.y() - width / 2, width, width)); + CGContextFillRect(context, FloatRect(p2.x(), p2.y() - width / 2, width, width)); + } + + // Example: 80 pixels with a width of 30 pixels. + // Remainder is 20. The maximum pixels of line we could paint + // will be 50 pixels. + int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width; + int remainder = distance % patWidth; + int coverage = distance - remainder; + int numSegments = coverage / patWidth; + + float patternOffset = 0.0f; + // Special case 1px dotted borders for speed. + if (patWidth == 1) + patternOffset = 1.0f; + else { + bool evenNumberOfSegments = numSegments % 2 == 0; + if (remainder) + evenNumberOfSegments = !evenNumberOfSegments; + if (evenNumberOfSegments) { + if (remainder) { + patternOffset += patWidth - remainder; + patternOffset += remainder / 2; + } else + patternOffset = patWidth / 2; + } else { + if (remainder) + patternOffset = (patWidth - remainder)/2; + } + } + + const CGFloat dottedLine[2] = { patWidth, patWidth }; + CGContextSetLineDash(context, patternOffset, dottedLine, 2); + } + + CGContextBeginPath(context); + CGContextMoveToPoint(context, p1.x(), p1.y()); + CGContextAddLineToPoint(context, p2.x(), p2.y()); + + CGContextStrokePath(context); + + CGContextRestoreGState(context); +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + // FIXME: CG added CGContextAddEllipseinRect in Tiger, so we should be able to quite easily draw an ellipse. + // This code can only handle circles, not ellipses. But khtml only + // uses it for circles. + ASSERT(rect.width() == rect.height()); + + if (paintingDisabled()) + return; + + CGContextRef context = platformContext(); + CGContextBeginPath(context); + float r = (float)rect.width() / 2; + CGContextAddArc(context, rect.x() + r, rect.y() + r, r, 0.0f, 2.0f * piFloat, 0); + CGContextClosePath(context); + + if (fillColor().alpha()) { + if (strokeStyle() != NoStroke) + // stroke and fill + CGContextDrawPath(context, kCGPathFillStroke); + else + CGContextFillPath(context); + } else if (strokeStyle() != NoStroke) + CGContextStrokePath(context); +} + + +void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) +{ + if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) + return; + + CGContextRef context = platformContext(); + CGContextSaveGState(context); + CGContextBeginPath(context); + CGContextSetShouldAntialias(context, false); + + int x = rect.x(); + int y = rect.y(); + float w = (float)rect.width(); + float h = (float)rect.height(); + float scaleFactor = h / w; + float reverseScaleFactor = w / h; + + if (w != h) + scale(FloatSize(1, scaleFactor)); + + float hRadius = w / 2; + float vRadius = h / 2; + float fa = startAngle; + float falen = fa + angleSpan; + float start = -fa * piFloat / 180.0f; + float end = -falen * piFloat / 180.0f; + CGContextAddArc(context, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, start, end, true); + + if (w != h) + scale(FloatSize(1, reverseScaleFactor)); + + + float width = strokeThickness(); + int patWidth = 0; + + switch (strokeStyle()) { + case DottedStroke: + patWidth = (int)(width / 2); + break; + case DashedStroke: + patWidth = 3 * (int)(width / 2); + break; + default: + break; + } + + if (patWidth) { + // Example: 80 pixels with a width of 30 pixels. + // Remainder is 20. The maximum pixels of line we could paint + // will be 50 pixels. + int distance; + if (hRadius == vRadius) + distance = static_cast<int>((piFloat * hRadius) / 2.0f); + else // We are elliptical and will have to estimate the distance + distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f); + + int remainder = distance % patWidth; + int coverage = distance - remainder; + int numSegments = coverage / patWidth; + + float patternOffset = 0.0f; + // Special case 1px dotted borders for speed. + if (patWidth == 1) + patternOffset = 1.0f; + else { + bool evenNumberOfSegments = numSegments % 2 == 0; + if (remainder) + evenNumberOfSegments = !evenNumberOfSegments; + if (evenNumberOfSegments) { + if (remainder) { + patternOffset += patWidth - remainder; + patternOffset += remainder / 2.0f; + } else + patternOffset = patWidth / 2.0f; + } else { + if (remainder) + patternOffset = (patWidth - remainder) / 2.0f; + } + } + + const CGFloat dottedLine[2] = { patWidth, patWidth }; + CGContextSetLineDash(context, patternOffset, dottedLine, 2); + } + + CGContextStrokePath(context); + + CGContextRestoreGState(context); +} + +void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) +{ + if (paintingDisabled() || !fillColor().alpha() && (strokeThickness() <= 0 || strokeStyle() == NoStroke)) + return; + + if (npoints <= 1) + return; + + CGContextRef context = platformContext(); + + CGContextSaveGState(context); + + CGContextSetShouldAntialias(context, shouldAntialias); + + CGContextBeginPath(context); + CGContextMoveToPoint(context, points[0].x(), points[0].y()); + for (size_t i = 1; i < npoints; i++) + CGContextAddLineToPoint(context, points[i].x(), points[i].y()); + CGContextClosePath(context); + + if (fillColor().alpha()) { + if (strokeStyle() != NoStroke) + CGContextDrawPath(context, kCGPathEOFillStroke); + else + CGContextEOFillPath(context); + } else + CGContextStrokePath(context); + + CGContextRestoreGState(context); +} + +void GraphicsContext::fillRect(const IntRect& rect, const Color& color) +{ + if (paintingDisabled()) + return; + if (color.alpha()) { + CGContextRef context = platformContext(); + Color oldFillColor = fillColor(); + if (oldFillColor != color) + setCGFillColor(context, color); + CGContextFillRect(context, rect); + if (oldFillColor != color) + setCGFillColor(context, oldFillColor); + } +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +{ + if (paintingDisabled()) + return; + if (color.alpha()) { + CGContextRef context = platformContext(); + Color oldFillColor = fillColor(); + if (oldFillColor != color) + setCGFillColor(context, color); + CGContextFillRect(context, rect); + if (oldFillColor != color) + setCGFillColor(context, oldFillColor); + } +} + +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +{ + if (paintingDisabled() || !color.alpha()) + return; + + CGContextRef context = platformContext(); + Color oldFillColor = fillColor(); + if (oldFillColor != color) + setCGFillColor(context, color); + + addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); + CGContextFillPath(context); + + if (oldFillColor != color) + setCGFillColor(context, oldFillColor); +} + + +void GraphicsContext::clip(const IntRect& rect) +{ + if (paintingDisabled()) + return; + CGContextClipToRect(platformContext(), rect); + m_data->clip(rect); +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect }; + CGContextBeginPath(platformContext()); + CGContextAddRects(platformContext(), rects, 2); + CGContextEOClip(platformContext()); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + CGContextBeginPath(platformContext()); + CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); + CGContextAddEllipseInRect(platformContext(), rect); + CGContextEOClip(platformContext()); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + if (paintingDisabled()) + return; + + clip(rect); + CGContextRef context = platformContext(); + + // Add outer ellipse + CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height())); + // Add inner ellipse. + CGContextAddEllipseInRect(context, CGRectMake(rect.x() + thickness, rect.y() + thickness, + rect.width() - (thickness * 2), rect.height() - (thickness * 2))); + + CGContextEOClip(context); +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + CGContextRef context = platformContext(); + CGContextSaveGState(context); + CGContextSetAlpha(context, opacity); + CGContextBeginTransparencyLayer(context, 0); + m_data->beginTransparencyLayer(); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + CGContextRef context = platformContext(); + CGContextEndTransparencyLayer(context); + CGContextRestoreGState(context); + m_data->endTransparencyLayer(); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + +void GraphicsContext::setShadow(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(); + + CGFloat width = size.width(); + CGFloat height = size.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); + if (width > 0) + width += extraShadowOffset; + else if (width < 0) + width -= extraShadowOffset; + + if (height > 0) + 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. + else { + CGColorRef colorCG = cgColor(color); + CGContextSetShadowWithColor(context, + CGSizeMake(width, -height), // y is flipped. + blur, + colorCG); + CGColorRelease(colorCG); + } +} + +void GraphicsContext::clearShadow() +{ + if (paintingDisabled()) + return; + CGContextSetShadowWithColor(platformContext(), CGSizeZero, 0, 0); +} + +void GraphicsContext::setMiterLimit(float limit) +{ + if (paintingDisabled()) + return; + CGContextSetMiterLimit(platformContext(), limit); +} + +void GraphicsContext::setAlpha(float alpha) +{ + if (paintingDisabled()) + return; + CGContextSetAlpha(platformContext(), alpha); +} + +void GraphicsContext::clearRect(const FloatRect& r) +{ + if (paintingDisabled()) + return; + CGContextClearRect(platformContext(), r); +} + +void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) +{ + if (paintingDisabled()) + return; + CGContextStrokeRectWithWidth(platformContext(), r, lineWidth); +} + +void GraphicsContext::setLineCap(LineCap cap) +{ + if (paintingDisabled()) + return; + switch (cap) { + case ButtCap: + CGContextSetLineCap(platformContext(), kCGLineCapButt); + break; + case RoundCap: + CGContextSetLineCap(platformContext(), kCGLineCapRound); + break; + case SquareCap: + CGContextSetLineCap(platformContext(), kCGLineCapSquare); + break; + } +} + +void GraphicsContext::setLineJoin(LineJoin join) +{ + if (paintingDisabled()) + return; + switch (join) { + case MiterJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinMiter); + break; + case RoundJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinRound); + break; + case BevelJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinBevel); + break; + } +} + +void GraphicsContext::beginPath() +{ + CGContextBeginPath(platformContext()); +} + +void GraphicsContext::addPath(const Path& path) +{ + CGContextAddPath(platformContext(), path.platformPath()); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + CGContextRef context = platformContext(); + CGContextBeginPath(context); + CGContextAddPath(context, path.platformPath()); + CGContextClip(context); + m_data->clip(path); +} + +void GraphicsContext::clipOut(const Path& path) +{ + if (paintingDisabled()) + return; + + CGContextBeginPath(platformContext()); + CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); + CGContextAddPath(platformContext(), path.platformPath()); + CGContextEOClip(platformContext()); +} + +void GraphicsContext::scale(const FloatSize& size) +{ + if (paintingDisabled()) + return; + CGContextScaleCTM(platformContext(), size.width(), size.height()); + m_data->scale(size); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + +void GraphicsContext::rotate(float angle) +{ + if (paintingDisabled()) + return; + CGContextRotateCTM(platformContext(), angle); + m_data->rotate(angle); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + +void GraphicsContext::translate(float x, float y) +{ + if (paintingDisabled()) + return; + CGContextTranslateCTM(platformContext(), x, y); + m_data->translate(x, y); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + +void GraphicsContext::concatCTM(const AffineTransform& transform) +{ + if (paintingDisabled()) + return; + CGContextConcatCTM(platformContext(), transform); + m_data->concatCTM(transform); + m_data->m_userToDeviceTransformKnownToBeIdentity = false; +} + +AffineTransform GraphicsContext::getCTM() const +{ + return CGContextGetCTM(platformContext()); +} + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +{ + // It is not enough just to round to pixels in device space. The rotation part of the + // affine transform matrix to device space can mess with this conversion if we have a + // rotating image like the hands of the world clock widget. We just need the scale, so + // we get the affine transform matrix and extract the scale. + + if (m_data->m_userToDeviceTransformKnownToBeIdentity) + return rect; + + CGAffineTransform deviceMatrix = CGContextGetUserSpaceToDeviceSpaceTransform(platformContext()); + if (CGAffineTransformIsIdentity(deviceMatrix)) { + m_data->m_userToDeviceTransformKnownToBeIdentity = true; + return rect; + } + + float deviceScaleX = sqrtf(deviceMatrix.a * deviceMatrix.a + deviceMatrix.b * deviceMatrix.b); + float deviceScaleY = sqrtf(deviceMatrix.c * deviceMatrix.c + deviceMatrix.d * deviceMatrix.d); + + CGPoint deviceOrigin = CGPointMake(rect.x() * deviceScaleX, rect.y() * deviceScaleY); + CGPoint deviceLowerRight = CGPointMake((rect.x() + rect.width()) * deviceScaleX, + (rect.y() + rect.height()) * deviceScaleY); + + deviceOrigin.x = roundf(deviceOrigin.x); + deviceOrigin.y = roundf(deviceOrigin.y); + deviceLowerRight.x = roundf(deviceLowerRight.x); + deviceLowerRight.y = roundf(deviceLowerRight.y); + + // Don't let the height or width round to 0 unless either was originally 0 + if (deviceOrigin.y == deviceLowerRight.y && rect.height() != 0) + deviceLowerRight.y += 1; + if (deviceOrigin.x == deviceLowerRight.x && rect.width() != 0) + deviceLowerRight.x += 1; + + FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY); + FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x / deviceScaleX, deviceLowerRight.y / deviceScaleY); + return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); +} + +void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool printing) +{ + if (paintingDisabled()) + return; + + if (width <= 0) + return; + + CGContextSaveGState(platformContext()); + + float x = point.x(); + float y = point.y(); + float lineLength = width; + + // Use a minimum thickness of 0.5 in user space. + // See http://bugs.webkit.org/show_bug.cgi?id=4255 for details of why 0.5 is the right minimum thickness to use. + float thickness = max(strokeThickness(), 0.5f); + + if (!printing) { + // On screen, use a minimum thickness of 1.0 in user space (later rounded to an integral number in device space). + float adjustedThickness = max(thickness, 1.0f); + + // FIXME: This should be done a better way. + // We try to round all parameters to integer boundaries in device space. If rounding pixels in device space + // makes our thickness more than double, then there must be a shrinking-scale factor and rounding to pixels + // in device space will make the underlines too thick. + CGRect lineRect = roundToDevicePixels(FloatRect(x, y, lineLength, adjustedThickness)); + if (lineRect.size.height < thickness * 2.0) { + x = lineRect.origin.x; + y = lineRect.origin.y; + lineLength = lineRect.size.width; + thickness = lineRect.size.height; + CGContextSetShouldAntialias(platformContext(), false); + } + } + + if (fillColor() != strokeColor()) + setCGFillColor(platformContext(), strokeColor()); + CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness)); + + CGContextRestoreGState(platformContext()); +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ + if (paintingDisabled()) + return; + + CFURLRef urlRef = link.createCFURL(); + if (urlRef) { + CGContextRef context = platformContext(); + + // Get the bounding box to handle clipping. + CGRect box = CGContextGetClipBoundingBox(context); + + IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height); + IntRect rect = destRect; + rect.intersect(intBox); + + CGPDFContextSetURLForRect(context, urlRef, + CGRectApplyAffineTransform(rect, CGContextGetCTM(context))); + + CFRelease(urlRef); + } +} + +void GraphicsContext::setUseLowQualityImageInterpolation(bool lowQualityMode) +{ + if (paintingDisabled()) + return; + + CGContextSetInterpolationQuality(platformContext(), lowQualityMode ? kCGInterpolationNone : kCGInterpolationDefault); +} + +bool GraphicsContext::useLowQualityImageInterpolation() const +{ + if (paintingDisabled()) + return false; + + return CGContextGetInterpolationQuality(platformContext()); +} + +void GraphicsContext::setPlatformTextDrawingMode(int mode) +{ + if (paintingDisabled()) + return; + + // Wow, wish CG had used bits here. + CGContextRef context = platformContext(); + switch (mode) { + case cTextInvisible: // Invisible + CGContextSetTextDrawingMode(context, kCGTextInvisible); + break; + case cTextFill: // Fill + CGContextSetTextDrawingMode(context, kCGTextFill); + break; + case cTextStroke: // Stroke + CGContextSetTextDrawingMode(context, kCGTextStroke); + break; + case 3: // Fill | Stroke + CGContextSetTextDrawingMode(context, kCGTextFillStroke); + break; + case cTextClip: // Clip + CGContextSetTextDrawingMode(context, kCGTextClip); + break; + case 5: // Fill | Clip + CGContextSetTextDrawingMode(context, kCGTextFillClip); + break; + case 6: // Stroke | Clip + CGContextSetTextDrawingMode(context, kCGTextStrokeClip); + break; + case 7: // Fill | Stroke | Clip + CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip); + break; + default: + break; + } +} + +void GraphicsContext::setPlatformStrokeColor(const Color& color) +{ + if (paintingDisabled()) + return; + setCGStrokeColor(platformContext(), color); +} + +void GraphicsContext::setPlatformStrokeThickness(float thickness) +{ + if (paintingDisabled()) + return; + CGContextSetLineWidth(platformContext(), thickness); +} + +void GraphicsContext::setPlatformFillColor(const Color& color) +{ + if (paintingDisabled()) + return; + setCGFillColor(platformContext(), color); +} + +void GraphicsContext::setUseAntialiasing(bool enable) +{ + if (paintingDisabled()) + return; + CGContextSetShouldAntialias(platformContext(), enable); +} + +#ifndef BUILDING_ON_TIGER // Tiger's setCompositeOperation() is defined in GraphicsContextMac.mm. +void GraphicsContext::setCompositeOperation(CompositeOperator mode) +{ + if (paintingDisabled()) + return; + + CGBlendMode target = kCGBlendModeNormal; + switch (mode) { + case CompositeClear: + target = kCGBlendModeClear; + break; + case CompositeCopy: + target = kCGBlendModeCopy; + break; + case CompositeSourceOver: + //kCGBlendModeNormal + break; + case CompositeSourceIn: + target = kCGBlendModeSourceIn; + break; + case CompositeSourceOut: + target = kCGBlendModeSourceOut; + break; + case CompositeSourceAtop: + target = kCGBlendModeSourceAtop; + break; + case CompositeDestinationOver: + target = kCGBlendModeDestinationOver; + break; + case CompositeDestinationIn: + target = kCGBlendModeDestinationIn; + break; + case CompositeDestinationOut: + target = kCGBlendModeDestinationOut; + break; + case CompositeDestinationAtop: + target = kCGBlendModeDestinationAtop; + break; + case CompositeXOR: + target = kCGBlendModeXOR; + break; + case CompositePlusDarker: + target = kCGBlendModePlusDarker; + break; + case CompositeHighlight: + // currently unsupported + break; + case CompositePlusLighter: + target = kCGBlendModePlusLighter; + break; + } + CGContextSetBlendMode(platformContext(), target); +} +#endif + +void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r) +{ + CGContextRef context = buffer->context()->platformContext(); + if (!context) + return; + CGContextFlush(context); + if (CGImageRef image = CGBitmapContextCreateImage(context)) { + CGContextDrawImage(platformContext(), roundToDevicePixels(r), image); + CGImageRelease(image); + } +} + +void GraphicsContext::drawImage(ImageBuffer* buffer, const FloatRect& srcRect, const FloatRect& destRect) +{ + CGContextRef context = buffer->context()->platformContext(); + CGContextFlush(context); + RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context)); + float iw = CGImageGetWidth(image.get()); + float ih = CGImageGetHeight(image.get()); + if (srcRect.x() == 0 && srcRect.y() == 0 && iw == srcRect.width() && ih == srcRect.height()) { + // Fast path, yay! + CGContextDrawImage(platformContext(), destRect, image.get()); + } else { + // Slow path, boo! + // FIXME: We can do this without creating a separate image + + size_t csw = static_cast<size_t>(ceilf(srcRect.width())); + size_t csh = static_cast<size_t>(ceilf(srcRect.height())); + + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + size_t bytesPerRow = csw * 4; + OwnArrayPtr<char> buffer(new char[csh * bytesPerRow]); + RetainPtr<CGContextRef> clippedSourceContext(AdoptCF, CGBitmapContextCreate(buffer.get(), csw, csh, + 8, bytesPerRow, colorSpace.get(), kCGImageAlphaPremultipliedLast)); + CGContextTranslateCTM(clippedSourceContext.get(), -srcRect.x(), -srcRect.y()); + CGContextDrawImage(clippedSourceContext.get(), CGRectMake(0, 0, iw, ih), image.get()); + + RetainPtr<CGImageRef> clippedSourceImage(AdoptCF, CGBitmapContextCreateImage(clippedSourceContext.get())); + + CGContextDrawImage(platformContext(), destRect, clippedSourceImage.get()); + } +} + +} + diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h new file mode 100644 index 0000000..937481b --- /dev/null +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <CoreGraphics/CGContext.h> + +namespace WebCore { + +class GraphicsContextPlatformPrivate { +public: + GraphicsContextPlatformPrivate(CGContextRef cgContext) + : m_cgContext(cgContext) +#if PLATFORM(WIN) + , m_hdc(0) + , m_transparencyCount(0) +#endif + , m_userToDeviceTransformKnownToBeIdentity(false) + { + CGContextRetain(m_cgContext); + } + + ~GraphicsContextPlatformPrivate() + { + CGContextRelease(m_cgContext); + } + +#if PLATFORM(MAC) + // These methods do nothing on Mac. + void save() {} + void restore() {} + void clip(const IntRect&) {} + void clip(const Path&) {} + void scale(const FloatSize&) {} + void rotate(float) {} + void translate(float, float) {} + void concatCTM(const AffineTransform&) {} + void beginTransparencyLayer() {} + void endTransparencyLayer() {} +#endif + +#if PLATFORM(WIN) + // On Windows, we need to update the HDC for form controls to draw in the right place. + void save(); + void restore(); + void clip(const IntRect&); + 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--; } +#endif + +#if PLATFORM(WIN) + HDC m_hdc; + unsigned m_transparencyCount; +#endif + + CGContextRef m_cgContext; + bool m_userToDeviceTransformKnownToBeIdentity; +}; + +} diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp new file mode 100644 index 0000000..2e48ceb --- /dev/null +++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Apple, 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageBuffer.h" + +#include "GraphicsContext.h" +#include "ImageData.h" + +#include <ApplicationServices/ApplicationServices.h> +#include <wtf/Assertions.h> + +using namespace std; + +namespace WebCore { + +auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale) +{ + if (size.width() < 0 || size.height() < 0) + return auto_ptr<ImageBuffer>(); + unsigned int bytesPerRow = size.width(); + if (!grayScale) { + // Protect against overflow + if (bytesPerRow > 0x3FFFFFFF) + return auto_ptr<ImageBuffer>(); + bytesPerRow *= 4; + } + + void* imageBuffer = fastCalloc(size.height(), bytesPerRow); + if (!imageBuffer) + return auto_ptr<ImageBuffer>(); + + CGColorSpaceRef colorSpace = grayScale ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); + CGContextRef cgContext = CGBitmapContextCreate(imageBuffer, size.width(), size.height(), 8, bytesPerRow, + colorSpace, grayScale ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast); + CGColorSpaceRelease(colorSpace); + if (!cgContext) { + fastFree(imageBuffer); + return auto_ptr<ImageBuffer>(); + } + + auto_ptr<GraphicsContext> context(new GraphicsContext(cgContext)); + 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) +{ + ASSERT((reinterpret_cast<size_t>(imageData) & 2) == 0); +} + +ImageBuffer::~ImageBuffer() +{ + fastFree(m_data); + CGImageRelease(m_cgImage); +} + +GraphicsContext* ImageBuffer::context() const +{ + return m_context.get(); +} + +CGImageRef ImageBuffer::cgImage() 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) { + ASSERT(context()); + m_cgImage = CGBitmapContextCreateImage(context()->platformContext()); + } + + return m_cgImage; +} + +PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +{ + if (!m_data) + 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 srcBytesPerRow = 4 * m_size.width(); + unsigned destBytesPerRow = 4 * rect.width(); + + // m_size.height() - originy to handle the accursed flipped y axis in CG backing store + unsigned char* srcRows = reinterpret_cast<unsigned char*>(m_data) + (m_size.height() - originy - 1) * 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++) { + if (unsigned char alpha = srcRows[3]) { + destRows[0] = (srcRows[0] * 255) / alpha; + destRows[1] = (srcRows[1] * 255) / alpha; + destRows[2] = (srcRows[2] * 255) / alpha; + destRows[3] = alpha; + } else { + reinterpret_cast<uint32_t*>(destRows)[0] = reinterpret_cast<uint32_t*>(srcRows)[0]; + } + destRows += 4; + } + srcRows -= srcBytesPerRow; + } + 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(endx <= 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; + + // -desty to handle the accursed flipped y axis + unsigned char* destRows = reinterpret_cast<unsigned char*>(m_data) + (m_size.height() - desty - 1) * destBytesPerRow + destx * 4; + for (int y = 0; y < numRows; ++y) { + for (int x = 0; x < numColumns; x++) { + unsigned char alpha = srcRows[x * 4 + 3]; + if (alpha != 255) { + destRows[x * 4 + 0] = (srcRows[0] * alpha) / 255; + destRows[x * 4 + 1] = (srcRows[1] * alpha) / 255; + destRows[x * 4 + 2] = (srcRows[2] * alpha) / 255; + destRows[x * 4 + 3] = alpha; + } else { + reinterpret_cast<uint32_t*>(destRows + x * 4)[0] = reinterpret_cast<uint32_t*>(srcRows + x * 4)[0]; + } + } + destRows -= destBytesPerRow; + srcRows += srcBytesPerRow; + } +} + +} diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp new file mode 100644 index 0000000..5958d86 --- /dev/null +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BitmapImage.h" + +#if PLATFORM(CG) + +#include "AffineTransform.h" +#include "FloatConversion.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "ImageObserver.h" +#include "PDFDocumentImage.h" +#include "PlatformString.h" +#include <ApplicationServices/ApplicationServices.h> + +#if PLATFORM(MAC) +#include "WebCoreSystemInterface.h" +#endif + +#if PLATFORM(WIN) +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#endif + +namespace WebCore { + +void FrameData::clear() +{ + if (m_frame) { + CGImageRelease(m_frame); + m_frame = 0; + m_duration = 0.0f; + m_hasAlpha = true; + } +} + +// ================================================ +// Image Class +// ================================================ + +// Drawing Routines + +void BitmapImage::checkForSolidColor() +{ + if (frameCount() > 1) + m_isSolidColor = false; + else { + CGImageRef image = frameAtIndex(0); + + // Currently we only check for solid color in the important special case of a 1x1 image. + if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) { + unsigned char pixel[4]; // RGBA + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + CGContextRef bmap = CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), space, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); + if (bmap) { + GraphicsContext(bmap).setCompositeOperation(CompositeCopy); + CGRect dst = { {0, 0}, {1, 1} }; + CGContextDrawImage(bmap, dst, image); + if (pixel[3] == 0) + m_solidColor = Color(0, 0, 0, 0); + else + m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]); + m_isSolidColor = true; + CFRelease(bmap); + } + CFRelease(space); + } + } +} + +CGImageRef BitmapImage::getCGImageRef() +{ + return frameAtIndex(0); +} + +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp) +{ + if (!m_source.initialized()) + return; + + CGRect fr = ctxt->roundToDevicePixels(srcRect); + CGRect ir = ctxt->roundToDevicePixels(dstRect); + + 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); + 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; + } + } + + CGContextRef context = ctxt->platformContext(); + ctxt->save(); + + // Flip the coords. + ctxt->setCompositeOperation(compositeOp); + CGContextTranslateCTM(context, ir.origin.x, ir.origin.y); + 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); + + ctxt->restore(); + + startAnimation(); + + if (imageObserver()) + imageObserver()->didDraw(this); +} + +void Image::drawPatternCallback(void* info, CGContextRef context) +{ + CGImageRef image = (CGImageRef)info; + CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect(0, 0, CGImageGetWidth(image), CGImageGetHeight(image))), image); +} + +void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + ASSERT(patternTransform.isInvertible()); + if (!patternTransform.isInvertible()) + // Avoid a hang under CGContextDrawTiledImage on release builds. + return; + + CGContextRef context = ctxt->platformContext(); + ctxt->save(); + CGContextClipToRect(context, destRect); + ctxt->setCompositeOperation(op); + CGContextTranslateCTM(context, destRect.x(), destRect.y()); + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -destRect.height()); + + // Compute the scaled tile size. + float scaledTileHeight = tileRect.height() * narrowPrecisionToFloat(patternTransform.d()); + + // We have to adjust the phase to deal with the fact we're in Cartesian space now (with the bottom left corner of destRect being + // the origin). + float adjustedX = phase.x() - destRect.x() + tileRect.x() * narrowPrecisionToFloat(patternTransform.a()); // We translated the context so that destRect.x() is the origin, so subtract it out. + float adjustedY = destRect.height() - (phase.y() - destRect.y() + tileRect.y() * narrowPrecisionToFloat(patternTransform.d()) + scaledTileHeight); + + CGImageRef tileImage = nativeImageForCurrentFrame(); + float h = CGImageGetHeight(tileImage); + + CGImageRef subImage; + if (tileRect.size() == size()) + subImage = tileImage; + else { + // Copying a sub-image out of a partially-decoded image stops the decoding of the original image. It should never happen + // because sub-images are only used for border-image, which only renders when the image is fully decoded. + ASSERT(h == height()); + subImage = CGImageCreateWithImageInRect(tileImage, tileRect); + } + +#ifndef BUILDING_ON_TIGER + // Leopard has an optimized call for the tiling of image patterns, but we can only use it if the image has been decoded enough that + // its buffer is the same size as the overall image. Because a partially decoded CGImageRef with a smaller width or height than the + // overall image buffer needs to tile with "gaps", we can't use the optimized tiling call in that case. + // FIXME: Could create WebKitSystemInterface SPI for CGCreatePatternWithImage2 and probably make Tiger tile faster as well. + float scaledTileWidth = tileRect.width() * narrowPrecisionToFloat(patternTransform.a()); + float w = CGImageGetWidth(tileImage); + if (w == size().width() && h == size().height()) + CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage); + else { +#endif + + // On Leopard, this code now only runs for partially decoded images whose buffers do not yet match the overall size of the image. + // On Tiger this code runs all the time. This code is suboptimal because the pattern does not reference the image directly, and the + // pattern is destroyed before exiting the function. This means any decoding the pattern does doesn't end up cached anywhere, so we + // redecode every time we paint. + static const CGPatternCallbacks patternCallbacks = { 0, drawPatternCallback, NULL }; + CGAffineTransform matrix = CGAffineTransformMake(narrowPrecisionToCGFloat(patternTransform.a()), 0, 0, narrowPrecisionToCGFloat(patternTransform.d()), adjustedX, adjustedY); + matrix = CGAffineTransformConcat(matrix, CGContextGetCTM(context)); + // The top of a partially-decoded image is drawn at the bottom of the tile. Map it to the top. + matrix = CGAffineTransformTranslate(matrix, 0, size().height() - h); + CGPatternRef pattern = CGPatternCreate(subImage, CGRectMake(0, 0, tileRect.width(), tileRect.height()), + matrix, tileRect.width(), tileRect.height(), + kCGPatternTilingConstantSpacing, true, &patternCallbacks); + if (pattern == NULL) { + if (subImage != tileImage) + CGImageRelease(subImage); + ctxt->restore(); + return; + } + + CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); + + CGFloat alpha = 1; + CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha); + CGContextSetFillColorSpace(context, patternSpace); + CGColorSpaceRelease(patternSpace); + CGPatternRelease(pattern); + + // FIXME: Really want a public API for this. It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy). + wkSetPatternBaseCTM(context, CGAffineTransformIdentity); + CGContextSetPatternPhase(context, CGSizeZero); + + CGContextSetFillColorWithColor(context, color); + CGContextFillRect(context, CGContextGetClipBoundingBox(context)); + + CGColorRelease(color); + +#ifndef BUILDING_ON_TIGER + } +#endif + + if (subImage != tileImage) + CGImageRelease(subImage); + ctxt->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); +} + + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp new file mode 100644 index 0000000..08e8172 --- /dev/null +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageSource.h" + +#if PLATFORM(CG) + +#include "IntSize.h" +#include "SharedBuffer.h" +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); + +ImageSource::ImageSource() + : m_decoder(0) +{ +} + +ImageSource::~ImageSource() +{ + clear(); +} + +void ImageSource::clear() +{ + if (m_decoder) { + CFRelease(m_decoder); + m_decoder = 0; + } +} + +CFDictionaryRef imageSourceOptions() +{ + static CFDictionaryRef options; + + if (!options) { + const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 }; + const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue }; + options = CFDictionaryCreate(NULL, keys, values, 2, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + return options; +} + +bool ImageSource::initialized() const +{ + return m_decoder; +} + +void ImageSource::setData(SharedBuffer* data, bool allDataReceived) +{ + if (!m_decoder) + m_decoder = CGImageSourceCreateIncremental(NULL); +#if PLATFORM(MAC) + // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability + // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. + CFDataRef cfData = data->createCFData(); +#else + // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the + // scenes. We use CFDataCreateWithBytesNoCopy in that case. + CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), kCFAllocatorNull); +#endif + CGImageSourceUpdateData(m_decoder, cfData, allDataReceived); + CFRelease(cfData); +} + +bool ImageSource::isSizeAvailable() +{ + bool result = false; + CGImageSourceStatus imageSourceStatus = CGImageSourceGetStatus(m_decoder); + + // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus! + if (imageSourceStatus >= kCGImageStatusIncomplete) { + CFDictionaryRef image0Properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()); + if (image0Properties) { + CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelWidth); + CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelHeight); + result = widthNumber && heightNumber; + CFRelease(image0Properties); + } + } + + return result; +} + +IntSize ImageSource::size() const +{ + IntSize result; + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()); + if (properties) { + int w = 0, h = 0; + CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + if (num) + CFNumberGetValue(num, kCFNumberIntType, &w); + num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + if (num) + CFNumberGetValue(num, kCFNumberIntType, &h); + result = IntSize(w, h); + CFRelease(properties); + } + return result; +} + +int ImageSource::repetitionCount() +{ + int result = cAnimationLoopOnce; // No property means loop once. + + // A property with value 0 means loop forever. + CFDictionaryRef properties = CGImageSourceCopyProperties(m_decoder, imageSourceOptions()); + if (properties) { + CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + if (gifProperties) { + CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); + if (num) + CFNumberGetValue(num, kCFNumberIntType, &result); + } else + result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate. + + CFRelease(properties); + } + + return result; +} + +size_t ImageSource::frameCount() const +{ + return m_decoder ? CGImageSourceGetCount(m_decoder) : 0; +} + +CGImageRef ImageSource::createFrameAtIndex(size_t index) +{ + CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions()); + CFStringRef imageUTI = CGImageSourceGetType(m_decoder); + static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); + if (!imageUTI || !CFEqual(imageUTI, xbmUTI)) + return image; + + // If it is an xbm image, mask out all the white areas to render them transparent. + const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255}; + CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors); + if (!maskedImage) + return image; + + CGImageRelease(image); + return maskedImage; +} + +bool ImageSource::frameIsCompleteAtIndex(size_t index) +{ + return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete; +} + +float ImageSource::frameDurationAtIndex(size_t index) +{ + float duration = 0; + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()); + if (properties) { + CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + if (typeProperties) { + CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime); + if (num) + CFNumberGetValue(num, kCFNumberFloatType, &duration); + } + CFRelease(properties); + } + + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. + // We follow WinIE's behavior and use a duration of 100 ms for any frames that specify + // a duration of <= 50 ms. See <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for more. + if (duration < 0.051f) + return 0.100f; + return duration; +} + +bool ImageSource::frameHasAlphaAtIndex(size_t index) +{ + // Might be interesting to do this optimization on Mac some day, but for now we're just using this + // for the Cairo source, since it uses our decoders, and our decoders can answer this question. + // FIXME: Could return false for JPEG and other non-transparent image formats. + // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary + // to determine whether or not a transparent color was defined. + return true; +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/IntPointCG.cpp b/WebCore/platform/graphics/cg/IntPointCG.cpp new file mode 100644 index 0000000..95dbe5f --- /dev/null +++ b/WebCore/platform/graphics/cg/IntPointCG.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntPoint.h" + +#if PLATFORM(CG) + +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +IntPoint::IntPoint(const CGPoint& p) : m_x(static_cast<int>(p.x)), m_y(static_cast<int>(p.y)) +{ +} + +IntPoint::operator CGPoint() const +{ + return CGPointMake(m_x, m_y); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/IntRectCG.cpp b/WebCore/platform/graphics/cg/IntRectCG.cpp new file mode 100644 index 0000000..73fd63f --- /dev/null +++ b/WebCore/platform/graphics/cg/IntRectCG.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntRect.h" + +#if PLATFORM(CG) + +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +IntRect::operator CGRect() const +{ + return CGRectMake(x(), y(), width(), height()); +} + +IntRect enclosingIntRect(const CGRect& rect) +{ + int l = static_cast<int>(floorf(rect.origin.x)); + int t = static_cast<int>(floorf(rect.origin.y)); + int r = static_cast<int>(ceilf(CGRectGetMaxX(rect))); + int b = static_cast<int>(ceilf(CGRectGetMaxY(rect))); + return IntRect(l, t, r - l, b - t); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/IntSizeCG.cpp b/WebCore/platform/graphics/cg/IntSizeCG.cpp new file mode 100644 index 0000000..d8e8c83 --- /dev/null +++ b/WebCore/platform/graphics/cg/IntSizeCG.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntSize.h" + +#if PLATFORM(CG) + +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +IntSize::IntSize(const CGSize& s) : m_width(static_cast<int>(s.width)), m_height(static_cast<int>(s.height)) +{ +} + +IntSize::operator CGSize() const +{ + return CGSizeMake(m_width, m_height); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp new file mode 100644 index 0000000..2578f08 --- /dev/null +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define _USE_MATH_DEFINES 1 +#include "config.h" +#include "PDFDocumentImage.h" + +#if PLATFORM(CG) + +#include "GraphicsContext.h" +#include "ImageObserver.h" +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +PDFDocumentImage::PDFDocumentImage() + : Image(0) // PDFs don't animate + , m_document(0) + , m_rotation(0.0f) + , m_currentPage(-1) +{ +} + +PDFDocumentImage::~PDFDocumentImage() +{ + CGPDFDocumentRelease(m_document); +} + +IntSize PDFDocumentImage::size() const +{ + const float sina = sinf(-m_rotation); + const float cosa = cosf(-m_rotation); + const float width = m_mediaBox.size().width(); + const float height = m_mediaBox.size().height(); + const float rotWidth = width * cosa - height * sina; + const float rotHeight = width * sina + height * cosa; + + return IntSize((int)(fabsf(rotWidth) + 0.5f), (int)(fabsf(rotHeight) + 0.5f)); +} + +bool PDFDocumentImage::dataChanged(bool allDataReceived) +{ + if (allDataReceived && !m_document) { +#if PLATFORM(MAC) + // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability + // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. + CFDataRef data = m_data->createCFData(); +#else + // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the + // scenes. We use CFDataCreateWithBytesNoCopy in that case. + CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(m_data->data()), m_data->size(), kCFAllocatorNull); +#endif + CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); + CFRelease(data); + m_document = CGPDFDocumentCreateWithProvider(dataProvider); + CGDataProviderRelease(dataProvider); + setCurrentPage(0); + } + return m_document; // return true if size is available +} + +void PDFDocumentImage::adjustCTM(GraphicsContext* context) const +{ + // rotate the crop box and calculate bounding box + float sina = sinf(-m_rotation); + float cosa = cosf(-m_rotation); + float width = m_cropBox.width(); + float height = m_cropBox.height(); + + // calculate rotated x and y edges of the corp box. if they're negative, it means part of the image has + // been rotated outside of the bounds and we need to shift over the image so it lies inside the bounds again + CGPoint rx = CGPointMake(width * cosa, width * sina); + CGPoint ry = CGPointMake(-height * sina, height * cosa); + + // adjust so we are at the crop box origin + const CGFloat zero = 0; + CGContextTranslateCTM(context->platformContext(), floorf(-min(zero, min(rx.x, ry.x))), floorf(-min(zero, min(rx.y, ry.y)))); + + // rotate -ve to remove rotation + CGContextRotateCTM(context->platformContext(), -m_rotation); + + // shift so we are completely within media box + CGContextTranslateCTM(context->platformContext(), m_mediaBox.x() - m_cropBox.x(), m_mediaBox.y() - m_cropBox.y()); +} + +void PDFDocumentImage::setCurrentPage(int page) +{ + if (!m_document) + return; + + if (page == m_currentPage) + return; + + if (!(page >= 0 && page < pageCount())) + return; + + m_currentPage = page; + + CGPDFPageRef cgPage = CGPDFDocumentGetPage(m_document, page + 1); + + // get media box (guaranteed) + m_mediaBox = CGPDFPageGetBoxRect(cgPage, kCGPDFMediaBox); + + // get crop box (not always there). if not, use media box + CGRect r = CGPDFPageGetBoxRect(cgPage, kCGPDFCropBox); + if (!CGRectIsEmpty(r)) + m_cropBox = r; + else + m_cropBox = m_mediaBox; + + // get page rotation angle + m_rotation = CGPDFPageGetRotationAngle(cgPage) * piFloat / 180.0f; // to radians +} + +int PDFDocumentImage::pageCount() const +{ + return m_document ? CGPDFDocumentGetNumberOfPages(m_document) : 0; +} + +void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op) +{ + if (!m_document || m_currentPage == -1) + return; + + context->save(); + + context->setCompositeOperation(op); + + float hScale = dstRect.width() / srcRect.width(); + float vScale = dstRect.height() / srcRect.height(); + + // Scale and translate so the document is rendered in the correct location, + // including accounting for the fact that a GraphicsContext is always flipped + // and doing appropriate flipping. + CGContextTranslateCTM(context->platformContext(), dstRect.x() - srcRect.x() * hScale, dstRect.y() - srcRect.y() * vScale); + CGContextScaleCTM(context->platformContext(), hScale, vScale); + CGContextScaleCTM(context->platformContext(), 1, -1); + CGContextTranslateCTM(context->platformContext(), 0, -srcRect.height()); + CGContextClipToRect(context->platformContext(), CGRectIntegral(srcRect)); + + // Rotate translate image into position according to doc properties. + adjustCTM(context); + + CGContextTranslateCTM(context->platformContext(), -m_mediaBox.x(), -m_mediaBox.y()); + CGContextDrawPDFPage(context->platformContext(), CGPDFDocumentGetPage(m_document, m_currentPage + 1)); + + context->restore(); + + if (imageObserver()) + imageObserver()->didDraw(this); +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h new file mode 100644 index 0000000..caddc05 --- /dev/null +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Image.h" + +#include "FloatRect.h" +#include "GraphicsTypes.h" + +#if PLATFORM(CG) + +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + + class GraphicsContext; + + class PDFDocumentImage : public Image { + public: + PDFDocumentImage(); + ~PDFDocumentImage(); + + virtual bool dataChanged(bool allDataReceived); + + virtual IntSize size() const; + + private: + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + + void setCurrentPage(int); + int pageCount() const; + void adjustCTM(GraphicsContext*) const; + + CGPDFDocumentRef m_document; + FloatRect m_mediaBox; + FloatRect m_cropBox; + float m_rotation; + int m_currentPage; + }; + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp new file mode 100644 index 0000000..c0a0caf --- /dev/null +++ b/WebCore/platform/graphics/cg/PathCG.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * 2006 Rob Buis <buis@kde.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Path.h" + +#if PLATFORM(CG) + +#include "AffineTransform.h" +#include <ApplicationServices/ApplicationServices.h> +#include "FloatRect.h" +#include "IntRect.h" +#include "PlatformString.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +Path::Path() + : m_path(CGPathCreateMutable()) +{ +} + +Path::~Path() +{ + CGPathRelease(m_path); +} + +Path::Path(const Path& other) + : m_path(CGPathCreateMutableCopy(other.m_path)) +{ +} + +Path& Path::operator=(const Path& other) +{ + CGMutablePathRef path = CGPathCreateMutableCopy(other.m_path); + CGPathRelease(m_path); + m_path = path; + return *this; +} + + +static void copyClosingSubpathsApplierFunction(void* info, const CGPathElement* element) +{ + CGMutablePathRef path = static_cast<CGMutablePathRef>(info); + CGPoint* points = element->points; + + switch (element->type) { + case kCGPathElementMoveToPoint: + if (!CGPathIsEmpty(path)) // to silence a warning when trying to close an empty path + CGPathCloseSubpath(path); // This is the only change from CGPathCreateMutableCopy + CGPathMoveToPoint(path, 0, points[0].x, points[0].y); + break; + case kCGPathElementAddLineToPoint: + CGPathAddLineToPoint(path, 0, points[0].x, points[0].y); + break; + case kCGPathElementAddQuadCurveToPoint: + CGPathAddQuadCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y); + break; + case kCGPathElementAddCurveToPoint: + CGPathAddCurveToPoint(path, 0, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); + break; + case kCGPathElementCloseSubpath: + CGPathCloseSubpath(path); + break; + } +} + +static CGMutablePathRef copyCGPathClosingSubpaths(CGPathRef originalPath) +{ + CGMutablePathRef path = CGPathCreateMutable(); + CGPathApply(originalPath, path, copyClosingSubpathsApplierFunction); + CGPathCloseSubpath(path); + return path; +} + +bool Path::contains(const FloatPoint &point, WindRule rule) const +{ + if (!boundingRect().contains(point)) + return false; + + // CGPathContainsPoint returns false for non-closed paths, as a work-around, we copy and close the path first. Radar 4758998 asks for a better CG API to use + CGMutablePathRef path = copyCGPathClosingSubpaths(m_path); + bool ret = CGPathContainsPoint(path, 0, point, rule == RULE_EVENODD ? true : false); + CGPathRelease(path); + return ret; +} + +void Path::translate(const FloatSize& size) +{ + CGAffineTransform translation = CGAffineTransformMake(1, 0, 0, 1, size.width(), size.height()); + CGMutablePathRef newPath = CGPathCreateMutable(); + CGPathAddPath(newPath, &translation, m_path); + CGPathRelease(m_path); + m_path = newPath; +} + +FloatRect Path::boundingRect() const +{ + return CGPathGetBoundingBox(m_path); +} + +void Path::moveTo(const FloatPoint& point) +{ + CGPathMoveToPoint(m_path, 0, point.x(), point.y()); +} + +void Path::addLineTo(const FloatPoint& p) +{ + CGPathAddLineToPoint(m_path, 0, p.x(), p.y()); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + CGPathAddQuadCurveToPoint(m_path, 0, cp.x(), cp.y(), p.x(), p.y()); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + CGPathAddCurveToPoint(m_path, 0, cp1.x(), cp1.y(), cp2.x(), cp2.y(), p.x(), p.y()); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + CGPathAddArcToPoint(m_path, 0, p1.x(), p1.y(), p2.x(), p2.y(), radius); +} + +void Path::closeSubpath() +{ + if (!CGPathIsEmpty(m_path)) // to silence a warning when trying to close an empty path + CGPathCloseSubpath(m_path); +} + +void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool clockwise) +{ + // Workaround for <rdar://problem/5189233> CGPathAddArc hangs or crashes when passed inf as start or end angle + if (isfinite(sa) && isfinite(ea)) + CGPathAddArc(m_path, 0, p.x(), p.y(), r, sa, ea, clockwise); +} + +void Path::addRect(const FloatRect& r) +{ + CGPathAddRect(m_path, 0, r); +} + +void Path::addEllipse(const FloatRect& r) +{ + CGPathAddEllipseInRect(m_path, 0, r); +} + +void Path::clear() +{ + CGPathRelease(m_path); + m_path = CGPathCreateMutable(); +} + +bool Path::isEmpty() const +{ + return CGPathIsEmpty(m_path); + } + +static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *element) +{ + CFMutableStringRef string = (CFMutableStringRef)info; + CFStringRef typeString = CFSTR(""); + CGPoint* points = element->points; + switch (element->type) { + case kCGPathElementMoveToPoint: + CFStringAppendFormat(string, 0, CFSTR("M%.2f,%.2f"), points[0].x, points[0].y); + break; + case kCGPathElementAddLineToPoint: + CFStringAppendFormat(string, 0, CFSTR("L%.2f,%.2f"), points[0].x, points[0].y); + break; + case kCGPathElementAddQuadCurveToPoint: + CFStringAppendFormat(string, 0, CFSTR("Q%.2f,%.2f,%.2f,%.2f"), + points[0].x, points[0].y, points[1].x, points[1].y); + break; + case kCGPathElementAddCurveToPoint: + CFStringAppendFormat(string, 0, CFSTR("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f"), + points[0].x, points[0].y, points[1].x, points[1].y, + points[2].x, points[2].y); + break; + case kCGPathElementCloseSubpath: + typeString = CFSTR("X"); break; + } +} + +static CFStringRef CFStringFromCGPath(CGPathRef path) +{ + if (!path) + return 0; + + CFMutableStringRef string = CFStringCreateMutable(NULL, 0); + CGPathApply(path, string, CGPathToCFStringApplierFunction); + + return string; +} + + +#pragma mark - +#pragma mark Path Management + +String Path::debugString() const +{ + String result; + if (!isEmpty()) { + CFStringRef pathString = CFStringFromCGPath(m_path); + result = String(pathString); + CFRelease(pathString); + } + return result; +} + +struct PathApplierInfo { + void* info; + PathApplierFunction function; +}; + +void CGPathApplierToPathApplier(void *info, const CGPathElement *element) +{ + PathApplierInfo* pinfo = (PathApplierInfo*)info; + FloatPoint points[3]; + PathElement pelement; + pelement.type = (PathElementType)element->type; + pelement.points = points; + CGPoint* cgPoints = element->points; + switch (element->type) { + case kCGPathElementMoveToPoint: + case kCGPathElementAddLineToPoint: + points[0] = cgPoints[0]; + break; + case kCGPathElementAddQuadCurveToPoint: + points[0] = cgPoints[0]; + points[1] = cgPoints[1]; + break; + case kCGPathElementAddCurveToPoint: + points[0] = cgPoints[0]; + points[1] = cgPoints[1]; + points[2] = cgPoints[2]; + break; + case kCGPathElementCloseSubpath: + break; + } + pinfo->function(pinfo->info, &pelement); +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + PathApplierInfo pinfo; + pinfo.info = info; + pinfo.function = function; + CGPathApply(m_path, &pinfo, CGPathApplierToPathApplier); +} + +void Path::transform(const AffineTransform& transform) +{ + CGMutablePathRef path = CGPathCreateMutable(); + CGAffineTransform transformCG = transform; + CGPathAddPath(path, &transformCG, m_path); + CGPathRelease(m_path); + m_path = path; +} + +} + +#endif // PLATFORM(CG) diff --git a/WebCore/platform/graphics/gtk/ColorGtk.cpp b/WebCore/platform/graphics/gtk/ColorGtk.cpp new file mode 100644 index 0000000..27f1b14 --- /dev/null +++ b/WebCore/platform/graphics/gtk/ColorGtk.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Color.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +Color::Color(const GdkColor& c) + : m_color(makeRGB(c.red >> 8, c.green >> 8, c.blue >> 8)) + , m_valid(true) +{ +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp new file mode 100644 index 0000000..aec5758 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontCache.h" + +#include "Font.h" +#include "SimpleFontData.h" +#include <wtf/Assertions.h> + +namespace WebCore { + +void FontCache::platformInit() +{ + if (!FontPlatformData::init()) + ASSERT_NOT_REACHED(); +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + return new SimpleFontData(FontPlatformData(font.fontDescription(), font.family().family())); +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return new FontPlatformData(font.fontDescription(), font.family().family()); +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) +{ + // FIXME: Would be even better to somehow get the user's default font here. + // For now we'll pick the default that the user would get without changing any prefs. + static AtomicString timesStr("Times New Roman"); + return getCachedFontPlatformData(fontDescription, timesStr); +} + +bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family) +{ + FontPlatformData platformData(fontDescription, family); + return platformData.m_pattern != 0; +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + return new FontPlatformData(fontDescription, family); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp new file mode 100644 index 0000000..3ff63c2 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "SharedBuffer.h" +#include "FontPlatformData.h" + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ + cairo_font_face_destroy(m_fontFace); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic) +{ + return FontPlatformData(m_fontFace, size, bold, italic); +} + +static void releaseData(void* data) +{ + static_cast<SharedBuffer*>(data)->deref(); +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + int error; + + static FT_Library library = 0; + if (!library) { + error = FT_Init_FreeType(&library); + if (error) { + library = 0; + return 0; + } + } + + FT_Face face; + error = FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer->data()), buffer->size(), 0, &face); + if (error) + return 0; + + buffer->ref(); + cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_ft_face(face, 0); + + static cairo_user_data_key_t bufferKey; + cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData); + + return new FontCustomPlatformData(fontFace); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.h b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h new file mode 100644 index 0000000..237904d --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h @@ -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. + * + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include <wtf/Noncopyable.h> + +typedef struct _cairo_font_face cairo_font_face_t; + +namespace WebCore { + +class FontPlatformData; +class SharedBuffer; + +struct FontCustomPlatformData : Noncopyable { + FontCustomPlatformData(cairo_font_face_t* fontFace) + : m_fontFace(fontFace) + {} + + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic); + + cairo_font_face_t* m_fontFace; +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer); + +} + +#endif diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp new file mode 100644 index 0000000..387b61c --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (c) 2007 Hiroyuki Ikezoe + * Copyright (c) 2007 Kouhei Sutou + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Xan Lopez <xan@gnome.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" + +#include <cairo.h> +#include <pango/pango.h> +#include <pango/pangocairo.h> + +namespace WebCore { + +#define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff) +#define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff) + +static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length) +{ + gboolean need_copy = FALSE; + int i; + + for (i = 0; i < aLength; i++) { + if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { + need_copy = TRUE; + break; + } + else if (IS_HIGH_SURROGATE(aText[i])) { + if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) + i++; + else { + need_copy = TRUE; + break; + } + } + } + + if (need_copy) { + + /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ + /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ + + UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0])); + + /* don't need to reset i */ + for (i = 0; i < aLength; i++) { + if (!p[i] || IS_LOW_SURROGATE(p[i])) + p[i] = 0xFFFD; + else if (IS_HIGH_SURROGATE(p[i])) { + if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) + i++; + else + p[i] = 0xFFFD; + } + } + + aText = p; + } + + glong items_written; + text = g_utf16_to_utf8(aText, aLength, NULL, &items_written, NULL); + length = items_written; + + if (need_copy) + g_free((gpointer)aText); + +} + +static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to) +{ + gchar* utf8 = 0; + gint new_length = 0; + utf16_to_utf8(characters, length, utf8, new_length); + if (!utf8) + return NULL; + + if (from > 0) { + // discard the first 'from' characters + // FIXME: we should do this before the conversion probably + gchar* str_left = g_utf8_offset_to_pointer(utf8, from); + gchar* tmp = g_strdup(str_left); + g_free(utf8); + utf8 = tmp; + } + + gchar* pos = utf8; + gint len = strlen(pos); + GString* ret = g_string_new_len(NULL, len); + + // replace line break by space + while (len > 0) { + gint index, start; + pango_find_paragraph_boundary(pos, len, &index, &start); + g_string_append_len(ret, pos, index); + if (index == start) + break; + g_string_append_c(ret, ' '); + pos += start; + len -= start; + } + return g_string_free(ret, FALSE); +} + +static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout) +{ + PangoAttrList* list = pango_attr_list_new(); + PangoAttribute* attr; + + attr = pango_attr_size_new_absolute((int)(font->size() * PANGO_SCALE)); + attr->end_index = G_MAXUINT; + pango_attr_list_insert_before(list, attr); + + if (!run.spacingDisabled()) { + attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE); + attr->end_index = G_MAXUINT; + pango_attr_list_insert_before(list, attr); + } + + // Pango does not yet support synthesising small caps + // See http://bugs.webkit.org/show_bug.cgi?id=15610 + + pango_layout_set_attributes(layout, list); + pango_attr_list_unref(list); + + 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::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + cairo_t* cr = context->platformContext(); + cairo_save(cr); + + PangoLayout* layout = pango_cairo_create_layout(cr); + + gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), from, to); + pango_layout_set_text(layout, utf8, -1); + g_free(utf8); + + setPangoAttributes(this, run, layout); + + // Set the text color to use for drawing. + float red, green, blue, alpha; + Color penColor = context->fillColor(); + penColor.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); + pango_cairo_show_layout_line(cr, layoutLine); + + 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 +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)); + PangoLayout* layout = pango_layout_new(pangoContext); + g_object_unref(pangoContext); + + return layout; +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + if (run.length() == 0) + return 0.0f; + + PangoLayout* layout = getDefaultPangoLayout(run); + setPangoAttributes(this, run, layout); + + gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); + pango_layout_set_text(layout, utf8, -1); + g_free(utf8); + + int layoutWidth; + pango_layout_get_size(layout, &layoutWidth, 0); + float width = (float)layoutWidth / (double)PANGO_SCALE; + g_object_unref(layout); + + return width; +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const +{ + PangoLayout* layout = getDefaultPangoLayout(run); + setPangoAttributes(this, run, layout); + + gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length()); + pango_layout_set_text(layout, utf8, -1); + + int index, trailing; + pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing); + glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index); + g_free(utf8); + g_object_unref(layout); + + return offset; +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const +{ + notImplemented(); + return FloatRect(); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h new file mode 100644 index 0000000..778d525 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontPlatformData.h @@ -0,0 +1,80 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontPlatformData_h +#define FontPlatformData_h + +#include "GlyphBuffer.h" +#include "FontDescription.h" +#include <cairo.h> +#include <cairo-ft.h> +#include <fontconfig/fcfreetype.h> + +namespace WebCore { + +class FontPlatformData { +public: + class Deleted {}; + FontPlatformData(Deleted) + : m_pattern(reinterpret_cast<FcPattern*>(-1)) + , m_scaledFont(0) + { } + + FontPlatformData() + : m_pattern(0) + , m_scaledFont(0) + { } + + FontPlatformData(const FontDescription&, const AtomicString& family); + + FontPlatformData(float size, bool bold, bool italic); + FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic); + + ~FontPlatformData(); + + static bool init(); + + bool isFixedPitch(); + float size() const { return m_fontDescription.specifiedSize(); } + + void setFont(cairo_t*) const; + + unsigned hash() const + { + uintptr_t hashCodes[1] = { reinterpret_cast<uintptr_t>(m_scaledFont) }; + return StringImpl::computeHash( reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + } + + bool operator==(const FontPlatformData&) const; + + FcPattern* m_pattern; + FontDescription m_fontDescription; + cairo_scaled_font_t* m_scaledFont; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp new file mode 100644 index 0000000..b28146f --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Holger Hans Peter Freyther + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "FontPlatformData.h" + +#include "CString.h" +#include "PlatformString.h" +#include "FontDescription.h" + +#include <cairo-ft.h> +#include <cairo.h> +#include <fontconfig/fcfreetype.h> +#include <gtk/gtk.h> + +namespace WebCore { + +FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) + : m_pattern(0) + , m_fontDescription(fontDescription) + , m_scaledFont(0) +{ + FontPlatformData::init(); + + CString familyNameString = familyName.string().utf8(); + const char* fcfamily = familyNameString.data(); + int fcslant = FC_SLANT_ROMAN; + int fcweight = FC_WEIGHT_NORMAL; + float fcsize = fontDescription.computedSize(); + if (fontDescription.italic()) + fcslant = FC_SLANT_ITALIC; + if (fontDescription.bold()) + fcweight = FC_WEIGHT_BOLD; + + int type = fontDescription.genericFamily(); + + FcPattern* pattern = FcPatternCreate(); + cairo_font_face_t* fontFace; + static const cairo_font_options_t* defaultOptions = cairo_font_options_create(); + const cairo_font_options_t* options = NULL; + cairo_matrix_t fontMatrix; + + if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) + goto freePattern; + + switch (type) { + case FontDescription::SerifFamily: + fcfamily = "serif"; + break; + case FontDescription::SansSerifFamily: + fcfamily = "sans-serif"; + break; + case FontDescription::MonospaceFamily: + fcfamily = "monospace"; + break; + case FontDescription::NoFamily: + case FontDescription::StandardFamily: + default: + fcfamily = "sans-serif"; + } + + if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) + goto freePattern; + if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant)) + goto freePattern; + if (!FcPatternAddInteger(pattern, FC_WEIGHT, fcweight)) + goto freePattern; + if (!FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fcsize)) + goto freePattern; + + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult fcresult; + m_pattern = FcFontMatch(NULL, pattern, &fcresult); + // FIXME: should we set some default font? + if (!m_pattern) + goto freePattern; + fontFace = cairo_ft_font_face_create_for_pattern(m_pattern); + cairo_matrix_t ctm; + cairo_matrix_init_scale(&fontMatrix, m_fontDescription.computedSize(), m_fontDescription.computedSize()); + cairo_matrix_init_identity(&ctm); + +#if GTK_CHECK_VERSION(2,10,0) + if (GdkScreen* screen = gdk_screen_get_default()) + options = gdk_screen_get_font_options(screen); +#endif + // gdk_screen_get_font_options() returns NULL if no default options are + // set, so we always have to check. + if (!options) + options = defaultOptions; + + m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options); + cairo_font_face_destroy(fontFace); + +freePattern: + FcPatternDestroy(pattern); +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool italic) + : m_pattern(0) + , m_fontDescription() + , 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_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(); + + // 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; + if (!FcInit()) { + fprintf(stderr, "Can't init font config library\n"); + return false; + } + initialized = true; + return true; +} + +FontPlatformData::~FontPlatformData() +{ +} + +bool FontPlatformData::isFixedPitch() +{ + // TODO: Support isFixedPitch() for custom fonts. + if (!m_pattern) + return false; + + int spacing; + if (FcPatternGetInteger(m_pattern, FC_SPACING, 0, &spacing) == FcResultMatch) + return spacing == FC_MONO; + return false; +} + +void FontPlatformData::setFont(cairo_t* cr) const +{ + ASSERT(m_scaledFont); + + cairo_set_scaled_font(cr, m_scaledFont); +} + +bool FontPlatformData::operator==(const FontPlatformData& other) const +{ + if (m_pattern == other.m_pattern) + return true; + if (m_pattern == 0 || m_pattern == reinterpret_cast<FcPattern*>(-1) + || other.m_pattern == 0 || other.m_pattern == reinterpret_cast<FcPattern*>(-1)) + return false; + return FcPatternEqual(m_pattern, other.m_pattern); +} + +} diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp new file mode 100644 index 0000000..24ad864 --- /dev/null +++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphPageTreeNode.h" + +#include "SimpleFontData.h" + +namespace WebCore { + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters. + // We won't support this for now. + if (bufferLength > GlyphPage::size) + return false; + + FT_Face face = cairo_ft_scaled_font_lock_face(fontData->m_font.m_scaledFont); + if (!face) + return false; + + bool haveGlyphs = false; + for (unsigned i = 0; i < length; i++) { + Glyph glyph = FcFreeTypeCharIndex(face, buffer[i]); + if (!glyph) + setGlyphDataForIndex(offset + i, 0, 0); + else { + setGlyphDataForIndex(offset + i, glyph, fontData); + haveGlyphs = true; + } + } + + cairo_ft_scaled_font_unlock_face(fontData->m_font.m_scaledFont); + + return haveGlyphs; +} + +} diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp new file mode 100644 index 0000000..a8e6536 --- /dev/null +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Holger Hans Peter Freyther + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Icon.h" + +#include "CString.h" +#include "GraphicsContext.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "PassRefPtr.h" + +#include <gtk/gtk.h> + +namespace WebCore { + +Icon::Icon() + : RefCounted<Icon>(0) + , m_icon(0) +{ + notImplemented(); +} + +Icon::~Icon() +{ + if(m_icon) + g_object_unref(m_icon); +} + +static String lookupIconName(String MIMEType) +{ + /* + Lookup an appropriate icon according to either the Icon Naming Spec + or conventional Gnome icon names respectively. + + See http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html + + The icon theme is probed for the following names: + 1. media-subtype + 2. gnome-mime-media-subtype + 3. media-x-generic + 4. gnome-mime-media + + In the worst case it falls back to the stock file icon. + */ + int pos = MIMEType.find('/'); + if(pos >= 0) { + String media = MIMEType.substring(0, pos); + String subtype = MIMEType.substring(pos + 1); + GtkIconTheme* iconTheme = gtk_icon_theme_get_default(); + String iconName = media + "-" + subtype; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + iconName = "gnome-mime-" + media + "-" + subtype; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + iconName = media + "-x-generic"; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + iconName = media + "gnome-mime-" + media; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + } + return GTK_STOCK_FILE; +} + +PassRefPtr<Icon> Icon::newIconForFile(const String& filename) +{ + if (!g_path_skip_root(filename.utf8().data())) + return 0; + + String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename); + String iconName = lookupIconName(MIMEType); + + Icon* icon = 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; +} + +void Icon::paint(GraphicsContext* context, const IntRect& rect) +{ + // TODO: Scale/clip the image if necessary. + cairo_t* cr = context->platformContext(); + cairo_save(cr); + gdk_cairo_set_source_pixbuf(cr, m_icon, rect.x(), rect.y()); + cairo_paint(cr); + cairo_restore(cr); +} + +} diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp new file mode 100644 index 0000000..a74bc54 --- /dev/null +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "BitmapImage.h" +#include "Image.h" +#include "NotImplemented.h" + +// This function loads resources from WebKit +Vector<char> loadResourceIntoArray(const char*); + +namespace WebCore { + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +Image* Image::loadPlatformResource(const char *name) +{ + Vector<char> arr = loadResourceIntoArray(name); + BitmapImage* img = new BitmapImage; + RefPtr<SharedBuffer> buffer = new SharedBuffer(arr.data(), arr.size()); + img->setData(buffer, true); + return img; +} +} diff --git a/WebCore/platform/graphics/gtk/IntPointGtk.cpp b/WebCore/platform/graphics/gtk/IntPointGtk.cpp new file mode 100644 index 0000000..c402158 --- /dev/null +++ b/WebCore/platform/graphics/gtk/IntPointGtk.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "IntPoint.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +IntPoint::IntPoint(const GdkPoint& p) + : m_x(p.x) + , m_y(p.y) +{ +} + +IntPoint::operator GdkPoint() const +{ + GdkPoint p = { x(), y() }; + return p; +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/gtk/IntRectGtk.cpp b/WebCore/platform/graphics/gtk/IntRectGtk.cpp new file mode 100644 index 0000000..aaa1944 --- /dev/null +++ b/WebCore/platform/graphics/gtk/IntRectGtk.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "IntRect.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +IntRect::IntRect(const GdkRectangle& r) + : m_location(IntPoint(r.x, r.y)) + , m_size(r.width, r.height) +{ +} + +IntRect::operator GdkRectangle() const +{ + GdkRectangle r = { x(), y(), width(), height() }; + return r; +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp new file mode 100644 index 0000000..c60bc20 --- /dev/null +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -0,0 +1,625 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Collabora Ltd. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(VIDEO) + +#include "MediaPlayerPrivateGStreamer.h" +#include "VideoSinkGStreamer.h" + +#include "CString.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "KURL.h" +#include "MIMETypeRegistry.h" +#include "MediaPlayer.h" +#include "NotImplemented.h" +#include "ScrollView.h" +#include "Widget.h" + +#include <gdk/gdkx.h> +#include <gst/base/gstbasesrc.h> +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> +#include <gst/interfaces/xoverlay.h> +#include <gst/video/video.h> +#include <libgnomevfs/gnome-vfs.h> +#include <limits> +#include <math.h> + +using namespace std; + +namespace WebCore { + +gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) + { + GError* err; + gchar* debug; + + gst_message_parse_error(message, &err, &debug); + if (err->code == 3) { + LOG_VERBOSE(Media, "File not found"); + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + if (mp) + mp->loadingFailed(); + } else { + LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); + g_error_free(err); + g_free(debug); + } + } + return true; +} + +gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) + { + LOG_VERBOSE(Media, "End of Stream"); + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + mp->didEnd(); + } + return true; +} + +gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) + { + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + mp->updateStates(); + } + return true; +} + +gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING) + { + gint percent = 0; + gst_message_parse_buffering(message, &percent); + LOG_VERBOSE(Media, "Buffering %d", percent); + } + return true; +} + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player) + , m_playBin(0) + , m_videoSink(0) + , m_source(0) + , m_rate(1.0f) + , m_endTime(numeric_limits<float>::infinity()) + , m_isEndReached(false) + , m_volume(0.5f) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::DataUnavailable) + , m_startedPlaying(false) + , m_isStreaming(false) + , m_rect(IntRect()) + , m_visible(true) +{ + + static bool gstInitialized = false; + // FIXME: We should pass the arguments from the command line + if (!gstInitialized) { + gst_init(0, NULL); + gstInitialized = true; + } + + // FIXME: The size shouldn't be fixed here, this is just a quick hack. + m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480); +} + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + if (m_surface) + cairo_surface_destroy(m_surface); + + if (m_playBin) { + gst_element_set_state(m_playBin, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(m_playBin)); + } +} + +void MediaPlayerPrivate::load(String url) +{ + LOG_VERBOSE(Media, "Load %s", url.utf8().data()); + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::DataUnavailable) { + m_readyState = MediaPlayer::DataUnavailable; + m_player->readyStateChanged(); + } + + createGSTPlayBin(url); + pause(); +} + +void MediaPlayerPrivate::play() +{ + LOG_VERBOSE(Media, "Play"); + // When end reached, rewind for Test video-seek-past-end-playing + if (m_isEndReached) + seek(0); + m_isEndReached = false; + + gst_element_set_state(m_playBin, GST_STATE_PLAYING); + m_startedPlaying = true; +} + +void MediaPlayerPrivate::pause() +{ + LOG_VERBOSE(Media, "Pause"); + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + m_startedPlaying = false; +} + +float MediaPlayerPrivate::duration() +{ + if (!m_playBin) + return 0.0; + + GstFormat fmt = GST_FORMAT_TIME; + gint64 len = 0; + + if (gst_element_query_duration(m_playBin, &fmt, &len)) + LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len)); + else + LOG_VERBOSE(Media, "Duration query failed "); + + if ((GstClockTime)len == GST_CLOCK_TIME_NONE) { + m_isStreaming = true; + return numeric_limits<float>::infinity(); + } + return (float) (len / 1000000000.0); + // FIXME: handle 3.14.9.5 properly +} + +float MediaPlayerPrivate::currentTime() const +{ + if (!m_playBin) + return 0; + // Necessary as sometimes, gstreamer return 0:00 at the EOS + if (m_isEndReached) + return m_endTime; + + float ret; + + GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); + if (gst_element_query(m_playBin, query)) { + gint64 position; + gst_query_parse_position(query, NULL, &position); + ret = (float) (position / 1000000000.0); + LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + } else { + LOG_VERBOSE(Media, "Position query failed..."); + ret = 0.0; + } + gst_query_unref(query); + + return ret; +} + +void MediaPlayerPrivate::seek(float time) +{ + GstClockTime sec = (GstClockTime)(time * GST_SECOND); + + if (!m_playBin) + return; + + if (m_isStreaming) + return; + + LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec)); + // FIXME: What happens when the seeked position is not available? + if (!gst_element_seek( m_playBin, m_rate, + GST_FORMAT_TIME, + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), + GST_SEEK_TYPE_SET, sec, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) + LOG_VERBOSE(Media, "Seek to %f failed", time); +} + +void MediaPlayerPrivate::setEndTime(float time) +{ + if (!m_playBin) + return; + if (m_isStreaming) + return; + if (m_endTime != time) { + m_endTime = time; + GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND); + GstClockTime end = (GstClockTime)(time * GST_SECOND); + LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end)); + // FIXME: What happens when the seeked position is not available? + if (!gst_element_seek(m_playBin, m_rate, + GST_FORMAT_TIME, + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_SET, end )) + LOG_VERBOSE(Media, "Seek to %f failed", time); + } +} + +void MediaPlayerPrivate::startEndPointTimerIfNeeded() +{ + notImplemented(); +} + +void MediaPlayerPrivate::cancelSeek() +{ + notImplemented(); +} + +void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) +{ + notImplemented(); +} + +bool MediaPlayerPrivate::paused() const +{ + return !m_startedPlaying; +} + +bool MediaPlayerPrivate::seeking() const +{ + return false; +} + +// Returns the size of the video +IntSize MediaPlayerPrivate::naturalSize() +{ + if (!hasVideo()) + return IntSize(); + + int x = 0, y = 0; + if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) { + gst_video_get_size(GST_PAD(pad), &x, &y); + gst_object_unref(GST_OBJECT(pad)); + } + + return IntSize(x, y); +} + +bool MediaPlayerPrivate::hasVideo() +{ + gint currentVideo = -1; + if (m_playBin) + g_object_get(G_OBJECT(m_playBin), "current-video", ¤tVideo, NULL); + return currentVideo > -1; +} + +void MediaPlayerPrivate::setVolume(float volume) +{ + m_volume = volume; + LOG_VERBOSE(Media, "Volume to %f", volume); + setMuted(false); +} + +void MediaPlayerPrivate::setMuted(bool b) +{ + if (!m_playBin) + return; + + if (b) { + g_object_get(G_OBJECT(m_playBin), "volume", &m_volume, NULL); + g_object_set(G_OBJECT(m_playBin), "volume", (double)0.0, NULL); + } else { + g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL); + } +} + +void MediaPlayerPrivate::setRate(float rate) +{ + if (rate == 0.0) { + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + return; + } + if (m_isStreaming) + return; + + m_rate = rate; + LOG_VERBOSE(Media, "Set Rate to %f", rate); + if (!gst_element_seek(m_playBin, rate, + GST_FORMAT_TIME, + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, (GstClockTime) (currentTime() * GST_SECOND), + GST_SEEK_TYPE_SET, (GstClockTime) (m_endTime * GST_SECOND))) + LOG_VERBOSE(Media, "Set Rate to %f failed", rate); +} + +int MediaPlayerPrivate::dataRate() const +{ + notImplemented(); + return 1; +} + +MediaPlayer::NetworkState MediaPlayerPrivate::networkState() +{ + return m_networkState; +} + +MediaPlayer::ReadyState MediaPlayerPrivate::readyState() +{ + return m_readyState; +} + +float MediaPlayerPrivate::maxTimeBuffered() +{ + notImplemented(); + LOG_VERBOSE(Media, "maxTimeBuffered"); + // rtsp streams are not buffered + return m_isStreaming ? 0 : maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeSeekable() +{ + // TODO + LOG_VERBOSE(Media, "maxTimeSeekable"); + if (m_isStreaming) + return numeric_limits<float>::infinity(); + // infinite duration means live stream + return maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeLoaded() +{ + // TODO + LOG_VERBOSE(Media, "maxTimeLoaded"); + notImplemented(); + return duration(); +} + +unsigned MediaPlayerPrivate::bytesLoaded() +{ + notImplemented(); + LOG_VERBOSE(Media, "bytesLoaded"); + /*if (!m_playBin) + return 0; + float dur = duration(); + float maxTime = maxTimeLoaded(); + if (!dur) + return 0;*/ + return 1;//totalBytes() * maxTime / dur; +} + +bool MediaPlayerPrivate::totalBytesKnown() +{ + notImplemented(); + LOG_VERBOSE(Media, "totalBytesKnown"); + return totalBytes() > 0; +} + +unsigned MediaPlayerPrivate::totalBytes() +{ + notImplemented(); + LOG_VERBOSE(Media, "totalBytes"); + if (!m_playBin) + return 0; + + if (!m_source) + return 0; + + // Do something with m_source to get the total bytes of the media + + return 100; +} + +void MediaPlayerPrivate::cancelLoad() +{ + notImplemented(); +} + +void MediaPlayerPrivate::updateStates() +{ + // There is no (known) way to get such level of information about + // the state of GStreamer, therefore, when in PAUSED state, + // we are sure we can display the first frame and go to play + + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + GstState state; + GstState pending; + + if (!m_playBin) + return; + + GstStateChangeReturn ret = gst_element_get_state (m_playBin, + &state, &pending, 250 * GST_NSECOND); + + switch(ret) { + case GST_STATE_CHANGE_SUCCESS: + LOG_VERBOSE(Media, "State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + + if (state == GST_STATE_READY) { + m_readyState = MediaPlayer::CanPlayThrough; + } else if (state == GST_STATE_PAUSED) { + m_readyState = MediaPlayer::CanPlayThrough; + } + if (m_networkState < MediaPlayer::Loaded) + m_networkState = MediaPlayer::Loaded; + + g_object_get(m_playBin, "source", &m_source, NULL); + if (!m_source) + LOG_VERBOSE(Media, "m_source is NULL"); + break; + case GST_STATE_CHANGE_ASYNC: + LOG_VERBOSE(Media, "Async: State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + // Change in progress + return; + break; + case GST_STATE_CHANGE_NO_PREROLL: + LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + if (state == GST_STATE_READY) { + m_readyState = MediaPlayer::CanPlay; + } else if (state == GST_STATE_PAUSED) { + m_readyState = MediaPlayer::CanPlay; + } + if (m_networkState < MediaPlayer::LoadedMetaData) + m_networkState = MediaPlayer::LoadedMetaData; + break; + default: + LOG_VERBOSE(Media, "Else : %d", ret); + break; + } + + if (seeking()) + m_readyState = MediaPlayer::DataUnavailable; + + if (m_networkState != oldNetworkState) { + LOG_VERBOSE(Media, "Network State Changed from %u to %u", + oldNetworkState, m_networkState); + m_player->networkStateChanged(); + } + if (m_readyState != oldReadyState) { + LOG_VERBOSE(Media, "Ready State Changed from %u to %u", + oldReadyState, m_readyState); + m_player->readyStateChanged(); + } +} + +void MediaPlayerPrivate::loadStateChanged() +{ + updateStates(); +} + +void MediaPlayerPrivate::rateChanged() +{ + updateStates(); +} + +void MediaPlayerPrivate::sizeChanged() +{ + notImplemented(); +} + +void MediaPlayerPrivate::timeChanged() +{ + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivate::volumeChanged() +{ + m_player->volumeChanged(); +} + +void MediaPlayerPrivate::didEnd() +{ + m_isEndReached = true; + pause(); + timeChanged(); +} + +void MediaPlayerPrivate::loadingFailed() +{ + if (m_networkState != MediaPlayer::LoadFailed) { + m_networkState = MediaPlayer::LoadFailed; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::DataUnavailable) { + m_readyState = MediaPlayer::DataUnavailable; + m_player->readyStateChanged(); + } +} + +void MediaPlayerPrivate::setRect(const IntRect& rect) +{ + m_rect = rect; +} + +void MediaPlayerPrivate::setVisible(bool visible) +{ + m_visible = visible; +} + +void MediaPlayerPrivate::repaint() +{ + m_player->repaint(); +} + +void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + if (!m_visible) + return; + + //TODO: m_rect vs rect? + cairo_t* cr = context->platformContext(); + + cairo_save(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_translate(cr, rect.x(), rect.y()); + cairo_rectangle(cr, 0, 0, rect.width(), rect.height()); + cairo_set_source_surface(cr, m_surface, 0, 0); + cairo_fill(cr); + cairo_restore(cr); +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +{ + // FIXME: do the real thing + notImplemented(); + types.add(String("video/x-theora+ogg")); +} + +void MediaPlayerPrivate::createGSTPlayBin(String url) +{ + ASSERT(!m_playBin); + m_playBin = gst_element_factory_make("playbin", "play"); + + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin)); + gst_bus_add_signal_watch(bus); + g_signal_connect(bus, "message::error", G_CALLBACK(mediaPlayerPrivateErrorCallback), this); + g_signal_connect(bus, "message::eos", G_CALLBACK(mediaPlayerPrivateEOSCallback), this); + g_signal_connect(bus, "message::state-changed", G_CALLBACK(mediaPlayerPrivateStateCallback), this); + g_signal_connect(bus, "message::buffering", G_CALLBACK(mediaPlayerPrivateBufferingCallback), this); + gst_object_unref(bus); + + g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL); + + GstElement* audioSink = gst_element_factory_make("gconfaudiosink", NULL); + m_videoSink = webkit_video_sink_new(m_surface); + + g_object_set(m_playBin, "audio-sink", audioSink, NULL); + g_object_set(m_playBin, "video-sink", m_videoSink, NULL); + + setVolume(m_volume); +} + +} + +#endif + diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h new file mode 100644 index 0000000..3f08bc0 --- /dev/null +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Collabora Ltd. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef MediaPlayerPrivateGStreamer_h +#define MediaPlayerPrivateGStreamer_h + +#if ENABLE(VIDEO) + +#include "MediaPlayer.h" +#include "Timer.h" + +#include <gtk/gtk.h> + +typedef struct _GstElement GstElement; +typedef struct _GstMessage GstMessage; +typedef struct _GstBus GstBus; + +namespace WebCore { + + class GraphicsContext; + class IntSize; + class IntRect; + class String; + + gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); + gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); + gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + + class MediaPlayerPrivate : Noncopyable + { + friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); + friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); + friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + + public: + MediaPlayerPrivate(MediaPlayer*); + ~MediaPlayerPrivate(); + + IntSize naturalSize(); + bool hasVideo(); + + void load(String url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration(); + float currentTime() const; + void seek(float); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + void setMuted(bool); + + int dataRate() const; + + MediaPlayer::NetworkState networkState(); + MediaPlayer::ReadyState readyState(); + + float maxTimeBuffered(); + float maxTimeSeekable(); + unsigned bytesLoaded(); + bool totalBytesKnown(); + unsigned totalBytes(); + + void setVisible(bool); + void setRect(const IntRect&); + + void loadStateChanged(); + void rateChanged(); + void sizeChanged(); + void timeChanged(); + void volumeChanged(); + void didEnd(); + void loadingFailed(); + + void repaint(); + void paint(GraphicsContext*, const IntRect&); + static void getSupportedTypes(HashSet<String>&); + static bool isAvailable() { return true; } + + private: + + void updateStates(); + void cancelSeek(); + void endPointTimerFired(Timer<MediaPlayerPrivate>*); + float maxTimeLoaded(); + void startEndPointTimerIfNeeded(); + + void createGSTPlayBin(String url); + + private: + MediaPlayer* m_player; + GstElement* m_playBin; + GstElement* m_videoSink; + GstElement* m_source; + float m_rate; + float m_endTime; + bool m_isEndReached; + double m_volume; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + bool m_startedPlaying; + bool m_isStreaming; + IntRect m_rect; + bool m_visible; + cairo_surface_t* m_surface; + }; +} + +#endif +#endif diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp new file mode 100644 index 0000000..a754c45 --- /dev/null +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Holger Hans Peter Freyther + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include "FloatRect.h" +#include "Font.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "GlyphBuffer.h" +#include <cairo.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +void SimpleFontData::platformInit() +{ + cairo_font_extents_t font_extents; + cairo_text_extents_t text_extents; + cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents); + m_ascent = static_cast<int>(font_extents.ascent); + m_descent = static_cast<int>(font_extents.descent); + m_lineSpacing = static_cast<int>(font_extents.height); + cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents); + m_xHeight = text_extents.height; + cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents); + m_spaceWidth = static_cast<int>(text_extents.x_advance); + m_lineGap = m_lineSpacing - m_ascent - m_descent; +} + +void SimpleFontData::platformDestroy() +{ + if (!isCustomFont()) { + if (m_font.m_pattern && ((FcPattern*)-1 != m_font.m_pattern)) { + FcPatternDestroy(m_font.m_pattern); + m_font.m_pattern = 0; + } + + if (m_font.m_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 +{ + FT_Face face = cairo_ft_scaled_font_lock_face(m_font.m_scaledFont); + + if (!face) + return false; + + for (unsigned i = 0; i < length; i++) { + if (FcFreeTypeCharIndex(face, characters[i]) == 0) { + cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + return false; + } + } + + cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + + return true; +} + +void SimpleFontData::determinePitch() +{ + m_treatAsFixedPitch = m_font.isFixedPitch(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + ASSERT(m_font.m_scaledFont); + + cairo_glyph_t cglyph = { glyph, 0, 0 }; + cairo_text_extents_t extents; + cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents); + + float w = (float)m_spaceWidth; + if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) + w = (float)extents.x_advance; + return w; +} + +void SimpleFontData::setFont(cairo_t* cr) const +{ + ASSERT(cr); + m_font.setFont(cr); +} + +} diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp new file mode 100644 index 0000000..7e97688 --- /dev/null +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2007 OpenedHand + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:webkit-video-sink + * @short_description: GStreamer video sink + * + * #WebKitVideoSink is a GStreamer sink element that sends + * data to a #cairo_surface_t. + */ + +#include "config.h" +#include "VideoSinkGStreamer.h" + +#include <glib.h> +#include <gst/gst.h> +#include <gst/video/video.h> + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink", + GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS(GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx)); + +GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug); +#define GST_CAT_DEFAULT webkit_video_sink_debug + +static GstElementDetails webkit_video_sink_details = + GST_ELEMENT_DETAILS("WebKit video sink", + "Sink/Video", + "Sends video data from a GStreamer pipeline to a Cairo surface", + "Alp Toker <alp@atoker.com>"); + +enum { + PROP_0, + PROP_SURFACE +}; + +struct _WebKitVideoSinkPrivate { + cairo_surface_t* surface; + GAsyncQueue* async_queue; + gboolean rgb_ordering; + int width; + int height; + int fps_n; + int fps_d; + int par_n; + int par_d; +}; + +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT (webkit_video_sink_debug, \ + "webkitsink", \ + 0, \ + "webkit video sink") + +GST_BOILERPLATE_FULL(WebKitVideoSink, + webkit_video_sink, + GstBaseSink, + GST_TYPE_BASE_SINK, + _do_init); + +static void +webkit_video_sink_base_init(gpointer g_class) +{ + GstElementClass* element_class = GST_ELEMENT_CLASS(g_class); + + gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate)); + gst_element_class_set_details(element_class, &webkit_video_sink_details); +} + +static void +webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass) +{ + WebKitVideoSinkPrivate* priv; + + sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); + priv->async_queue = g_async_queue_new(); +} + +static gboolean +webkit_video_sink_idle_func(gpointer data) +{ + WebKitVideoSinkPrivate* priv; + GstBuffer* buffer; + + priv = (WebKitVideoSinkPrivate*)data; + + if (!priv->async_queue) + return FALSE; + + buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue); + if (buffer == NULL || G_UNLIKELY(!GST_IS_BUFFER(buffer))) + return FALSE; + + // TODO: consider priv->rgb_ordering? + cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~ 3); + + // TODO: We copy the data twice right now. This could be easily improved. + cairo_t* cr = cairo_create(priv->surface); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(cr, src, 0, 0); + cairo_surface_destroy(src); + cairo_rectangle(cr, 0, 0, priv->width, priv->height); + cairo_fill(cr); + cairo_destroy(cr); + + gst_buffer_unref(buffer); + + return FALSE; +} + +static GstFlowReturn +webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); + WebKitVideoSinkPrivate* priv = sink->priv; + + g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer)); + g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, priv, NULL); + + return GST_FLOW_OK; +} + +static gboolean +webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); + WebKitVideoSinkPrivate* priv = sink->priv; + GstStructure* structure; + gboolean ret; + const GValue* fps; + const GValue* par; + gint width, height; + int red_mask; + + GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps); + + if (gst_caps_is_empty(intersection)) + return FALSE; + + gst_caps_unref(intersection); + + structure = gst_caps_get_structure(caps, 0); + + ret = gst_structure_get_int(structure, "width", &width); + ret &= gst_structure_get_int(structure, "height", &height); + fps = gst_structure_get_value(structure, "framerate"); + ret &= (fps != NULL); + + par = gst_structure_get_value(structure, "pixel-aspect-ratio"); + + if (!ret) + return FALSE; + + priv->width = width; + priv->height = height; + + /* We dont yet use fps or pixel aspect into but handy to have */ + priv->fps_n = gst_value_get_fraction_numerator(fps); + priv->fps_d = gst_value_get_fraction_denominator(fps); + + if (par) { + priv->par_n = gst_value_get_fraction_numerator(par); + priv->par_d = gst_value_get_fraction_denominator(par); + } else + priv->par_n = priv->par_d = 1; + + gst_structure_get_int(structure, "red_mask", &red_mask); + priv->rgb_ordering = (red_mask == 0xff000000); + + return TRUE; +} + +static void +webkit_video_sink_dispose(GObject* object) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + WebKitVideoSinkPrivate* priv = sink->priv; + + if (priv->surface) { + cairo_surface_destroy(priv->surface); + priv->surface = NULL; + } + + if (priv->async_queue) { + g_async_queue_unref(priv->async_queue); + priv->async_queue = NULL; + } + + G_OBJECT_CLASS(parent_class)->dispose(object); +} + +static void +webkit_video_sink_finalize(GObject* object) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + + G_OBJECT_CLASS(parent_class)->finalize(object); +} + +static void +webkit_video_sink_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + WebKitVideoSinkPrivate* priv = sink->priv; + + switch (prop_id) { + case PROP_SURFACE: + if (priv->surface) + cairo_surface_destroy(priv->surface); + priv->surface = cairo_surface_reference((cairo_surface_t*)g_value_get_pointer(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +webkit_video_sink_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + + switch (prop_id) { + case PROP_SURFACE: + g_value_set_pointer(value, sink->priv->surface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static gboolean +webkit_video_sink_stop(GstBaseSink* base_sink) +{ + WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv; + + g_async_queue_lock(priv->async_queue); + + /* Remove all remaining objects from the queue */ + while(GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue)) + gst_buffer_unref(buffer); + + g_async_queue_unlock(priv->async_queue); + + return TRUE; +} + +static void +webkit_video_sink_class_init(WebKitVideoSinkClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + GstBaseSinkClass* gstbase_sink_class = GST_BASE_SINK_CLASS(klass); + + g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate)); + + gobject_class->set_property = webkit_video_sink_set_property; + gobject_class->get_property = webkit_video_sink_get_property; + + gobject_class->dispose = webkit_video_sink_dispose; + gobject_class->finalize = webkit_video_sink_finalize; + + gstbase_sink_class->render = webkit_video_sink_render; + gstbase_sink_class->preroll = webkit_video_sink_render; + gstbase_sink_class->stop = webkit_video_sink_stop; + gstbase_sink_class->set_caps = webkit_video_sink_set_caps; + + g_object_class_install_property( + gobject_class, PROP_SURFACE, + g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*", + (GParamFlags)(G_PARAM_READWRITE))); +} + +/** + * webkit_video_sink_new: + * @surface: a #cairo_surface_t + * + * Creates a new GStreamer video sink which uses @surface as the target + * for sinking a video stream from GStreamer. + * + * Return value: a #GstElement for the newly created video sink + */ +GstElement* +webkit_video_sink_new(cairo_surface_t* surface) +{ + return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, NULL); +} + +void +webkit_video_sink_set_surface(WebKitVideoSink* sink, cairo_surface_t* surface) +{ + WebKitVideoSinkPrivate* priv; + + sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); + if (priv->surface) + cairo_surface_destroy(priv->surface); + priv->surface = cairo_surface_reference(surface); +} diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h new file mode 100644 index 0000000..2a706fb --- /dev/null +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 OpenedHand + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _HAVE_WEBKIT_VIDEO_SINK_H +#define _HAVE_WEBKIT_VIDEO_SINK_H + +#include <cairo.h> +#include <glib-object.h> +#include <gst/base/gstbasesink.h> + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_VIDEO_SINK webkit_video_sink_get_type() + +#define WEBKIT_VIDEO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSink)) + +#define WEBKIT_VIDEO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass)) + +#define WEBKIT_IS_VIDEO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + WEBKIT_TYPE_VIDEO_SINK)) + +#define WEBKIT_IS_VIDEO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + WEBKIT_TYPE_VIDEO_SINK)) + +#define WEBKIT_VIDEO_SINK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass)) + +typedef struct _WebKitVideoSink WebKitVideoSink; +typedef struct _WebKitVideoSinkClass WebKitVideoSinkClass; +typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate; + +struct _WebKitVideoSink +{ + /*< private >*/ + GstBaseSink parent; + WebKitVideoSinkPrivate *priv; +}; + +struct _WebKitVideoSinkClass +{ + /*< private >*/ + GstBaseSinkClass parent_class; + + /* Future padding */ + void (* _webkit_reserved1) (void); + void (* _webkit_reserved2) (void); + void (* _webkit_reserved3) (void); + void (* _webkit_reserved4) (void); + void (* _webkit_reserved5) (void); + void (* _webkit_reserved6) (void); +}; + +GType webkit_video_sink_get_type (void) G_GNUC_CONST; +GstElement *webkit_video_sink_new (cairo_surface_t *surface); + +void webkit_video_sink_set_surface (WebKitVideoSink *sink, cairo_surface_t *surface); + +G_END_DECLS + +#endif diff --git a/WebCore/platform/graphics/mac/ColorMac.h b/WebCore/platform/graphics/mac/ColorMac.h new file mode 100644 index 0000000..3be9094 --- /dev/null +++ b/WebCore/platform/graphics/mac/ColorMac.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ColorMac_h +#define ColorMac_h + +#include "Color.h" + +#ifdef __OBJC__ +@class NSColor; +#else +class NSColor; +#endif + +namespace WebCore { + + Color colorFromNSColor(NSColor *); + NSColor* nsColor(const Color&); + + bool usesTestModeFocusRingColor(); + void setUsesTestModeFocusRingColor(bool); + +} + +#endif diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm new file mode 100644 index 0000000..5c89715 --- /dev/null +++ b/WebCore/platform/graphics/mac/ColorMac.mm @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "Color.h" +#import "ColorMac.h" + +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> + +@interface WebCoreControlTintObserver : NSObject ++ (void)controlTintDidChange; +@end + +namespace WebCore { + +// NSColor calls don't throw, so no need to block Cocoa exceptions in this file + +static RGBA32 oldAquaFocusRingColor = 0xFF7DADD9; +static bool tintIsKnown; +static void (*tintChangeFunction)(); +static RGBA32 systemFocusRingColor; +static bool useOldAquaFocusRingColor; + + +static RGBA32 makeRGBAFromNSColor(NSColor *c) +{ + return makeRGBA((int)(255 * [c redComponent]), (int)(255 * [c greenComponent]), (int)(255 * [c blueComponent]), (int)(255 * [c alphaComponent])); +} + +Color colorFromNSColor(NSColor *c) +{ + return Color(makeRGBAFromNSColor(c)); +} + +NSColor* nsColor(const Color& color) +{ + unsigned c = color.rgb(); + switch (c) { + case 0: { + // Need this to avoid returning nil because cachedRGBAValues will default to 0. + static RetainPtr<NSColor> clearColor = [NSColor clearColor]; + return clearColor.get(); + } + case Color::black: { + static RetainPtr<NSColor> blackColor = [NSColor blackColor]; + return blackColor.get(); + } + case Color::white: { + static RetainPtr<NSColor> whiteColor = [NSColor whiteColor]; + return whiteColor.get(); + } + default: { + const int cacheSize = 32; + static unsigned cachedRGBAValues[cacheSize]; + static RetainPtr<NSColor> cachedColors[cacheSize]; + + for (int i = 0; i != cacheSize; ++i) + if (cachedRGBAValues[i] == c) + return cachedColors[i].get(); + +#ifdef COLORMATCH_EVERYTHING + NSColor* result = [NSColor colorWithCalibratedRed:color.red() / 255.0f + green:color.green() / 255.0f + blue:color.blue() / 255.0f + alpha:color.alpha() /255.0f]; +#else + NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f + green:color.green() / 255.0f + blue:color.blue() / 255.0f + alpha:color.alpha() /255.0f]; +#endif + + static int cursor; + cachedRGBAValues[cursor] = c; + cachedColors[cursor] = result; + if (++cursor == cacheSize) + cursor = 0; + return result; + } + } +} + +static CGColorRef CGColorFromNSColor(NSColor* color) +{ + // This needs to always use device colorspace so it can de-calibrate the color for + // CGColor to possibly recalibrate it. + NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + CGFloat red = [deviceColor redComponent]; + CGFloat green = [deviceColor greenComponent]; + CGFloat blue = [deviceColor blueComponent]; + CGFloat alpha = [deviceColor alphaComponent]; + const CGFloat components[4] = { red, green, blue, alpha }; + static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB(); + CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components); + return cgColor; +} + +CGColorRef cgColor(const Color& c) +{ + // We could directly create a CGColor here, but that would + // skip any RGB caching the nsColor method does. A direct + // creation could be investigated for a possible performance win. + return CGColorFromNSColor(nsColor(c)); +} + +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(); + + if (usesTestModeFocusRingColor()) + return oldAquaFocusRingColor; + + return systemFocusRingColor; +} + +bool usesTestModeFocusRingColor() +{ + return useOldAquaFocusRingColor; +} + +void setUsesTestModeFocusRingColor(bool newValue) +{ + useOldAquaFocusRingColor = newValue; +} + +} + +@implementation WebCoreControlTintObserver + ++ (void)controlTintDidChange +{ +#ifdef COLORMATCH_EVERYTHING +#error Not yet implemented. +#else + NSColor* color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; + WebCore::systemFocusRingColor = WebCore::makeRGBAFromNSColor(color); +#endif +} + +@end diff --git a/WebCore/platform/graphics/mac/FloatPointMac.mm b/WebCore/platform/graphics/mac/FloatPointMac.mm new file mode 100644 index 0000000..2f73314 --- /dev/null +++ b/WebCore/platform/graphics/mac/FloatPointMac.mm @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatPoint.h" + +namespace WebCore { + +#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES + +FloatPoint::FloatPoint(const NSPoint& p) : m_x(p.x), m_y(p.y) +{ +} + +FloatPoint::operator NSPoint() const +{ + return NSMakePoint(m_x, m_y); +} + +#endif + +} diff --git a/WebCore/platform/graphics/mac/FloatRectMac.mm b/WebCore/platform/graphics/mac/FloatRectMac.mm new file mode 100644 index 0000000..1d6b045 --- /dev/null +++ b/WebCore/platform/graphics/mac/FloatRectMac.mm @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatRect.h" + +namespace WebCore { + +#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES + +FloatRect::FloatRect(const NSRect& r) : m_location(r.origin), m_size(r.size) +{ +} + +FloatRect::operator NSRect() const +{ + return NSMakeRect(x(), y(), width(), height()); +} + +#endif + +} diff --git a/WebCore/platform/graphics/mac/FloatSizeMac.mm b/WebCore/platform/graphics/mac/FloatSizeMac.mm new file mode 100644 index 0000000..01efbe9 --- /dev/null +++ b/WebCore/platform/graphics/mac/FloatSizeMac.mm @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2005 Nokia. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatSize.h" + +namespace WebCore { + +#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES + +FloatSize::FloatSize(const NSSize& s) : m_width(s.width), m_height(s.height) +{ +} + +FloatSize::operator NSSize() const +{ + return NSMakeSize(m_width, m_height); +} + +#endif + +} diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm new file mode 100644 index 0000000..ffb3068 --- /dev/null +++ b/WebCore/platform/graphics/mac/FontCacheMac.mm @@ -0,0 +1,262 @@ +/* + * 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. + */ + +#import "config.h" +#import "FontCache.h" + +#import "Font.h" +#import "SimpleFontData.h" +#import "FontPlatformData.h" +#import "WebCoreSystemInterface.h" +#import "WebFontCache.h" + +#ifdef BUILDING_ON_TIGER +typedef int NSInteger; +#endif + +namespace WebCore { + +static bool getAppDefaultValue(CFStringRef key, int *v) +{ + 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; +} + +static bool getUserDefaultValue(CFStringRef key, int *v) +{ + 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; +} + +static int getLCDScaleParameters(void) +{ + int mode; + CFStringRef key; + + key = CFSTR("AppleFontSmoothing"); + if (!getAppDefaultValue(key, &mode)) { + if (!getUserDefaultValue(key, &mode)) + return 1; + } + + if (wkFontSmoothingModeIsLCD(mode)) + return 4; + return 1; +} + +#define MINIMUM_GLYPH_CACHE_SIZE 1536 * 1024 + +void FontCache::platformInit() +{ + size_t s = MINIMUM_GLYPH_CACHE_SIZE*getLCDScaleParameters(); + + wkSetUpFontCache(s); +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + const FontPlatformData& platformData = font.fontDataAt(0)->fontDataForCharacter(characters[0])->platformData(); + NSFont *nsFont = platformData.font(); + + NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(characters) + length:length freeWhenDone:NO]; + NSFont *substituteFont = wkGetFontInLanguageForRange(nsFont, string, NSMakeRange(0, length)); + [string release]; + + if (!substituteFont && length == 1) + substituteFont = wkGetFontInLanguageForCharacter(nsFont, characters[0]); + if (!substituteFont) + return 0; + + // Use the family name from the AppKit-supplied substitute font, requesting the + // traits, weight, and size we want. One way this does better than the original + // AppKit request is that it takes synthetic bold and oblique into account. + // But it does create the possibility that we could end up with a font that + // doesn't actually cover the characters we need. + + NSFontManager *manager = [NSFontManager sharedFontManager]; + + NSFontTraitMask traits; + NSInteger weight; + CGFloat size; + + if (nsFont) { + traits = [manager traitsOfFont:nsFont]; + if (platformData.m_syntheticBold) + traits |= NSBoldFontMask; + if (platformData.m_syntheticOblique) + traits |= NSItalicFontMask; + weight = [manager weightOfFont:nsFont]; + size = [nsFont pointSize]; + } else { + // For custom fonts nsFont is nil. + traits = (font.bold() ? NSBoldFontMask : 0) | (font.italic() ? NSItalicFontMask : 0); + weight = 5; + size = font.pixelSize(); + } + + NSFont *bestVariation = [manager fontWithFamily:[substituteFont familyName] + traits:traits + weight:weight + size:size]; + if (bestVariation) + substituteFont = bestVariation; + + substituteFont = font.fontDescription().usePrinterFont() + ? [substituteFont printerFont] : [substituteFont screenFont]; + + NSFontTraitMask substituteFontTraits = [manager traitsOfFont:substituteFont]; + + FontPlatformData alternateFont(substituteFont, + !font.isPlatformFont() && (traits & NSBoldFontMask) && !(substituteFontTraits & NSBoldFontMask), + !font.isPlatformFont() && (traits & NSItalicFontMask) && !(substituteFontTraits & NSItalicFontMask)); + return getCachedFontData(&alternateFont); +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + // Attempt to find an appropriate font using a match based on + // the presence of keywords in the the requested names. For example, we'll + // match any name that contains "Arabic" to Geeza Pro. + FontPlatformData* platformData = 0; + const FontFamily* currFamily = &font.fontDescription().family(); + while (currFamily && !platformData) { + if (currFamily->family().length()) { + static String matchWords[3] = { String("Arabic"), String("Pashto"), String("Urdu") }; + static AtomicString geezaStr("Geeza Pro"); + for (int j = 0; j < 3 && !platformData; ++j) + if (currFamily->family().contains(matchWords[j], false)) + platformData = getCachedFontPlatformData(font.fontDescription(), geezaStr); + } + currFamily = currFamily->next(); + } + + return platformData; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) +{ + static AtomicString timesStr("Times"); + static AtomicString lucidaGrandeStr("Lucida Grande"); + + // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick + // the default that the user would get without changing any prefs. + FontPlatformData* platformFont = getCachedFontPlatformData(fontDescription, timesStr); + if (!platformFont) + // The Times fallback will almost always work, but in the highly unusual case where + // the user doesn't have it, we fall back on Lucida Grande because that's + // guaranteed to be there, according to Nathan Taylor. This is good enough + // to avoid a crash at least. + platformFont = getCachedFontPlatformData(fontDescription, lucidaGrandeStr); + + return platformFont; +} + +bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family) +{ + 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; +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + 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]; + if (!nsFont) + return 0; + + NSFontTraitMask actualTraits = 0; + if (fontDescription.bold() || fontDescription.italic()) + actualTraits = [[NSFontManager sharedFontManager] traitsOfFont: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); + return result; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp new file mode 100644 index 0000000..f143458 --- /dev/null +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include <ApplicationServices/ApplicationServices.h> +#include "SharedBuffer.h" +#include "FontPlatformData.h" + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ + ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault); + CGFontRelease(m_cgFont); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic) +{ + return FontPlatformData(m_cgFont, (ATSUFontID)m_atsFont, size, bold, italic); +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + // Use ATS to activate the font. + ATSFontContainerRef containerRef = 0; + + // The value "3" means that the font is private and can't be seen by anyone else. + ATSFontActivateFromMemory((void*)buffer->data(), buffer->size(), 3, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &containerRef); + if (!containerRef) + return 0; + ItemCount fontCount; + ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 0, NULL, &fontCount); + + // We just support the first font in the list. + if (fontCount == 0) { + ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); + return 0; + } + + ATSFontRef fontRef = 0; + ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, &fontRef, NULL); + if (!fontRef) { + ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); + return 0; + } + + CGFontRef cgFontRef = CGFontCreateWithPlatformFont(&fontRef); +#ifndef BUILDING_ON_TIGER + // Workaround for <rdar://problem/5675504>. + if (!CGFontGetNumberOfGlyphs(cgFontRef)) { + CFRelease(cgFontRef); + cgFontRef = 0; + } +#endif + if (!cgFontRef) { + ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); + return 0; + } + + return new FontCustomPlatformData(containerRef, fontRef, cgFontRef); +} + +} diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/WebCore/platform/graphics/mac/FontCustomPlatformData.h new file mode 100644 index 0000000..d2e83ca --- /dev/null +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include <wtf/Noncopyable.h> + +typedef struct CGFont* CGFontRef; +typedef UInt32 ATSFontContainerRef; +typedef UInt32 ATSFontRef; + +namespace WebCore { + +class FontPlatformData; +class SharedBuffer; + +struct FontCustomPlatformData : Noncopyable { + FontCustomPlatformData(ATSFontContainerRef container, ATSFontRef atsFont, CGFontRef cgFont) + : m_atsContainer(container), m_atsFont(atsFont), m_cgFont(cgFont) + {} + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic); + + ATSFontContainerRef m_atsContainer; + ATSFontRef m_atsFont; + CGFontRef m_cgFont; +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer); + +} + +#endif diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm new file mode 100644 index 0000000..06d8d9e --- /dev/null +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -0,0 +1,659 @@ +/** + * 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. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#import "config.h" +#import "Font.h" + +#import "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" + +#define SYNTHETIC_OBLIQUE_ANGLE 14 + +#ifdef __LP64__ +#define URefCon void* +#else +#define URefCon UInt32 +#endif + +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(¶ms); + + 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(¶ms); + + 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(¶ms); + + 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(¶ms); + + 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(); + + bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext); + bool newShouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); + + if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) + CGContextSetShouldSmoothFonts(cgContext, newShouldUseFontSmoothing); + + const FontPlatformData& platformData = font->platformData(); + NSFont* drawFont; + if (!isPrinterFont()) { + drawFont = [platformData.font() screenFont]; + if (drawFont != platformData.font()) + // We are getting this in too many places (3406411); use ERROR so it only prints on debug versions for now. (We should debug this also, eventually). + LOG_ERROR("Attempting to set non-screen font (%@) when drawing to screen. Using screen font anyway, may result in incorrect metrics.", + [[[platformData.font() fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]); + } else { + drawFont = [platformData.font() printerFont]; + if (drawFont != platformData.font()) + NSLog(@"Attempting to set non-printer font (%@) when printing. Using printer font anyway, may result in incorrect metrics.", + [[[platformData.font() fontDescriptor] fontAttributes] objectForKey:NSFontNameAttribute]); + } + + CGContextSetFont(cgContext, platformData.m_cgFont); + + CGAffineTransform matrix = CGAffineTransformIdentity; + if (drawFont) + memcpy(&matrix, [drawFont matrix], sizeof(matrix)); + matrix.b = -matrix.b; + matrix.d = -matrix.d; + if (platformData.m_syntheticOblique) + matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); + CGContextSetTextMatrix(cgContext, matrix); + + if (drawFont) { + wkSetCGFontRenderingMode(cgContext, drawFont); + CGContextSetFontSize(cgContext, 1.0f); + } else + CGContextSetFontSize(cgContext, platformData.m_size); + + CGContextSetTextPosition(cgContext, point.x(), point.y()); + CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + if (font->m_syntheticBoldOffset) { + CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y()); + CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + } + + if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) + CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing); +} + +} diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h new file mode 100644 index 0000000..8f118e0 --- /dev/null +++ b/WebCore/platform/graphics/mac/FontPlatformData.h @@ -0,0 +1,102 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontPlatformData_h +#define FontPlatformData_h + +#include "StringImpl.h" + +#ifdef __OBJC__ +@class NSFont; +#else +class NSFont; +#endif + +typedef struct CGFont* CGFontRef; +typedef UInt32 ATSUFontID; + +#include <CoreFoundation/CFBase.h> +#include <objc/objc-auto.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) + {} + + FontPlatformData(float s, bool b, bool o) + : m_syntheticBold(b) + , m_syntheticOblique(o) + , m_cgFont(0) + , m_atsuFontID(0) + , m_size(s) + , m_font(0) + { + } + + FontPlatformData(NSFont* f = 0, bool b = false, bool o = 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) + { + } + + FontPlatformData(const FontPlatformData& f); + + ~FontPlatformData(); + + 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; + + unsigned hash() const + { + ASSERT(m_font != 0 || m_cgFont == 0); + uintptr_t hashCodes[2] = { (uintptr_t)m_font, m_syntheticBold << 1 | m_syntheticOblique }; + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + } + + bool operator==(const FontPlatformData& other) const + { + return m_font == other.m_font && m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique && + m_cgFont == other.m_cgFont && m_size == other.m_size && m_atsuFontID == other.m_atsuFontID; + } + + NSFont *font() const { return m_font; } + void setFont(NSFont* font); + +private: + NSFont *m_font; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm new file mode 100644 index 0000000..d1e00d1 --- /dev/null +++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm @@ -0,0 +1,70 @@ +/* + * This file is part of the internal font implementation. + * + * Copyright (C) 2006-7 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#import "config.h" +#import "FontPlatformData.h" + +#import "WebCoreSystemInterface.h" + +namespace WebCore { + +FontPlatformData::FontPlatformData(NSFont* f, bool b , bool o) +: m_syntheticBold(b), m_syntheticOblique(o), m_font(f) +{ + if (f) + CFRetain(f); + m_size = f ? [f pointSize] : 0.0f; + m_cgFont = wkGetCGFontFromNSFont(f); + m_atsuFontID = wkGetNSFontATSUFontId(f); +} + +FontPlatformData::FontPlatformData(const FontPlatformData& f) +{ + m_font = (f.m_font && f.m_font != (NSFont*)-1) ? (NSFont*)CFRetain(f.m_font) : f.m_font; + m_syntheticBold = f.m_syntheticBold; + m_syntheticOblique = f.m_syntheticOblique; + m_size = f.m_size; + m_cgFont = f.m_cgFont; + m_atsuFontID = f.m_atsuFontID; +} + +FontPlatformData:: ~FontPlatformData() +{ + if (m_font && m_font != (NSFont*)-1) + CFRelease(m_font); +} + +void FontPlatformData::setFont(NSFont* font) { + if (m_font == font) + return; + if (font) + CFRetain(font); + if (m_font && m_font != (NSFont*)-1) + CFRelease(m_font); + m_font = font; + m_size = font ? [font pointSize] : 0.0f; + m_cgFont = wkGetCGFontFromNSFont(font); + m_atsuFontID = wkGetNSFontATSUFontId(font); +} + +} + diff --git a/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp b/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp new file mode 100644 index 0000000..b9f2da3 --- /dev/null +++ b/WebCore/platform/graphics/mac/GlyphPageTreeNodeMac.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphPageTreeNode.h" + +#include "SimpleFontData.h" +#include "WebCoreSystemInterface.h" +#include <ApplicationServices/ApplicationServices.h> + +namespace WebCore { + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + // Use an array of long so we get good enough alignment. + long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)]; + + OSStatus status = wkInitializeGlyphVector(GlyphPage::size, &glyphVector); + if (status != noErr) + // This should never happen, perhaps indicates a bad font! If it does the + // font substitution code will find an alternate font. + return false; + + wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector); + + unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector); + if (numGlyphs != length) { + // This should never happen, perhaps indicates a bad font? + // If it does happen, the font substitution code will find an alternate font. + wkClearGlyphVector(&glyphVector); + return false; + } + + bool haveGlyphs = false; + ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector); + for (unsigned i = 0; i < length; i++) { + Glyph glyph = glyphRecord->glyphID; + if (!glyph) + setGlyphDataForIndex(offset + i, 0, 0); + else { + setGlyphDataForIndex(offset + i, glyph, fontData); + haveGlyphs = true; + } + glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector)); + } + wkClearGlyphVector(&glyphVector); + + return haveGlyphs; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm new file mode 100644 index 0000000..3f9176c --- /dev/null +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "GraphicsContext.h" + +#import "../cg/GraphicsContextPlatformPrivateCG.h" + +#import "WebCoreSystemInterface.h" + +// FIXME: More of this should use CoreGraphics instead of AppKit. +// FIXME: More of this should move into GraphicsContextCG.cpp. + +namespace WebCore { + +// NSColor, NSBezierPath, and NSGraphicsContext +// calls in this file are all exception-safe, so we don't block +// exceptions for those. + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + int radius = (focusRingWidth() - 1) / 2; + int offset = radius + focusRingOffset(); + CGColorRef colorRef = color.isValid() ? cgColor(color) : 0; + + CGMutablePathRef focusRingPath = CGPathCreateMutable(); + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + for (unsigned i = 0; i < rectCount; i++) + CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset)); + + CGContextRef context = platformContext(); +#ifdef BUILDING_ON_TIGER + CGContextBeginTransparencyLayer(context, NULL); +#endif + CGContextBeginPath(context); + CGContextAddPath(context, focusRingPath); + wkDrawFocusRing(context, colorRef, radius); +#ifdef BUILDING_ON_TIGER + CGContextEndTransparencyLayer(context); +#endif + CGColorRelease(colorRef); + + CGPathRelease(focusRingPath); +} + +#ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp. +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [[NSGraphicsContext graphicsContextWithGraphicsPort:platformContext() flipped:YES] + setCompositingOperation:(NSCompositingOperation)op]; + [pool drain]; +} +#endif + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar) +{ + if (paintingDisabled()) + return; + + // Constants for spelling pattern color + static RetainPtr<NSColor> spellingPatternColor = nil; + static bool usingDotForSpelling = false; + + // Constants for grammar pattern color + static RetainPtr<NSColor> grammarPatternColor = nil; + static bool usingDotForGrammar = false; + + // These are the same for misspelling or bad grammar + int patternHeight = cMisspellingLineThickness; + int patternWidth = cMisspellingLinePatternWidth; + + // Initialize pattern color if needed + if (!grammar && !spellingPatternColor) { + NSImage *image = [NSImage imageNamed:@"SpellingDot"]; + ASSERT(image); // if image is not available, we want to know + NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil); + if (color) + usingDotForSpelling = true; + else + color = [NSColor redColor]; + spellingPatternColor = color; + } + + if (grammar && !grammarPatternColor) { + NSImage *image = [NSImage imageNamed:@"GrammarDot"]; + ASSERT(image); // if image is not available, we want to know + NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil); + if (color) + usingDotForGrammar = true; + else + color = [NSColor greenColor]; + grammarPatternColor = color; + } + + bool usingDot; + NSColor *patternColor; + if (grammar) { + usingDot = usingDotForGrammar; + patternColor = grammarPatternColor.get(); + } else { + usingDot = usingDotForSpelling; + patternColor = spellingPatternColor.get(); + } + + // Make sure to draw only complete dots. + // NOTE: Code here used to shift the underline to the left and increase the width + // to make sure everything gets underlined, but that results in drawing out of + // bounds (e.g. when at the edge of a view) and could make it appear that the + // space between adjacent misspelled words was underlined. + if (usingDot) { + // allow slightly more considering that the pattern ends with a transparent pixel + int widthMod = width % patternWidth; + if (patternWidth - widthMod > cMisspellingLinePatternGapWidth) + width -= widthMod; + } + + // FIXME: This code should not use NSGraphicsContext currentContext + // In order to remove this requirement we will need to use CGPattern instead of NSColor + // FIXME: This code should not be using wkSetPatternPhaseInUserSpace, as this approach is wrong + // for transforms. + + // Draw underline + NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; + CGContextRef context = (CGContextRef)[currentContext graphicsPort]; + CGContextSaveGState(context); + + [patternColor set]; + + wkSetPatternPhaseInUserSpace(context, point); + + NSRectFillUsingOperation(NSMakeRect(point.x(), point.y(), width, patternHeight), NSCompositeSourceOver); + + CGContextRestoreGState(context); +} + +} diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm new file mode 100644 index 0000000..b630ba6 --- /dev/null +++ b/WebCore/platform/graphics/mac/IconMac.mm @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#import "config.h" +#import "Icon.h" + +#import "GraphicsContext.h" +#import "LocalCurrentGraphicsContext.h" +#import "PlatformString.h" +#import <wtf/PassRefPtr.h> + +namespace WebCore { + +Icon::Icon() + : RefCounted<Icon>(0) +{ +} + +Icon::Icon(NSImage *image) + : RefCounted<Icon>(0) + , m_nsImage(image) +{ + // Need this because WebCore uses AppKit's flipped coordinate system exclusively. + [image setFlipped:YES]; +} + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::newIconForFile(const String& filename) +{ + // Don't pass relative filenames -- we don't want a result that depends on the current directory. + // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[] + if (filename.isEmpty() || filename[0U] != '/') + return 0; + + NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filename]; + if (!image) + return 0; + + return new Icon(image); +} + +void Icon::paint(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + LocalCurrentGraphicsContext localCurrentGC(context); + + [m_nsImage.get() drawInRect:rect + fromRect:NSMakeRect(0, 0, [m_nsImage.get() size].width, [m_nsImage.get() size].height) + operation:NSCompositeSourceOver fraction:1.0f]; +} + +} diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm new file mode 100644 index 0000000..121eb78 --- /dev/null +++ b/WebCore/platform/graphics/mac/ImageMac.mm @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "BitmapImage.h" + +#import "FloatRect.h" +#import "FoundationExtras.h" +#import "GraphicsContext.h" +#import "PlatformString.h" +#import "WebCoreFrameBridge.h" + +namespace WebCore { + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ + if (m_frames.size() != 1) + return; + + m_nsImage = 0; + m_tiffRep = 0; +} + +Image* Image::loadPlatformResource(const char *name) +{ + static BitmapImage nullImage; + + NSBundle *bundle = [NSBundle bundleForClass:[WebCoreFrameBridge class]]; + NSString *imagePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"tiff"]; + NSData *namedImageData = [NSData dataWithContentsOfFile:imagePath]; + if (namedImageData) { + Image* image = new BitmapImage; + image->setData(SharedBuffer::wrapNSData(namedImageData), true); + return image; + } + + // 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; +} + +CFDataRef BitmapImage::getTIFFRepresentation() +{ + if (m_tiffRep) + return m_tiffRep.get(); + + unsigned numFrames = frameCount(); + + // If numFrames is zero, we know for certain this image doesn't have valid data + // Even though the call to CGImageDestinationCreateWithData will fail and we'll handle it gracefully, + // in certain circumstances that call will spam the console with an error message + if (!numFrames) + return 0; + + Vector<CGImageRef> images; + for (unsigned i = 0; i < numFrames; ++i ) { + CGImageRef cgImage = frameAtIndex(i); + if (cgImage) + images.append(cgImage); + } + + unsigned numValidFrames = images.size(); + + RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, 0)); + // FIXME: Use type kCGImageTypeIdentifierTIFF constant once is becomes available in the API + CGImageDestinationRef destination = CGImageDestinationCreateWithData(data.get(), CFSTR("public.tiff"), numValidFrames, 0); + + if (!destination) + return 0; + + for (unsigned i = 0; i < numValidFrames; ++i) + CGImageDestinationAddImage(destination, images[i], 0); + + CGImageDestinationFinalize(destination); + CFRelease(destination); + + m_tiffRep = data; + return m_tiffRep.get(); +} + +NSImage* BitmapImage::getNSImage() +{ + if (m_nsImage) + return m_nsImage.get(); + + CFDataRef data = getTIFFRepresentation(); + if (!data) + return 0; + + m_nsImage.adoptNS([[NSImage alloc] initWithData:(NSData*)data]); + return m_nsImage.get(); +} + +} diff --git a/WebCore/platform/graphics/mac/IntPointMac.mm b/WebCore/platform/graphics/mac/IntPointMac.mm new file mode 100644 index 0000000..7a2e730 --- /dev/null +++ b/WebCore/platform/graphics/mac/IntPointMac.mm @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntPoint.h" + +namespace WebCore { + +#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES + +IntPoint::IntPoint(const NSPoint& p) : m_x(static_cast<int>(p.x)), m_y(static_cast<int>(p.y)) +{ +} + +IntPoint::operator NSPoint() const +{ + return NSMakePoint(m_x, m_y); +} + +#endif + +} diff --git a/WebCore/platform/graphics/mac/IntRectMac.mm b/WebCore/platform/graphics/mac/IntRectMac.mm new file mode 100644 index 0000000..738618a --- /dev/null +++ b/WebCore/platform/graphics/mac/IntRectMac.mm @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntRect.h" + +namespace WebCore { + +#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES + +IntRect::operator NSRect() const +{ + return NSMakeRect(x(), y(), width(), height()); +} + +IntRect enclosingIntRect(const NSRect& rect) +{ + int l = static_cast<int>(floorf(rect.origin.x)); + int t = static_cast<int>(floorf(rect.origin.y)); + int r = static_cast<int>(ceilf(NSMaxX(rect))); + int b = static_cast<int>(ceilf(NSMaxY(rect))); + return IntRect(l, t, r - l, b - t); +} + +#endif + +} diff --git a/WebCore/platform/graphics/mac/IntSizeMac.mm b/WebCore/platform/graphics/mac/IntSizeMac.mm new file mode 100644 index 0000000..c7dcd88 --- /dev/null +++ b/WebCore/platform/graphics/mac/IntSizeMac.mm @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntSize.h" + +namespace WebCore { + +#ifndef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES + +IntSize::IntSize(const NSSize& s) : m_width(static_cast<int>(s.width)), m_height(static_cast<int>(s.height)) +{ +} + +IntSize::operator NSSize() const +{ + return NSMakeSize(m_width, m_height); +} + +#endif + +} diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h new file mode 100644 index 0000000..8975d9b --- /dev/null +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayerPrivateQTKit_h +#define MediaPlayerPrivateQTKit_h + +#if ENABLE(VIDEO) + +#include "MediaPlayer.h" +#include "Timer.h" +#include <wtf/RetainPtr.h> + +#ifdef __OBJC__ +#import <QTKit/QTTime.h> +@class QTMovie; +@class QTMovieView; +@class WebCoreMovieObserver; +#else +class QTMovie; +class QTMovieView; +class QTTime; +class WebCoreMovieObserver; +#endif + +namespace WebCore { + +class MediaPlayerPrivate : Noncopyable { +public: + MediaPlayerPrivate(MediaPlayer*); + ~MediaPlayerPrivate(); + + IntSize naturalSize() const; + bool hasVideo() const; + + void load(const String& url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + void setEndTime(float time); + + void setRate(float); + void setVolume(float); + + int dataRate() const; + + MediaPlayer::NetworkState networkState() const { return m_networkState; } + MediaPlayer::ReadyState readyState() const { return m_readyState; } + + float maxTimeBuffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + bool totalBytesKnown() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setRect(const IntRect& r); + + void loadStateChanged(); + void rateChanged(); + void sizeChanged(); + void timeChanged(); + void didEnd(); + + void repaint(); + void paint(GraphicsContext*, const IntRect&); + + static void getSupportedTypes(HashSet<String>& types); + static bool isAvailable(); + +private: + void createQTMovie(const String& url); + void createQTMovieView(); + void detachQTMovieView(); + QTTime createQTTime(float time) const; + + void updateStates(); + void doSeek(); + void cancelSeek(); + void seekTimerFired(Timer<MediaPlayerPrivate>*); + void endPointTimerFired(Timer<MediaPlayerPrivate>*); + float maxTimeLoaded() const; + void startEndPointTimerIfNeeded(); + void disableUnsupportedTracks(unsigned& enabledTrackCount); + + MediaPlayer* m_player; + RetainPtr<QTMovie> m_qtMovie; + RetainPtr<QTMovieView> m_qtMovieView; + RetainPtr<WebCoreMovieObserver> m_objcObserver; + float m_seekTo; + float m_endTime; + Timer<MediaPlayerPrivate> m_seekTimer; + Timer<MediaPlayerPrivate> m_endPointTimer; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + bool m_startedPlaying; + bool m_isStreaming; +}; + +} + +#endif +#endif diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm new file mode 100644 index 0000000..541d5f6 --- /dev/null +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -0,0 +1,843 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" + +#if ENABLE(VIDEO) + +#import "MediaPlayerPrivateQTKit.h" + +#import "BlockExceptions.h" +#import "GraphicsContext.h" +#import "KURL.h" +#import "ScrollView.h" +#import "SoftLinking.h" +#import "WebCoreSystemInterface.h" +#import <QTKit/QTKit.h> +#import <objc/objc-runtime.h> + +#ifdef BUILDING_ON_TIGER +static IMP method_setImplementation(Method m, IMP imp) +{ + IMP result = m->method_imp; + m->method_imp = imp; + return result; +} +#endif + +SOFT_LINK_FRAMEWORK(QTKit) + +SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (timeValue, timeScale)) + +SOFT_LINK_CLASS(QTKit, QTMovie) +SOFT_LINK_CLASS(QTKit, QTMovieView) + +SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *) +SOFT_LINK_POINTER(QTKit, QTMediaTypeSound, NSString *) +SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *) +SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieDataSizeAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieDidEndNotification, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieHasVideoAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieNaturalSizeAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMoviePreventExternalURLLinksAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieRateDidChangeNotification, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieSizeDidChangeNotification, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieTimeDidChangeNotification, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieTimeScaleAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieURLAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieVolumeDidChangeNotification, NSString *) +SOFT_LINK_POINTER(QTKit, QTSecurityPolicyNoCrossSiteAttribute, NSString *) + +#define QTMovie getQTMovieClass() +#define QTMovieView getQTMovieViewClass() + +#define QTMediaTypeAttribute getQTMediaTypeAttribute() +#define QTMediaTypeBase getQTMediaTypeBase() +#define QTMediaTypeSound getQTMediaTypeSound() +#define QTMediaTypeText getQTMediaTypeText() +#define QTMediaTypeVideo getQTMediaTypeVideo() +#define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute() +#define QTMovieDidEndNotification getQTMovieDidEndNotification() +#define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute() +#define QTMovieIsActiveAttribute getQTMovieIsActiveAttribute() +#define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute() +#define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification() +#define QTMovieNaturalSizeAttribute getQTMovieNaturalSizeAttribute() +#define QTMoviePreventExternalURLLinksAttribute getQTMoviePreventExternalURLLinksAttribute() +#define QTMovieRateDidChangeNotification getQTMovieRateDidChangeNotification() +#define QTMovieSizeDidChangeNotification getQTMovieSizeDidChangeNotification() +#define QTMovieTimeDidChangeNotification getQTMovieTimeDidChangeNotification() +#define QTMovieTimeScaleAttribute getQTMovieTimeScaleAttribute() +#define QTMovieURLAttribute getQTMovieURLAttribute() +#define QTMovieVolumeDidChangeNotification getQTMovieVolumeDidChangeNotification() +#define QTSecurityPolicyNoCrossSiteAttribute getQTSecurityPolicyNoCrossSiteAttribute() + +// Older versions of the QTKit header don't have these constants. +#if !defined QTKIT_VERSION_MAX_ALLOWED || QTKIT_VERSION_MAX_ALLOWED <= QTKIT_VERSION_7_0 +enum { + QTMovieLoadStateError = -1L, + QTMovieLoadStateLoaded = 2000L, + QTMovieLoadStatePlayable = 10000L, + QTMovieLoadStatePlaythroughOK = 20000L, + QTMovieLoadStateComplete = 100000L +}; +#endif + +using namespace WebCore; +using namespace std; + +@interface WebCoreMovieObserver : NSObject +{ + MediaPlayerPrivate* m_callback; + BOOL m_delayCallbacks; +} +-(id)initWithCallback:(MediaPlayerPrivate*)callback; +-(void)disconnect; +-(void)repaint; +-(void)setDelayCallbacks:(BOOL)shouldDelay; +-(void)loadStateChanged:(NSNotification *)notification; +-(void)rateChanged:(NSNotification *)notification; +-(void)sizeChanged:(NSNotification *)notification; +-(void)timeChanged:(NSNotification *)notification; +-(void)didEnd:(NSNotification *)notification; +@end + +namespace WebCore { + +static const float endPointTimerInterval = 0.020f; +static const long minimumQuickTimeVersion = 0x07300000; // 7.3 + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player) + , m_objcObserver(AdoptNS, [[WebCoreMovieObserver alloc] initWithCallback:this]) + , m_seekTo(-1) + , m_endTime(numeric_limits<float>::infinity()) + , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired) + , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::DataUnavailable) + , m_startedPlaying(false) + , m_isStreaming(false) +{ +} + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + detachQTMovieView(); + + [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()]; + [m_objcObserver.get() disconnect]; +} + +void MediaPlayerPrivate::createQTMovie(const String& url) +{ + [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()]; + + m_qtMovie = 0; + + // Disable streaming support for now, <rdar://problem/5693967> + if (protocolIs(url, "rtsp")) + return; + + NSURL *cocoaURL = KURL(url); + NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys: + cocoaURL, QTMovieURLAttribute, + [NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute, + [NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute, + nil]; + + NSError* error = nil; + m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]); + + // FIXME: Find a proper way to detect streaming content. + m_isStreaming = protocolIs(url, "rtsp"); + + if (!m_qtMovie) + return; + + [m_qtMovie.get() setVolume:m_player->volume()]; + + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() + selector:@selector(loadStateChanged:) + name:QTMovieLoadStateDidChangeNotification + object:m_qtMovie.get()]; + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() + selector:@selector(rateChanged:) + name:QTMovieRateDidChangeNotification + object:m_qtMovie.get()]; + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() + selector:@selector(sizeChanged:) + name:QTMovieSizeDidChangeNotification + object:m_qtMovie.get()]; + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() + selector:@selector(timeChanged:) + name:QTMovieTimeDidChangeNotification + object:m_qtMovie.get()]; + [[NSNotificationCenter defaultCenter] addObserver:m_objcObserver.get() + selector:@selector(didEnd:) + name:QTMovieDidEndNotification + object:m_qtMovie.get()]; +} + +static void mainThreadSetNeedsDisplay(id self, SEL _cmd) +{ + id movieView = [self superview]; + ASSERT(!movieView || [movieView isKindOfClass:[QTMovieView class]]); + if (!movieView || ![movieView isKindOfClass:[QTMovieView class]]) + return; + + WebCoreMovieObserver* delegate = [movieView delegate]; + ASSERT(!delegate || [delegate isKindOfClass:[WebCoreMovieObserver class]]); + if (!delegate || ![delegate isKindOfClass:[WebCoreMovieObserver class]]) + return; + + [delegate repaint]; +} + +void MediaPlayerPrivate::createQTMovieView() +{ + detachQTMovieView(); + + if (!m_player->m_parentWidget || !m_qtMovie) + return; + + static bool addedCustomMethods = false; + if (!addedCustomMethods) { + Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView"); + ASSERT(QTMovieContentViewClass); + + Method mainThreadSetNeedsDisplayMethod = class_getInstanceMethod(QTMovieContentViewClass, @selector(_mainThreadSetNeedsDisplay)); + ASSERT(mainThreadSetNeedsDisplayMethod); + + method_setImplementation(mainThreadSetNeedsDisplayMethod, reinterpret_cast<IMP>(mainThreadSetNeedsDisplay)); + addedCustomMethods = true; + } + + m_qtMovieView.adoptNS([[QTMovieView alloc] init]); + setRect(m_player->rect()); + NSView* parentView = static_cast<ScrollView*>(m_player->m_parentWidget)->getDocumentView(); + [parentView addSubview:m_qtMovieView.get()]; +#ifdef BUILDING_ON_TIGER + // setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy + [m_qtMovieView.get() performSelector:@selector(setDelegate:) withObject:m_objcObserver.get()]; +#else + [m_qtMovieView.get() setDelegate:m_objcObserver.get()]; +#endif + [m_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); +} + +void MediaPlayerPrivate::detachQTMovieView() +{ + if (m_qtMovieView) { +#ifdef BUILDING_ON_TIGER + // setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy + [m_qtMovieView.get() performSelector:@selector(setDelegate:) withObject:nil]; +#else + [m_qtMovieView.get() setDelegate:nil]; +#endif + [m_qtMovieView.get() removeFromSuperview]; + m_qtMovieView = nil; + } +} + +QTTime MediaPlayerPrivate::createQTTime(float time) const +{ + if (!m_qtMovie) + return QTMakeTime(0, 600); + long timeScale = [[m_qtMovie.get() attributeForKey:QTMovieTimeScaleAttribute] longValue]; + return QTMakeTime(time * timeScale, timeScale); +} + +void MediaPlayerPrivate::load(const String& url) +{ + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::DataUnavailable) { + m_readyState = MediaPlayer::DataUnavailable; + m_player->readyStateChanged(); + } + cancelSeek(); + m_endPointTimer.stop(); + + [m_objcObserver.get() setDelayCallbacks:YES]; + + createQTMovie(url); + if (m_player->visible()) + createQTMovieView(); + + [m_objcObserver.get() loadStateChanged:nil]; + [m_objcObserver.get() setDelayCallbacks:NO]; +} + +void MediaPlayerPrivate::play() +{ + if (!m_qtMovie) + return; + m_startedPlaying = true; + [m_objcObserver.get() setDelayCallbacks:YES]; + [m_qtMovie.get() setRate:m_player->rate()]; + [m_objcObserver.get() setDelayCallbacks:NO]; + startEndPointTimerIfNeeded(); +} + +void MediaPlayerPrivate::pause() +{ + if (!m_qtMovie) + return; + m_startedPlaying = false; + [m_objcObserver.get() setDelayCallbacks:YES]; + [m_qtMovie.get() stop]; + [m_objcObserver.get() setDelayCallbacks:NO]; + m_endPointTimer.stop(); +} + +float MediaPlayerPrivate::duration() const +{ + if (!m_qtMovie) + return 0; + QTTime time = [m_qtMovie.get() duration]; + if (time.flags == kQTTimeIsIndefinite) + return numeric_limits<float>::infinity(); + return static_cast<float>(time.timeValue) / time.timeScale; +} + +float MediaPlayerPrivate::currentTime() const +{ + if (!m_qtMovie) + return 0; + QTTime time = [m_qtMovie.get() currentTime]; + return min(static_cast<float>(time.timeValue) / time.timeScale, m_endTime); +} + +void MediaPlayerPrivate::seek(float time) +{ + cancelSeek(); + + if (!m_qtMovie) + return; + + if (time > duration()) + time = duration(); + + m_seekTo = time; + if (maxTimeLoaded() >= m_seekTo) + doSeek(); + else + m_seekTimer.start(0, 0.5f); +} + +void MediaPlayerPrivate::doSeek() +{ + QTTime qttime = createQTTime(m_seekTo); + // setCurrentTime generates several event callbacks, update afterwards + [m_objcObserver.get() setDelayCallbacks:YES]; + float oldRate = [m_qtMovie.get() rate]; + [m_qtMovie.get() setRate:0]; + [m_qtMovie.get() setCurrentTime:qttime]; + float timeAfterSeek = currentTime(); + // restore playback only if not at end, othewise QTMovie will loop + if (timeAfterSeek < duration() && timeAfterSeek < m_endTime) + [m_qtMovie.get() setRate:oldRate]; + cancelSeek(); + [m_objcObserver.get() setDelayCallbacks:NO]; +} + +void MediaPlayerPrivate::cancelSeek() +{ + m_seekTo = -1; + m_seekTimer.stop(); +} + +void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*) +{ + if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) { + cancelSeek(); + updateStates(); + m_player->timeChanged(); + return; + } + + if (maxTimeLoaded() >= m_seekTo) + doSeek(); + else { + MediaPlayer::NetworkState state = networkState(); + if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) { + cancelSeek(); + updateStates(); + m_player->timeChanged(); + } + } +} + +void MediaPlayerPrivate::setEndTime(float time) +{ + m_endTime = time; + startEndPointTimerIfNeeded(); +} + +void MediaPlayerPrivate::startEndPointTimerIfNeeded() +{ + if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive()) + m_endPointTimer.startRepeating(endPointTimerInterval); +} + +void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) +{ + float time = currentTime(); + + // just do end for now + if (time >= m_endTime) { + pause(); + didEnd(); + } +} + +bool MediaPlayerPrivate::paused() const +{ + if (!m_qtMovie) + return true; + return [m_qtMovie.get() rate] == 0; +} + +bool MediaPlayerPrivate::seeking() const +{ + if (!m_qtMovie) + return false; + return m_seekTo >= 0; +} + +IntSize MediaPlayerPrivate::naturalSize() const +{ + if (!m_qtMovie) + return IntSize(); + return IntSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]); +} + +bool MediaPlayerPrivate::hasVideo() const +{ + if (!m_qtMovie) + return false; + return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue]; +} + +void MediaPlayerPrivate::setVolume(float volume) +{ + if (!m_qtMovie) + return; + [m_qtMovie.get() setVolume:volume]; +} + +void MediaPlayerPrivate::setRate(float rate) +{ + if (!m_qtMovie) + return; + if (!paused()) + [m_qtMovie.get() setRate:rate]; +} + +int MediaPlayerPrivate::dataRate() const +{ + if (!m_qtMovie) + return 0; + return wkQTMovieDataRate(m_qtMovie.get()); +} + + +float MediaPlayerPrivate::maxTimeBuffered() const +{ + // rtsp streams are not buffered + return m_isStreaming ? 0 : maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeSeekable() const +{ + // infinite duration means live stream + return isinf(duration()) ? 0 : maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeLoaded() const +{ + if (!m_qtMovie) + return 0; + return wkQTMovieMaxTimeLoaded(m_qtMovie.get()); +} + +unsigned MediaPlayerPrivate::bytesLoaded() const +{ + float dur = duration(); + if (!dur) + return 0; + return totalBytes() * maxTimeLoaded() / dur; +} + +bool MediaPlayerPrivate::totalBytesKnown() const +{ + return totalBytes() > 0; +} + +unsigned MediaPlayerPrivate::totalBytes() const +{ + if (!m_qtMovie) + return 0; + return [[m_qtMovie.get() attributeForKey:QTMovieDataSizeAttribute] intValue]; +} + +void MediaPlayerPrivate::cancelLoad() +{ + // FIXME: Is there a better way to check for this? + if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) + return; + + detachQTMovieView(); + m_qtMovie = nil; + + updateStates(); +} + +void MediaPlayerPrivate::updateStates() +{ + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + + long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError); + + if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData) { + unsigned enabledTrackCount; + disableUnsupportedTracks(enabledTrackCount); + // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692> + if (!enabledTrackCount) + loadState = QTMovieLoadStateError; + } + + // "Loaded" is reserved for fully buffered movies, never the case when streaming + if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) { + if (m_networkState < MediaPlayer::Loaded) + m_networkState = MediaPlayer::Loaded; + m_readyState = MediaPlayer::CanPlayThrough; + } else if (loadState >= QTMovieLoadStatePlaythroughOK) { + if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking()) + m_networkState = MediaPlayer::LoadedFirstFrame; + m_readyState = MediaPlayer::CanPlayThrough; + } else if (loadState >= QTMovieLoadStatePlayable) { + if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking()) + m_networkState = MediaPlayer::LoadedFirstFrame; + // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967> + m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable; + } else if (loadState >= QTMovieLoadStateLoaded) { + if (m_networkState < MediaPlayer::LoadedMetaData) + m_networkState = MediaPlayer::LoadedMetaData; + m_readyState = MediaPlayer::DataUnavailable; + } else if (loadState > QTMovieLoadStateError) { + if (m_networkState < MediaPlayer::Loading) + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::DataUnavailable; + } else { + m_networkState = MediaPlayer::LoadFailed; + m_readyState = MediaPlayer::DataUnavailable; + } + + if (seeking()) + m_readyState = MediaPlayer::DataUnavailable; + + if (m_networkState != oldNetworkState) + m_player->networkStateChanged(); + if (m_readyState != oldReadyState) + m_player->readyStateChanged(); +} + +void MediaPlayerPrivate::loadStateChanged() +{ + updateStates(); +} + +void MediaPlayerPrivate::rateChanged() +{ + updateStates(); +} + +void MediaPlayerPrivate::sizeChanged() +{ +} + +void MediaPlayerPrivate::timeChanged() +{ + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivate::didEnd() +{ + m_endPointTimer.stop(); + m_startedPlaying = false; + updateStates(); + m_player->timeChanged(); +} + +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]; +} + +void MediaPlayerPrivate::setVisible(bool b) +{ + if (b) + createQTMovieView(); + else + detachQTMovieView(); +} + +void MediaPlayerPrivate::repaint() +{ + m_player->repaint(); +} + +void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) +{ + if (context->paintingDisabled()) + return; + NSView *view = m_qtMovieView.get(); + if (view == nil) + 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)); + IntRect paintRect(IntPoint(0, 0), IntSize(r.width(), r.height())); + NSGraphicsContext* newContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context->platformContext() flipped:NO]; + [view displayRectIgnoringOpacity:paintRect inContext:newContext]; + context->restore(); + END_BLOCK_OBJC_EXCEPTIONS; + [m_objcObserver.get() setDelayCallbacks:NO]; +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +{ + NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes]; + int count = [fileTypes count]; + for (int n = 0; n < count; n++) { + CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]); + RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL)); + if (!uti) + continue; + RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType)); + if (!mime) + continue; + types.add(mime.get()); + } +} + +bool MediaPlayerPrivate::isAvailable() +{ + 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."); + return false; + } + if (version < minimumQuickTimeVersion) { + LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", version, minimumQuickTimeVersion); + return false; + } + return true; +} + +void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) +{ + if (!m_qtMovie) { + enabledTrackCount = 0; + return; + } + + static HashSet<String>* allowedTrackTypes = 0; + if (!allowedTrackTypes) { + allowedTrackTypes = new HashSet<String>; + allowedTrackTypes->add(QTMediaTypeVideo); + allowedTrackTypes->add(QTMediaTypeSound); + allowedTrackTypes->add(QTMediaTypeText); + allowedTrackTypes->add(QTMediaTypeBase); + allowedTrackTypes->add("clcp"); + allowedTrackTypes->add("sbtl"); + } + + NSArray *tracks = [m_qtMovie.get() tracks]; + + unsigned trackCount = [tracks count]; + enabledTrackCount = trackCount; + for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++) { + // Grab the track at the current index. If there isn't one there, then + // we can move onto the next one. + QTTrack *track = [tracks objectAtIndex:trackIndex]; + if (!track) + continue; + + // Check to see if the track is disabled already, we should move along. + // We don't need to re-disable it. + if (![track isEnabled]) + continue; + + // Grab the track's media. We're going to check to see if we need to + // disable the tracks. They could be unsupported. + QTMedia *trackMedia = [track media]; + if (!trackMedia) + continue; + + // Grab the media type for this track. + NSString *mediaType = [trackMedia attributeForKey:QTMediaTypeAttribute]; + if (!mediaType) + continue; + + // Test whether the media type is in our white list. + if (!allowedTrackTypes->contains(mediaType)) { + // If this track type is not allowed, then we need to disable it. + [track setEnabled:NO]; + --enabledTrackCount; + } + + // Disable chapter tracks. These are most likely to lead to trouble, as + // they will be composited under the video tracks, forcing QT to do extra + // work. + QTTrack *chapterTrack = [track performSelector:@selector(chapterlist)]; + if (!chapterTrack) + continue; + + // Try to grab the media for the track. + QTMedia *chapterMedia = [chapterTrack media]; + if (!chapterMedia) + continue; + + // Grab the media type for this track. + id chapterMediaType = [chapterMedia attributeForKey:QTMediaTypeAttribute]; + if (!chapterMediaType) + continue; + + // Check to see if the track is a video track. We don't care about + // other non-video tracks. + if (![chapterMediaType isEqual:QTMediaTypeVideo]) + continue; + + // Check to see if the track is already disabled. If it is, we + // should move along. + if (![chapterTrack isEnabled]) + continue; + + // Disable the evil, evil track. + [chapterTrack setEnabled:NO]; + --enabledTrackCount; + } +} + +} + +@implementation WebCoreMovieObserver + +- (id)initWithCallback:(MediaPlayerPrivate *)callback +{ + m_callback = callback; + return [super init]; +} + +- (void)disconnect +{ + [NSObject cancelPreviousPerformRequestsWithTarget:self]; + m_callback = 0; +} + +-(void)repaint +{ + if (m_delayCallbacks) + [self performSelector:_cmd withObject:nil afterDelay:0.]; + else if (m_callback) + m_callback->repaint(); +} + +- (void)loadStateChanged:(NSNotification *)notification +{ + if (m_delayCallbacks) + [self performSelector:_cmd withObject:nil afterDelay:0]; + else + m_callback->loadStateChanged(); +} + +- (void)rateChanged:(NSNotification *)notification +{ + if (m_delayCallbacks) + [self performSelector:_cmd withObject:nil afterDelay:0]; + else + m_callback->rateChanged(); +} + +- (void)sizeChanged:(NSNotification *)notification +{ + if (m_delayCallbacks) + [self performSelector:_cmd withObject:nil afterDelay:0]; + else + m_callback->sizeChanged(); +} + +- (void)timeChanged:(NSNotification *)notification +{ + if (m_delayCallbacks) + [self performSelector:_cmd withObject:nil afterDelay:0]; + else + m_callback->timeChanged(); +} + +- (void)didEnd:(NSNotification *)notification +{ + if (m_delayCallbacks) + [self performSelector:_cmd withObject:nil afterDelay:0]; + else + m_callback->didEnd(); +} + +- (void)setDelayCallbacks:(BOOL)shouldDelay +{ + m_delayCallbacks = shouldDelay; +} + +@end + +#endif diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm new file mode 100644 index 0000000..5d90514 --- /dev/null +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Alexey Proskuryakov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "SimpleFontData.h" + +#import "BlockExceptions.h" +#import "Color.h" +#import "FloatRect.h" +#import "Font.h" +#import "FontCache.h" +#import "FontDescription.h" +#import "SharedBuffer.h" +#import "WebCoreSystemInterface.h" +#import <ApplicationServices/ApplicationServices.h> +#import <float.h> +#import <unicode/uchar.h> +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> + +@interface NSFont (WebAppKitSecretAPI) +- (BOOL)_isFakeFixedPitch; +@end + +namespace WebCore { + +const float smallCapsFontSizeMultiplier = 0.7f; +const float contextDPI = 72.0f; +static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (contextDPI / (contextDPI * unitsPerEm)); } + +bool initFontData(SimpleFontData* fontData) +{ + if (!fontData->m_font.m_cgFont) + return false; + + ATSUStyle fontStyle; + if (ATSUCreateStyle(&fontStyle) != noErr) + return false; + + ATSUFontID fontId = fontData->m_font.m_atsuFontID; + if (!fontId) { + ATSUDisposeStyle(fontStyle); + return false; + } + + ATSUAttributeTag tag = kATSUFontTag; + ByteCount size = sizeof(ATSUFontID); + ATSUFontID *valueArray[1] = {&fontId}; + OSStatus status = ATSUSetAttributes(fontStyle, 1, &tag, &size, (void* const*)valueArray); + if (status != noErr) { + ATSUDisposeStyle(fontStyle); + return false; + } + + if (wkGetATSStyleGroup(fontStyle, &fontData->m_styleGroup) != noErr) { + ATSUDisposeStyle(fontStyle); + return false; + } + + ATSUDisposeStyle(fontStyle); + + return true; +} + +static NSString *webFallbackFontFamily(void) +{ + static RetainPtr<NSString> webFallbackFontFamily = nil; + if (!webFallbackFontFamily) + webFallbackFontFamily = [[NSFont systemFontOfSize:16.0f] familyName]; + return webFallbackFontFamily.get(); +} + +#if !ERROR_DISABLED +#ifdef __LP64__ +static NSString* pathFromFont(NSFont*) +{ + // FMGetATSFontRefFromFont is not available in 64-bit. As pathFromFont is only used for debugging + // purposes, returning nil is acceptable. + return nil; +} +#else +static NSString* pathFromFont(NSFont *font) +{ + ATSFontRef atsFont = FMGetATSFontRefFromFont(wkGetNSFontATSUFontId(font)); + 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() +{ + m_styleGroup = 0; + m_ATSUStyleInitialized = false; + m_ATSUMirrors = false; + m_checkedShapesArabic = false; + m_shapesArabic = false; + + m_syntheticBoldOffset = m_font.m_syntheticBold ? 1.0f : 0.f; + + bool failedSetup = false; + if (!initFontData(this)) { + // Ack! Something very bad happened, like a corrupt font. + // Try looking for an alternate 'base' font for this renderer. + + // Special case hack to use "Times New Roman" in place of "Times". + // "Times RO" is a common font whose family name is "Times". + // It overrides the normal "Times" family font. + // It also appears to have a corrupt regular variant. + NSString *fallbackFontFamily; + if ([[m_font.font() familyName] isEqual:@"Times"]) + fallbackFontFamily = @"Times New Roman"; + else + fallbackFontFamily = webFallbackFontFamily(); + + // Try setting up the alternate font. + // This is a last ditch effort to use a substitute font when something has gone wrong. +#if !ERROR_DISABLED + RetainPtr<NSFont> initialFont = m_font.font(); +#endif + m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:fallbackFontFamily]); +#if !ERROR_DISABLED + NSString *filePath = pathFromFont(initialFont.get()); + if (!filePath) + filePath = @"not known"; +#endif + if (!initFontData(this)) { + if ([fallbackFontFamily isEqual:@"Times New Roman"]) { + // OK, couldn't setup Times New Roman as an alternate to Times, fallback + // on the system font. If this fails we have no alternative left. + m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:webFallbackFontFamily()]); + if (!initFontData(this)) { + // We tried, Times, Times New Roman, and the system font. No joy. We have to give up. + LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath); + failedSetup = true; + } + } else { + // We tried the requested font and the system font. No joy. We have to give up. + LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath); + failedSetup = true; + } + } + + // Report the problem. + LOG_ERROR("Corrupt font detected, using %@ in place of %@ located at \"%@\".", + [m_font.font() familyName], [initialFont.get() familyName], filePath); + } + + // If all else fails, try to set up using the system font. + // This is probably because Times and Times New Roman are both unavailable. + if (failedSetup) { + m_font.setFont([NSFont systemFontOfSize:[m_font.font() pointSize]]); + LOG_ERROR("failed to set up font, using system font %s", m_font.font()); + initFontData(this); + } + + int iAscent; + int iDescent; + int iLineGap; +#ifdef BUILDING_ON_TIGER + wkGetFontMetrics(m_font.m_cgFont, &iAscent, &iDescent, &iLineGap, &m_unitsPerEm); +#else + iAscent = CGFontGetAscent(m_font.m_cgFont); + iDescent = CGFontGetDescent(m_font.m_cgFont); + iLineGap = CGFontGetLeading(m_font.m_cgFont); + m_unitsPerEm = CGFontGetUnitsPerEm(m_font.m_cgFont); +#endif + + float pointSize = m_font.m_size; + float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; + float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; + float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; + + // We need to adjust Times, Helvetica, and Courier to closely match the + // vertical metrics of their Microsoft counterparts that are the de facto + // web standard. The AppKit adjustment of 20% is too big and is + // incorrectly added to line spacing, so we use a 15% adjustment instead + // and add it to the ascent. + NSString *familyName = [m_font.font() familyName]; + if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"]) + fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f); + + m_ascent = lroundf(fAscent); + m_descent = lroundf(fDescent); + m_lineGap = lroundf(fLineGap); + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + // Hack Hiragino line metrics to allow room for marked text underlines. + // <rdar://problem/5386183> + if (m_descent < 3 && m_lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) { + m_lineGap -= 3 - m_descent; + m_descent = 3; + } + + // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font. + // Unfortunately, NSFont will round this for us so we don't quite get the right value. + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0; + if (xGlyph) { + NSRect xBox = [m_font.font() boundingRectForGlyph:xGlyph]; + // Use the maximum of either width or height because "x" is nearly square + // and web pages that foolishly use this metric for width will be laid out + // poorly if we return an accurate height. Classic case is Times 13 point, + // which has an "x" that is 7x6 pixels. + m_xHeight = MAX(NSMaxX(xBox), NSMaxY(xBox)); + } else + m_xHeight = [m_font.font() xHeight]; +} + +void SimpleFontData::platformDestroy() +{ + if (m_styleGroup) + wkReleaseStyleGroup(m_styleGroup); + + if (m_ATSUStyleInitialized) + ATSUDisposeStyle(m_ATSUStyle); +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + if (isCustomFont()) { + FontPlatformData smallCapsFontData(m_font); + smallCapsFontData.m_size = smallCapsFontData.m_size * smallCapsFontSizeMultiplier; + m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); + } else { + BEGIN_BLOCK_OBJC_EXCEPTIONS; + float size = [m_font.font() pointSize] * smallCapsFontSizeMultiplier; + FontPlatformData smallCapsFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toSize:size]); + + // AppKit resets the type information (screen/printer) when you convert a font to a different size. + // We have to fix up the font that we're handed back. + smallCapsFont.setFont(fontDescription.usePrinterFont() ? [smallCapsFont.font() printerFont] : [smallCapsFont.font() screenFont]); + + if (smallCapsFont.font()) { + NSFontManager *fontManager = [NSFontManager sharedFontManager]; + NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_font.font()]; + + if (m_font.m_syntheticBold) + fontTraits |= NSBoldFontMask; + if (m_font.m_syntheticOblique) + fontTraits |= NSItalicFontMask; + + NSFontTraitMask smallCapsFontTraits = [fontManager traitsOfFont:smallCapsFont.font()]; + smallCapsFont.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(smallCapsFontTraits & NSBoldFontMask); + smallCapsFont.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(smallCapsFontTraits & NSItalicFontMask); + + m_smallCapsFontData = FontCache::getCachedFontData(&smallCapsFont); + } + END_BLOCK_OBJC_EXCEPTIONS; + } + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + NSString *string = [[NSString alloc] initWithCharactersNoCopy:(UniChar*)characters length:length freeWhenDone:NO]; + NSCharacterSet *set = [[m_font.font() coveredCharacterSet] invertedSet]; + bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound; + [string release]; + return result; +} + +void SimpleFontData::determinePitch() +{ + NSFont* f = m_font.font(); + // Special case Osaka-Mono. + // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixed pitch. + // Note that the AppKit does not report Osaka-Mono as fixed pitch. + + // Special case MS-PGothic. + // According to <rdar://problem/4032938>, we should not treat MS-PGothic as fixed pitch. + // Note that AppKit does report MS-PGothic as fixed pitch. + + // Special case MonotypeCorsiva + // According to <rdar://problem/5454704>, we should not treat MonotypeCorsiva as fixed pitch. + // Note that AppKit does report MonotypeCorsiva as fixed pitch. + + NSString *name = [f fontName]; + m_treatAsFixedPitch = ([f isFixedPitch] || [f _isFakeFixedPitch] || + [name caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame) && + [name caseInsensitiveCompare:@"MS-PGothic"] != NSOrderedSame && + [name caseInsensitiveCompare:@"MonotypeCorsiva"] != NSOrderedSame; +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + NSFont* font = m_font.font(); + float pointSize = m_font.m_size; + CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); + CGSize advance; + if (!wkGetGlyphTransformedAdvances(m_font.m_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; +} + +void SimpleFontData::checkShapesArabic() const +{ + ASSERT(!m_checkedShapesArabic); + + m_checkedShapesArabic = true; + + ATSUFontID fontID = m_font.m_atsuFontID; + if (!fontID) { + LOG_ERROR("unable to get ATSUFontID for %@", m_font.font()); + return; + } + + // This function is called only on fonts that contain Arabic glyphs. Our + // heuristic is that if such a font has a glyph metamorphosis table, then + // it includes shaping information for Arabic. + FourCharCode tables[] = { 'morx', 'mort' }; + for (unsigned i = 0; i < sizeof(tables) / sizeof(tables[0]); ++i) { + ByteCount tableSize; + OSStatus status = ATSFontGetTable(fontID, tables[i], 0, 0, 0, &tableSize); + if (status == noErr) { + m_shapesArabic = true; + return; + } + + if (status != kATSInvalidFontTableAccess) + LOG_ERROR("ATSFontGetTable failed (%d)", status); + } +} + +} diff --git a/WebCore/platform/graphics/qt/AffineTransformQt.cpp b/WebCore/platform/graphics/qt/AffineTransformQt.cpp new file mode 100644 index 0000000..8bd5c87 --- /dev/null +++ b/WebCore/platform/graphics/qt/AffineTransformQt.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AffineTransform.h" + +#include "IntRect.h" +#include "FloatRect.h" + +namespace WebCore { + +AffineTransform::AffineTransform() + : m_transform() +{ +} + +AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) + : m_transform(a, b, c, d, tx, ty) +{ +} + +AffineTransform::AffineTransform(const QMatrix& matrix) + : m_transform(matrix) +{ +} + +void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty) +{ + m_transform.setMatrix(a, b, c, d, tx, ty); +} + +void AffineTransform::map(double x, double y, double* x2, double* y2) const +{ + qreal tx2, ty2; + m_transform.map(qreal(x), qreal(y), &tx2, &ty2); + *x2 = tx2; + *y2 = ty2; +} + +IntRect AffineTransform::mapRect(const IntRect& rect) const +{ + return m_transform.mapRect(rect); +} + +FloatRect AffineTransform::mapRect(const FloatRect& rect) const +{ + return m_transform.mapRect(rect); +} + +bool AffineTransform::isIdentity() const +{ + return m_transform.isIdentity(); +} + +double AffineTransform::a() const +{ + return m_transform.m11(); +} + +void AffineTransform::setA(double a) +{ + m_transform.setMatrix(a, b(), c(), d(), e(), f()); +} + +double AffineTransform::b() const +{ + return m_transform.m12(); +} + +void AffineTransform::setB(double b) +{ + m_transform.setMatrix(a(), b, c(), d(), e(), f()); +} + +double AffineTransform::c() const +{ + return m_transform.m21(); +} + +void AffineTransform::setC(double c) +{ + m_transform.setMatrix(a(), b(), c, d(), e(), f()); +} + +double AffineTransform::d() const +{ + return m_transform.m22(); +} + +void AffineTransform::setD(double d) +{ + m_transform.setMatrix(a(), b(), c(), d, e(), f()); +} + +double AffineTransform::e() const +{ + return m_transform.dx(); +} + +void AffineTransform::setE(double e) +{ + m_transform.setMatrix(a(), b(), c(), d(), e, f()); +} + +double AffineTransform::f() const +{ + return m_transform.dy(); +} + +void AffineTransform::setF(double f) +{ + m_transform.setMatrix(a(), b(), c(), d(), e(), f); +} + +void AffineTransform::reset() +{ + m_transform.reset(); +} + +AffineTransform& AffineTransform::scale(double sx, double sy) +{ + m_transform.scale(sx, sy); + return *this; +} + +AffineTransform& AffineTransform::rotate(double d) +{ + m_transform.rotate(d); + return *this; +} + +AffineTransform& AffineTransform::translate(double tx, double ty) +{ + m_transform.translate(tx, ty); + return *this; +} + +AffineTransform& AffineTransform::shear(double sx, double sy) +{ + m_transform.shear(sx, sy); + return *this; +} + +double AffineTransform::det() const +{ + return m_transform.det(); +} + +AffineTransform AffineTransform::inverse() const +{ + if(!isInvertible()) + return AffineTransform(); + + return m_transform.inverted(); +} + +AffineTransform::operator QMatrix() const +{ + return m_transform; +} + +bool AffineTransform::operator==(const AffineTransform& other) const +{ + return m_transform == other.m_transform; +} + +AffineTransform& AffineTransform::operator*=(const AffineTransform& other) +{ + m_transform *= other.m_transform; + return *this; +} + +AffineTransform AffineTransform::operator*(const AffineTransform& other) +{ + return m_transform * other.m_transform; +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ColorQt.cpp b/WebCore/platform/graphics/qt/ColorQt.cpp new file mode 100644 index 0000000..5d16740 --- /dev/null +++ b/WebCore/platform/graphics/qt/ColorQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +#include <QColor> + +namespace WebCore { + +Color::Color(const QColor& c) + : m_color(makeRGBA(c.red(), c.green(), c.blue(), c.alpha())) +{ + m_valid = c.isValid(); +} + +Color::operator QColor() const +{ + return QColor(red(), green(), blue(), alpha()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/FloatPointQt.cpp b/WebCore/platform/graphics/qt/FloatPointQt.cpp new file mode 100644 index 0000000..82093d8 --- /dev/null +++ b/WebCore/platform/graphics/qt/FloatPointQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatPoint.h" + +#include <QPointF> + +namespace WebCore { + +FloatPoint::FloatPoint(const QPointF& p) + : m_x(p.x()) + , m_y(p.y()) +{ +} + +FloatPoint::operator QPointF() const +{ + return QPointF(m_x, m_y); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/FloatRectQt.cpp b/WebCore/platform/graphics/qt/FloatRectQt.cpp new file mode 100644 index 0000000..1c918e3 --- /dev/null +++ b/WebCore/platform/graphics/qt/FloatRectQt.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatRect.h" + +#include <QRectF> + +namespace WebCore { + +FloatRect::FloatRect(const QRectF& r) + : m_location(r.topLeft()) + , m_size(r.width() + , r.height()) +{ +} + +FloatRect::operator QRectF() const +{ + return QRectF(x(), y(), width(), height()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp new file mode 100644 index 0000000..8fb3fba --- /dev/null +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -0,0 +1,54 @@ +/* + Copyright (C) 2007 Trolltech ASA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "Font.h" + +namespace WebCore { + +bool FontCache::fontExists(const FontDescription &desc, const AtomicString& family) +{ + // 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) +{ + return 0; +} + +SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&) +{ + return 0; +} + +} diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp new file mode 100644 index 0000000..67193d4 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp @@ -0,0 +1,56 @@ +/* + Copyright (C) 2007 Trolltech ASA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "FontPlatformData.h" +#include "SharedBuffer.h" +#include <QFontDatabase> + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ + QFontDatabase::removeApplicationFont(handle); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic) +{ + FontPlatformData result; + result.handle = handle; + return result; +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + int id = QFontDatabase::addApplicationFontFromData(QByteArray(buffer->data(), buffer->size())); + if (id == -1) + return 0; + FontCustomPlatformData *data = new FontCustomPlatformData; + data->handle = id; + return data; +} + +} + diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/WebCore/platform/graphics/qt/FontCustomPlatformData.h new file mode 100644 index 0000000..b7a2b15 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2007 Trolltech ASA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#ifndef FontCustomPlatformData_h_ +#define FontCustomPlatformData_h_ + +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class SharedBuffer; +class FontPlatformData; + +struct FontCustomPlatformData : Noncopyable { + ~FontCustomPlatformData(); + + int handle; // for use with QFontDatabase::addApplicationFont/removeApplicationFont + + FontPlatformData fontPlatformData(int size, bool bold, bool italic); +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer); + +} // namespace WebCore + +#endif // FontCustomPlatformData_h_ diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h new file mode 100644 index 0000000..7daf6ed --- /dev/null +++ b/WebCore/platform/graphics/qt/FontPlatformData.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2007 Trolltech ASA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#ifndef FontPlatformData_h +#define FontPlatformData_h + +namespace WebCore { + +class FontPlatformData +{ +public: + // this is only used for custom loaded fonts and represents the id handle passed to + // QFontDatabase::addApplicationFont/removeApplicationFont + int handle; +}; + +} // namespace WebCore + +#endif // FontPlatformData_h diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp new file mode 100644 index 0000000..29b63bf --- /dev/null +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -0,0 +1,651 @@ +/* + Copyright (C) 2007 Trolltech ASA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "Font.h" +#include "FontDescription.h" +#include "FontSelector.h" + +#include "GraphicsContext.h" +#include <QTextLayout> +#include <QPainter> +#include <QFontMetrics> +#include <QFontInfo> +#include <qalgorithms.h> +#include <qdebug.h> + +#include <limits.h> +namespace WebCore { + +#if QT_VERSION >= 0x040400 + +Font::Font() + : m_letterSpacing(0) + , m_wordSpacing(0) + , m_font() + , m_scFont() +{ + QFontMetrics metrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); +} + +Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing) + : m_fontDescription(description) + , m_letterSpacing(letterSpacing) + , m_wordSpacing(wordSpacing) +{ + const FontFamily* family = &description.family(); + QString familyName; + while (family) { + familyName += family->family(); + family = family->next(); + if (family) + familyName += QLatin1Char(','); + } + + m_font.setFamily(familyName); + m_font.setPixelSize(qRound(description.computedSize())); + m_font.setItalic(description.italic()); + if (description.bold()) { + // Qt's Bold is 75, Webkit is 63. + m_font.setWeight(QFont::Bold); + } else { + m_font.setWeight(description.weight()); + } + bool smallCaps = description.smallCaps(); + m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); + + QFontMetrics metrics = QFontMetrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); + + if (wordSpacing) + m_font.setWordSpacing(wordSpacing); + if (letterSpacing) + m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); +} + +void Font::setWordSpacing(short s) +{ + m_font.setWordSpacing(s); + m_wordSpacing = s; +} +void Font::setLetterSpacing(short s) +{ + m_font.setLetterSpacing(QFont::AbsoluteSpacing, s); + m_letterSpacing = s; +} + + +static QString qstring(const TextRun& run) +{ + QString string((QChar *)run.characters(), run.length()); + QChar *uc = string.data(); + for (int i = 0; i < string.length(); ++i) { + if (Font::treatAsSpace(uc[i].unicode())) + uc[i] = 0x20; + else if (Font::treatAsZeroWidthSpace(uc[i].unicode())) + uc[i] = 0x200c; + } + return string; +} + + +static QTextLine setupLayout(QTextLayout* layout, const TextRun& style) +{ + int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; + if (style.padding()) + flags |= Qt::TextJustificationForced; + layout->setFlags(flags); + layout->beginLayout(); + QTextLine line = layout->createLine(); + line.setLineWidth(INT_MAX/256); + if (style.padding()) + line.setLineWidth(line.naturalTextWidth() + style.padding()); + layout->endLayout(); + return line; +} + +void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + if (to < 0) + to = run.length(); + QPainter *p = ctx->platformContext(); + Color color = ctx->fillColor(); + p->setPen(QColor(color)); + + QString string = qstring(run); + + if (from > 0 || to < run.length()) { + QTextLayout layout(string, m_font); + QTextLine line = setupLayout(&layout, run); + float x1 = line.cursorToX(from); + float x2 = line.cursorToX(to); + if (x2 < x1) + qSwap(x1, x2); + + QFontMetrics fm(m_font); + int ascent = fm.ascent(); + QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); + + p->save(); + p->setClipRect(clip.toRect()); + QPointF pt(point.x(), point.y() - ascent); + line.draw(p, pt); + p->restore(); + return; + } + + p->setFont(m_font); + + QPointF pt(point.x(), point.y()); + int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; + p->drawText(pt, string, flags, run.padding()); +} + +int Font::width(const TextRun& run) const +{ + if (!run.length()) + return 0; + QString string = qstring(run); + int w = QFontMetrics(m_font).width(string); + // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) + if (treatAsSpace(run[0])) + w -= m_wordSpacing; + + return w + run.padding(); +} + +float Font::floatWidth(const TextRun& run) const +{ + return width(run); +} + +int Font::offsetForPosition(const TextRun& run, int position, bool /*includePartialGlyphs*/) const +{ + QString string = qstring(run); + QTextLayout layout(string, m_font); + QTextLine line = setupLayout(&layout, run); + return line.xToCursor(position); +} + +FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const +{ + QString string = qstring(run); + QTextLayout layout(string, m_font); + QTextLine line = setupLayout(&layout, run); + + float x1 = line.cursorToX(from); + float x2 = line.cursorToX(to); + if (x2 < x1) + qSwap(x1, x2); + + return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); +} + +#else + + +struct TextRunComponent { + TextRunComponent() : font(0) {} + TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false); + TextRunComponent(int spaces, bool rtl, const QFont *font, int offset); + + inline bool isSpace() const { return spaces != 0; } + + QString string; + const QFont *font; + int width; + int offset; + int spaces; +}; + +TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc) + : string(reinterpret_cast<const QChar*>(start), length) + , font(f) + , offset(o) + , spaces(0) +{ + if (sc) + string = string.toUpper(); + string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); + width = QFontMetrics(*font).width(string); +} + +TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o) + : string(s, QLatin1Char(' ')) + , font(f) + , offset(o) + , spaces(s) +{ + string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); + width = spaces * QFontMetrics(*font).width(QLatin1Char(' ')); +} + + +Font::Font() + : m_letterSpacing(0) + , m_wordSpacing(0) + , m_font() + , m_scFont() +{ + QFontMetrics metrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); + qreal pointsize = m_font.pointSizeF(); + if (pointsize > 0) + m_scFont.setPointSizeF(pointsize*0.7); + else + m_scFont.setPixelSize(qRound(m_font.pixelSize()*.7)); +} + +Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing) + : m_fontDescription(description) + , m_letterSpacing(letterSpacing) + , m_wordSpacing(wordSpacing) +{ + const FontFamily* family = &description.family(); + QString familyName; + while (family) { + familyName += family->family(); + family = family->next(); + if (family) + familyName += QLatin1Char(','); + } + + m_font.setFamily(familyName); + m_font.setPixelSize(qRound(description.computedSize())); + m_font.setItalic(description.italic()); + if (description.bold()) { + // Qt's Bold is 75, Webkit is 63. + m_font.setWeight(QFont::Bold); + } else { + m_font.setWeight(description.weight()); + } + QFontMetrics metrics = QFontMetrics(m_font); + m_spaceWidth = metrics.width(QLatin1Char(' ')); + m_scFont = m_font; + m_scFont.setPixelSize(qRound(description.computedSize()*.7)); +} + +void Font::setWordSpacing(short s) +{ + m_wordSpacing = s; +} +void Font::setLetterSpacing(short s) +{ + m_letterSpacing = s; +} + +static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run) +{ +// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length()); + int letterSpacing = font.letterSpacing(); + int wordSpacing = font.wordSpacing(); + bool smallCaps = font.fontDescription().smallCaps(); + int padding = run.padding(); + int numSpaces = 0; + if (padding) { + for (int i = 0; i < run.length(); i++) + if (Font::treatAsSpace(run[i])) + ++numSpaces; + } + + int offset = 0; + const QFont *f = &font.font(); + if (letterSpacing || smallCaps) { + // need to draw every letter on it's own + int start = 0; + if (Font::treatAsSpace(run[0])) { + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += add + letterSpacing + components->last().width; + start = 1; +// qDebug() << "space at 0" << offset; + } else if (smallCaps) { + f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); + } + for (int i = 1; i < run.length(); ++i) { + uint ch = run[i]; + if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate()) + ch = QChar::surrogateToUcs4(ch, run[i-1]); + if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing) + continue; + if (Font::treatAsSpace(run[i])) { + int add = 0; +// qDebug() << " treatAsSpace:" << i << start; + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width + letterSpacing; +// qDebug() << " appending(1) " << components->last().string << components->last().width; + } + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += wordSpacing + add + components->last().width + letterSpacing; + start = i + 1; + continue; + } else if (!letterSpacing) { +// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) << +// QFontInfo(*f).pointSizeF(); + if (QChar::category(ch) == QChar::Letter_Lowercase) { + if (f == &font.scFont()) + continue; + } else { + if (f == &font.font()) + continue; + } + } + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width + letterSpacing; +// qDebug() << " appending(2) " << components->last().string << components->last().width; + } + if (smallCaps) + f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); + start = i; + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width; +// qDebug() << " appending(3) " << components->last().string << components->last().width; + } + offset += letterSpacing; + } else { + int start = 0; + for (int i = 0; i < run.length(); ++i) { + if (Font::treatAsSpace(run[i])) { + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset)); + offset += components->last().width; + } + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += add + components->last().width; + if (i) + offset += wordSpacing; + start = i + 1; + } + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run.rtl(), + f, offset)); + offset += components->last().width; + } + } + return offset; +} + +void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + if (to < 0) + to = run.length(); + QPainter *p = ctx->platformContext(); + Color color = ctx->fillColor(); + p->setPen(QColor(color)); + + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + if (from > 0 || to < run.length()) { + FloatRect clip = selectionRectForText(run, + IntPoint(qRound(point.x()), qRound(point.y())), + QFontMetrics(m_font).height(), from, to); + QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height()); + p->save(); + p->setClipRect(rect.toRect()); + } + + if (run.rtl()) { + for (int i = 0; i < components.size(); ++i) { + if (!components.at(i).isSpace()) { + p->setFont(*components.at(i).font); + QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y()); + p->drawText(pt, components.at(i).string); + } + } + } else { + for (int i = 0; i < components.size(); ++i) { + if (!components.at(i).isSpace()) { + p->setFont(*components.at(i).font); + QPointF pt(point.x() + components.at(i).offset, point.y()); + p->drawText(pt, components.at(i).string); + } + } + } + if (from > 0 || to < run.length()) + p->restore(); +} + +int Font::width(const TextRun& run) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + +// qDebug() << " width=" << w; + return w; +} + +float Font::floatWidth(const TextRun& run) const +{ + return width(run); +} + +int Font::offsetForPosition(const TextRun& run, int position, bool includePartialGlyphs) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + int offset = 0; + if (run.rtl()) { + for (int i = 0; i < components.size(); ++i) { + int xe = w - components.at(i).offset; + int xs = xe - components.at(i).width; + if (position >= xs) { + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return offset; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + if (position - xs >= l.width()) + return offset; + int cursor = l.xToCursor(position - xs); + if (cursor > 1) + --cursor; + return offset + cursor; + } else { + offset += components.at(i).string.length() - 1; + } + } + } else { + for (int i = 0; i < components.size(); ++i) { + int xs = components.at(i).offset; + int xe = xs + components.at(i).width; + if (position <= xe) { + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return offset; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + if (position - xs >= l.width()) + return offset + components.at(i).string.length() - 1; + int cursor = l.xToCursor(position - xs); + if (cursor > 1) + --cursor; + return offset + cursor; + } else { + offset += components.at(i).string.length() - 1; + } + } + } + return run.length(); +} + +static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor) +{ + int start = 0; + for (int i = 0; i < components.size(); ++i) { + if (start + components.at(i).string.length() - 1 < cursor) { + start += components.at(i).string.length() - 1; + continue; + } + int xs = components.at(i).offset; + if (rtl) + xs = width - xs - components.at(i).width; + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return 0; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + return xs + l.cursorToX(cursor - start + 1); + } + return width; +} + +FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, + int h, int from, int to) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + if (from == 0 && to == run.length()) + return FloatRect(pt.x(), pt.y(), w, h); + + float x1 = cursorToX(components, w, run.rtl(), from); + float x2 = cursorToX(components, w, run.rtl(), to); + if (x2 < x1) + qSwap(x1, x2); + + return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); +} +#endif + + +Font::~Font() +{ +} + +Font::Font(const Font& other) + : m_fontDescription(other.m_fontDescription) + , m_letterSpacing(other.m_letterSpacing) + , m_wordSpacing(other.m_wordSpacing) + , m_font(other.m_font) + , m_scFont(other.m_scFont) + , m_spaceWidth(other.m_spaceWidth) +{ +} + +Font& Font::operator=(const Font& other) +{ + m_fontDescription = other.m_fontDescription; + m_letterSpacing = other.m_letterSpacing; + m_wordSpacing = other.m_wordSpacing; + m_font = other.m_font; + m_scFont = other.m_scFont; + m_spaceWidth = other.m_spaceWidth; + return *this; +} + +bool Font::operator==(const Font& other) const +{ + return m_fontDescription == other.m_fontDescription + && m_letterSpacing == other.m_letterSpacing + && m_wordSpacing == other.m_wordSpacing + && m_font == other.m_font + && m_scFont == other.m_scFont + && m_spaceWidth == other.m_spaceWidth; +} + +void Font::update(PassRefPtr<FontSelector>) const +{ + // don't think we need this +} + + +bool Font::isFixedPitch() const +{ + return QFontInfo(m_font).fixedPitch(); +} + +// Metrics that we query the FontFallbackList for. +int Font::ascent() const +{ + return QFontMetrics(m_font).ascent(); +} + +int Font::descent() const +{ + return QFontMetrics(m_font).descent(); +} + +int Font::lineSpacing() const +{ + return QFontMetrics(m_font).lineSpacing(); +} + +float Font::xHeight() const +{ + return QFontMetrics(m_font).xHeight(); +} + +unsigned Font::unitsPerEm() const +{ + return 1; // FIXME! +} + +int Font::spaceWidth() const +{ + return m_spaceWidth; +} + +} diff --git a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp new file mode 100644 index 0000000..220807e --- /dev/null +++ b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp @@ -0,0 +1,31 @@ +/* + Copyright (C) 2007 Trolltech ASA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "GlyphPageTreeNode.h" + +namespace WebCore { + +void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData) +{ +} + +} diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp new file mode 100644 index 0000000..ec35d96 --- /dev/null +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -0,0 +1,943 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 George Staikos <staikos@kde.org> + * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org> + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "AffineTransform.h" +#include "Path.h" +#include "Color.h" +#include "GraphicsContext.h" +#include "ImageBuffer.h" +#include "Font.h" +#include "Pen.h" +#include "NotImplemented.h" + +#include <QStack> +#include <QPainter> +#include <QPolygonF> +#include <QPainterPath> +#include <QPaintDevice> +#include <QPixmap> +#include <QDebug> + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace WebCore { + +static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op) +{ + switch (op) { + case CompositeClear: + return QPainter::CompositionMode_Clear; + case CompositeCopy: + return QPainter::CompositionMode_Source; + case CompositeSourceOver: + return QPainter::CompositionMode_SourceOver; + case CompositeSourceIn: + return QPainter::CompositionMode_SourceIn; + case CompositeSourceOut: + return QPainter::CompositionMode_SourceOut; + case CompositeSourceAtop: + return QPainter::CompositionMode_SourceAtop; + case CompositeDestinationOver: + return QPainter::CompositionMode_DestinationOver; + case CompositeDestinationIn: + return QPainter::CompositionMode_DestinationIn; + case CompositeDestinationOut: + return QPainter::CompositionMode_DestinationOut; + case CompositeDestinationAtop: + return QPainter::CompositionMode_DestinationAtop; + case CompositeXOR: + return QPainter::CompositionMode_Xor; + case CompositePlusDarker: + return QPainter::CompositionMode_SourceOver; + case CompositeHighlight: + return QPainter::CompositionMode_SourceOver; + case CompositePlusLighter: + return QPainter::CompositionMode_SourceOver; + } + + return QPainter::CompositionMode_SourceOver; +} + +static inline Qt::PenCapStyle toQtLineCap(LineCap lc) +{ + switch (lc) { + case ButtCap: + return Qt::FlatCap; + case RoundCap: + return Qt::RoundCap; + case SquareCap: + return Qt::SquareCap; + } + + return Qt::FlatCap; +} + +static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj) +{ + switch (lj) { + case MiterJoin: + return Qt::SvgMiterJoin; + case RoundJoin: + return Qt::RoundJoin; + case BevelJoin: + return Qt::BevelJoin; + } + + return Qt::MiterJoin; +} + +static Qt::PenStyle toQPenStyle(StrokeStyle style) +{ + switch (style) { + case NoStroke: + return Qt::NoPen; + break; + case SolidStroke: + return Qt::SolidLine; + break; + case DottedStroke: + return Qt::DotLine; + break; + case DashedStroke: + return Qt::DashLine; + break; + } + qWarning("couldn't recognize the pen style"); + return Qt::NoPen; +} + +struct TransparencyLayer +{ + TransparencyLayer(const QPainter* p, const QRect &rect) + : pixmap(rect.width(), rect.height()) + { + offset = rect.topLeft(); + pixmap.fill(Qt::transparent); + painter.begin(&pixmap); + painter.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()); + painter.setClipPath(p->clipPath()); + } + + TransparencyLayer() + { + } + + QPixmap pixmap; + QPoint offset; + QPainter painter; + qreal opacity; +private: + TransparencyLayer(const TransparencyLayer &) {} + 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: + GraphicsContextPlatformPrivate(QPainter* painter); + ~GraphicsContextPlatformPrivate(); + + inline QPainter* p() + { + if (layers.isEmpty()) { + if (redirect) + return redirect; + + return painter; + } else + return &layers.top()->painter; + } + + QPaintDevice* device; + + QStack<TransparencyLayer *> layers; + QPainter* redirect; + + TextShadow shadow; + + // Only used by SVG for now. + QPainterPath currentPath; + +private: + QPainter* painter; +}; + + +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); +} + +GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() +{ +} + +GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate(context)) +{ + setPaintingDisabled(!context); + if (context) { + // Make sure the context starts in sync with our state. + setPlatformFillColor(fillColor()); + setPlatformStrokeColor(strokeColor()); + } +} + +GraphicsContext::~GraphicsContext() +{ + while(!m_data->layers.isEmpty()) + endTransparencyLayer(); + + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + return m_data->p(); +} + +AffineTransform GraphicsContext::getCTM() const +{ + return platformContext()->combinedMatrix(); +} + +void GraphicsContext::savePlatformState() +{ + m_data->p()->save(); +} + +void GraphicsContext::restorePlatformState() +{ + m_data->p()->restore(); +} + +/* FIXME: DISABLED WHILE MERGING BACK FROM UNITY +void GraphicsContext::drawTextShadow(const TextRun& run, const IntPoint& point, const FontStyle& style) +{ + if (paintingDisabled()) + return; + + if (m_data->shadow.isNull()) + return; + + TextShadow* shadow = &m_data->shadow; + + if (shadow->blur <= 0) { + Pen p = pen(); + setPen(shadow->color); + font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y)); + setPen(p); + } else { + const int thickness = shadow->blur; + // FIXME: OPTIMIZE: limit the area to only the actually painted area + 2*thickness + const int w = m_data->p()->device()->width(); + const int h = m_data->p()->device()->height(); + const QRgb color = qRgb(255, 255, 255); + const QRgb bgColor = qRgb(0, 0, 0); + QImage image(QSize(w, h), QImage::Format_ARGB32); + image.fill(bgColor); + QPainter p; + + Pen curPen = pen(); + p.begin(&image); + setPen(color); + m_data->redirect = &p; + font().drawText(this, run, style, IntPoint(point.x() + shadow->x, point.y() + shadow->y)); + m_data->redirect = 0; + p.end(); + setPen(curPen); + + int md = thickness * thickness; // max-dist^2 + + // blur map/precalculated shadow-decay + float* bmap = (float*) alloca(sizeof(float) * (md + 1)); + for (int n = 0; n <= md; n++) { + float f; + f = n / (float) (md + 1); + f = 1.0 - f * f; + bmap[n] = f; + } + + float factor = 0.0; // maximal potential opacity-sum + for (int n = -thickness; n <= thickness; n++) { + for (int m = -thickness; m <= thickness; m++) { + int d = n * n + m * m; + if (d <= md) + factor += bmap[d]; + } + } + + // alpha map + float* amap = (float*) alloca(sizeof(float) * (h * w)); + memset(amap, 0, h * w * (sizeof(float))); + + for (int j = thickness; j<h-thickness; j++) { + for (int i = thickness; i<w-thickness; i++) { + QRgb col = image.pixel(i,j); + if (col == bgColor) + continue; + + float g = qAlpha(col); + g = g / 255; + + for (int n = -thickness; n <= thickness; n++) { + for (int m = -thickness; m <= thickness; m++) { + int d = n * n + m * m; + if (d > md) + continue; + + float f = bmap[d]; + amap[(i + m) + (j + n) * w] += (g * f); + } + } + } + } + + QImage res(QSize(w,h),QImage::Format_ARGB32); + int r = shadow->color.red(); + int g = shadow->color.green(); + int b = shadow->color.blue(); + int a1 = shadow->color.alpha(); + + // arbitratry factor adjustment to make shadows more solid. + factor = 1.333 / factor; + + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + int a = (int) (amap[i + j * w] * factor * a1); + if (a > 255) + a = 255; + + res.setPixel(i,j, qRgba(r, g, b, a)); + } + } + + m_data->p()->drawImage(0, 0, res, 0, 0, -1, -1, Qt::DiffuseAlphaDither | Qt::ColorOnly | Qt::PreferDither); + } +} +*/ + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->p()->drawRect(rect); +} + +// FIXME: Now that this is refactored, it should be shared by all contexts. +static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, + const StrokeStyle& penStyle) +{ + // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic + // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., + // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave + // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. + if (penStyle == DottedStroke || penStyle == DashedStroke) { + if (p1.x() == p2.x()) { + p1.setY(p1.y() + strokeWidth); + p2.setY(p2.y() - strokeWidth); + } else { + p1.setX(p1.x() + strokeWidth); + p2.setX(p2.x() - strokeWidth); + } + } + + if (((int) strokeWidth) % 2) { + if (p1.x() == p2.x()) { + // We're a vertical line. Adjust our x. + p1.setX(p1.x() + 0.5); + p2.setX(p2.x() + 0.5); + } else { + // We're a horizontal line. Adjust our y. + p1.setY(p1.y() + 0.5); + p2.setY(p2.y() + 0.5); + } + } +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + FloatPoint p1 = point1; + FloatPoint p2 = point2; + + adjustLineToPixelBoundaries(p1, p2, strokeThickness(), strokeStyle()); + m_data->p()->drawLine(p1, p2); +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->p()->drawEllipse(rect); +} + +void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) +{ + if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) + return; + + m_data->p()->drawArc(rect, startAngle * 16, angleSpan * 16); +} + +void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + if (npoints <= 1) + return; + + QPolygonF polygon(npoints); + + for (size_t i = 0; i < npoints; i++) + polygon[i] = points[i]; + + QPainter *p = m_data->p(); + p->save(); + p->setRenderHint(QPainter::Antialiasing, shouldAntialias); + p->drawConvexPolygon(polygon); + p->restore(); +} + +void GraphicsContext::fillRect(const IntRect& rect, const Color& c) +{ + if (paintingDisabled()) + return; + + m_data->p()->fillRect(rect, QColor(c)); +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) +{ + if (paintingDisabled()) + return; + + m_data->p()->fillRect(rect, QColor(c)); +} + +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +{ + if (paintingDisabled() || !color.alpha()) + return; + + Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight); + m_data->p()->fillPath(*path.platformPath(), QColor(color)); +} + +void GraphicsContext::beginPath() +{ + m_data->currentPath = QPainterPath(); +} + +void GraphicsContext::addPath(const Path& path) +{ + m_data->currentPath = *(path.platformPath()); +} + +void GraphicsContext::setFillRule(WindRule rule) +{ + m_data->currentPath.setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); +} + +PlatformPath* GraphicsContext::currentPath() +{ + return &m_data->currentPath; +} + +void GraphicsContext::clip(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + if (p->clipRegion().isEmpty()) + p->setClipRect(rect); + else p->setClipRect(rect, Qt::IntersectClip); +} + +/** + * Focus ring handling is not handled here. Qt style in + * RenderTheme handles drawing focus on widgets which + * need it. + */ +void setFocusRingColorChangeFunction(void (*)()) { } +Color focusRingColor() { return Color(0, 0, 0); } +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + + if (rects.size() == 0) + return; + + QPainter *p = m_data->p(); + + const QPen oldPen = p->pen(); + const QBrush oldBrush = p->brush(); + + QPen nPen = p->pen(); + nPen.setColor(color); + p->setBrush(Qt::NoBrush); + nPen.setStyle(Qt::DotLine); + p->setPen(nPen); +#if 0 + // FIXME How do we do a bounding outline with Qt? + QPainterPath path; + for (int i = 0; i < rectCount; ++i) + path.addRect(QRectF(rects[i])); + QPainterPathStroker stroker; + QPainterPath newPath = stroker.createStroke(path); + p->strokePath(newPath, nPen); +#else + for (int i = 0; i < rectCount; ++i) + p->drawRect(QRectF(rects[i])); +#endif + p->setPen(oldPen); + p->setBrush(oldBrush); +} + +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +{ + if (paintingDisabled()) + return; + + IntPoint endPoint = origin + IntSize(width, 0); + drawLine(origin, endPoint); +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, + int width, bool grammar) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +{ + QRectF rect(frect); + rect = m_data->p()->deviceMatrix().mapRect(rect); + + QRect result = rect.toRect(); //round it + return FloatRect(QRectF(result)); +} + +void GraphicsContext::setShadow(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; +} + +void GraphicsContext::clearShadow() +{ + if (paintingDisabled()) + return; + + m_data->shadow = TextShadow(); +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + int x, y, w, h; + x = y = 0; + w = m_data->device->width(); + h = m_data->device->height(); + + QPainter *p = m_data->p(); + 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); + } + TransparencyLayer * layer = new TransparencyLayer(m_data->p(), QRect(x, y, w, h)); + + layer->opacity = opacity; + m_data->layers.push(layer); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + + TransparencyLayer *layer = m_data->layers.pop(); + layer->painter.end(); + + QPainter *p = m_data->p(); + p->save(); + p->resetTransform(); + p->setOpacity(layer->opacity); + p->drawPixmap(layer->offset, layer->pixmap); + p->restore(); + + delete layer; +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPainter::CompositionMode currentCompositionMode = p->compositionMode(); + p->setCompositionMode(QPainter::CompositionMode_Source); + p->eraseRect(rect); + p->setCompositionMode(currentCompositionMode); +} + +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); +} + +void GraphicsContext::setLineCap(LineCap lc) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPen nPen = p->pen(); + nPen.setCapStyle(toQtLineCap(lc)); + p->setPen(nPen); +} + +void GraphicsContext::setLineJoin(LineJoin lj) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPen nPen = p->pen(); + nPen.setJoinStyle(toQtLineJoin(lj)); + p->setPen(nPen); +} + +void GraphicsContext::setMiterLimit(float limit) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPen nPen = p->pen(); + nPen.setMiterLimit(limit); + p->setPen(nPen); +} + +void GraphicsContext::setAlpha(float opacity) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + p->setOpacity(opacity); +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + + m_data->p()->setCompositionMode(toQtCompositionMode(op)); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip); +} + +void GraphicsContext::clipOut(const Path& path) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QRectF clipBounds = p->clipPath().boundingRect(); + QPainterPath clippedOut = *path.platformPath(); + QPainterPath newClip; + newClip.setFillRule(Qt::OddEvenFill); + newClip.addRect(clipBounds); + newClip.addPath(clippedOut); + + p->setClipPath(newClip, Qt::IntersectClip); +} + +void GraphicsContext::translate(float x, float y) +{ + if (paintingDisabled()) + return; + + m_data->p()->translate(x, y); +} + +IntPoint GraphicsContext::origin() +{ + if (paintingDisabled()) + return IntPoint(); + const QTransform &transform = m_data->p()->transform(); + return IntPoint(qRound(transform.dx()), qRound(transform.dy())); +} + +void GraphicsContext::rotate(float radians) +{ + if (paintingDisabled()) + return; + + m_data->p()->rotate(radians); +} + +void GraphicsContext::scale(const FloatSize& s) +{ + if (paintingDisabled()) + return; + + m_data->p()->scale(s.width(), s.height()); +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QRectF clipBounds = p->clipPath().boundingRect(); + QPainterPath newClip; + newClip.setFillRule(Qt::OddEvenFill); + newClip.addRect(clipBounds); + newClip.addRect(QRect(rect)); + + p->setClipPath(newClip, Qt::IntersectClip); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QRectF clipBounds = p->clipPath().boundingRect(); + QPainterPath newClip; + newClip.setFillRule(Qt::OddEvenFill); + newClip.addRect(clipBounds); + newClip.addEllipse(QRect(rect)); + + p->setClipPath(newClip, Qt::IntersectClip); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, + int thickness) +{ + if (paintingDisabled()) + return; + + clip(rect); + QPainterPath path; + + // Add outer ellipse + path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height())); + + // Add inner ellipse. + path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness, + rect.width() - (thickness * 2), rect.height() - (thickness * 2))); + + path.setFillRule(Qt::OddEvenFill); + m_data->p()->setClipPath(path, Qt::IntersectClip); +} + +void GraphicsContext::concatCTM(const AffineTransform& transform) +{ + if (paintingDisabled()) + return; + + m_data->p()->setMatrix(transform, true); +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformFont(const Font& aFont) +{ + if (paintingDisabled()) + return; + m_data->p()->setFont(aFont.font()); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& color) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + QPen newPen(p->pen()); + newPen.setColor(color); + p->setPen(newPen); +} + +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + QPen newPen(p->pen()); + newPen.setStyle(toQPenStyle(strokeStyle)); + p->setPen(newPen); +} + +void GraphicsContext::setPlatformStrokeThickness(float thickness) +{ + if (paintingDisabled()) + return; + QPainter *p = m_data->p(); + QPen newPen(p->pen()); + newPen.setWidthF(thickness); + p->setPen(newPen); +} + +void GraphicsContext::setPlatformFillColor(const Color& color) +{ + if (paintingDisabled()) + return; + m_data->p()->setBrush(QBrush(color)); +} + +void GraphicsContext::setUseAntialiasing(bool enable) +{ + if (paintingDisabled()) + return; + m_data->p()->setRenderHint(QPainter::Antialiasing, enable); +} + +void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r) +{ + if (paintingDisabled()) + return; + QPixmap pixmap = *buffer->pixmap(); + if (pixmap.isNull()) + return; + QPainter* painter = platformContext(); + QPen currentPen = painter->pen(); + qreal currentOpacity = painter->opacity(); + QBrush currentBrush = painter->brush(); + QBrush currentBackground = painter->background(); + if (painter->isActive()) + painter->end(); + static_cast<QPainter*>(painter)->drawPixmap(r, pixmap); + painter->begin(&pixmap); + painter->setPen(currentPen); + painter->setBrush(currentBrush); + painter->setOpacity(currentOpacity); + painter->setBackground(currentBackground); +} + +void GraphicsContext::drawImage(ImageBuffer* buffer, const FloatRect& srcRect, const FloatRect& dstRect) +{ + QPainter* painter = static_cast<QPainter*>(platformContext()); + QPixmap px = *buffer->pixmap(); + if (px.isNull()) + return; + painter->drawPixmap(dstRect, px, srcRect); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp new file mode 100644 index 0000000..c9c900b --- /dev/null +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Icon.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "IntRect.h" +#include "NotImplemented.h" + +#include <qpainter.h> +#include <qpixmap.h> +#include <qrect.h> +#include <qglobal.h> + +namespace WebCore { + +Icon::Icon() + : RefCounted<Icon>(0) +{ +} + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::newIconForFile(const String& filename) +{ + Icon *i = new Icon; + i->m_icon = QIcon(filename); + return PassRefPtr<Icon>(i); +} + +void Icon::paint(GraphicsContext* ctx, const IntRect& rect) +{ + QPixmap px = m_icon.pixmap(rect.size()); + QPainter *p = static_cast<QPainter*>(ctx->platformContext()); + if (p && !px.isNull()) { + p->drawPixmap(rect.x(), rect.y(), px); + } +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp new file mode 100644 index 0000000..449677e --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageBuffer.h" + +#include "GraphicsContext.h" +#include "ImageData.h" +#include "NotImplemented.h" + +#include <QPainter> +#include <QPixmap> + +namespace WebCore { + +std::auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale) +{ + QPixmap px(size); + return std::auto_ptr<ImageBuffer>(new ImageBuffer(px)); +} + +ImageBuffer::ImageBuffer(const QPixmap& px) + : m_pixmap(px), + m_painter(0) +{ + m_painter = new QPainter(&m_pixmap); + m_context.set(new GraphicsContext(m_painter)); +} + +ImageBuffer::~ImageBuffer() +{ + delete m_painter; +} + +GraphicsContext* ImageBuffer::context() const +{ + if (!m_painter->isActive()) + m_painter->begin(&m_pixmap); + + return m_context.get(); +} + +QPixmap* ImageBuffer::pixmap() const +{ + if (!m_painter) + return &m_pixmap; + if (m_painter->isActive()) + m_painter->end(); + return &m_pixmap; +} + +PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&) +{ + notImplemented(); +} + +} diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp new file mode 100644 index 0000000..44ab0d3 --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com> + * Copyright (C) 2006 Trolltech ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageDecoderQt.h" + +#include <QtCore/QByteArray> +#include <QtCore/QBuffer> + +#include <QtGui/QImageReader> +#include <qdebug.h> + +namespace { + const QImage::Format DesiredFormat = QImage::Format_ARGB32; + const bool debugImageDecoderQt = false; +} + +namespace WebCore { +ImageDecoderQt::ImageData::ImageData(const QImage& image, ImageState imageState, int duration) : + m_image(image), m_imageState(imageState), m_duration(duration) +{ +} + +// Context, maintains IODevice on a data buffer. +class ImageDecoderQt::ReadContext { +public: + + enum LoadMode { + // Load images incrementally. This is still experimental and + // will cause the image plugins to report errors. + // Also note that as of Qt 4.2.2, the JPEG loader does not return error codes + // on "preliminary end of data". + LoadIncrementally, + // Load images only if all data have been received + LoadComplete }; + + ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target); + + enum ReadResult { ReadEOF, ReadFailed, ReadPartial, ReadComplete }; + + // Append data and read out all images. Returns the result + // of the last read operation, so, even if ReadPartial is returned, + // a few images might have been read. + ReadResult read(bool allDataReceived); + + QImageReader *reader() { return &m_reader; } + +private: + enum IncrementalReadResult { IncrementalReadFailed, IncrementalReadPartial, IncrementalReadComplete }; + // Incrementally read an image + IncrementalReadResult readImageLines(ImageData &); + + const LoadMode m_loadMode; + + QByteArray m_data; + QBuffer m_buffer; + QImageReader m_reader; + + ImageList &m_target; + + // Detected data format of the stream + enum QImage::Format m_dataFormat; + QSize m_size; + +}; + +ImageDecoderQt::ReadContext::ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target) + : m_loadMode(loadMode) + , m_data(data.data(), data.size()) + , m_buffer(&m_data) + , m_reader(&m_buffer) + , m_target(target) + , m_dataFormat(QImage::Format_Invalid) +{ + m_buffer.open(QIODevice::ReadOnly); +} + + +ImageDecoderQt::ReadContext::ReadResult + ImageDecoderQt::ReadContext::read(bool allDataReceived) +{ + // Complete mode: Read only all all data received + if (m_loadMode == LoadComplete && !allDataReceived) + return ReadPartial; + + // Attempt to read out all images + while (true) { + if (m_target.empty() || m_target.back().m_imageState == ImageComplete) { + // Start a new image. + if (!m_reader.canRead()) + return ReadEOF; + + // Attempt to construct an empty image of the matching size and format + // for efficient reading + QImage newImage = m_dataFormat != QImage::Format_Invalid ? + QImage(m_size,m_dataFormat) : QImage(); + m_target.push_back(ImageData(newImage)); + } + + // read chunks + switch (readImageLines(m_target.back())) { + case IncrementalReadFailed: + m_target.pop_back(); + return ReadFailed; + case IncrementalReadPartial: + return ReadPartial; + case IncrementalReadComplete: + m_target.back().m_imageState = ImageComplete; + //store for next + m_dataFormat = m_target.back().m_image.format(); + m_size = m_target.back().m_image.size(); + const bool supportsAnimation = m_reader.supportsAnimation(); + + if (debugImageDecoderQt) + qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size << " format " << m_dataFormat + << " supportsAnimation=" << supportsAnimation ; + // No point in readinfg further + if (!supportsAnimation) + return ReadComplete; + + break; + } + } + return ReadComplete; +} + + + +ImageDecoderQt::ReadContext::IncrementalReadResult + ImageDecoderQt::ReadContext::readImageLines(ImageData &imageData) +{ + // TODO: Implement incremental reading here, + // set state to reflect complete header, etc. + // For now, we read the whole image. + + const qint64 startPos = m_buffer.pos (); + // Oops, failed. Rewind. + if (!m_reader.read(&imageData.m_image)) { + m_buffer.seek(startPos); + const bool gotHeader = imageData.m_image.size().width(); + + if (debugImageDecoderQt) + qDebug() << "readImageLines(): read() failed: " << m_reader.errorString() + << " got header=" << gotHeader; + // [Experimental] Did we manage to read the header? + if (gotHeader) { + imageData.m_imageState = ImageHeaderValid; + return IncrementalReadPartial; + } + return IncrementalReadFailed; + } + imageData.m_duration = m_reader.nextImageDelay(); + return IncrementalReadComplete; +} + + +// ImageDecoderQt +ImageDecoderQt::ImageDecoderQt( ) +{ +} + +ImageDecoderQt::~ImageDecoderQt() +{ +} + +bool ImageDecoderQt::hasFirstImageHeader() const +{ + return !m_imageList.empty() && m_imageList[0].m_imageState >= ImageHeaderValid; +} + +void ImageDecoderQt::reset() +{ + m_failed = false; + m_imageList.clear(); + m_pixmapCache.clear(); + m_sizeAvailable = false; + m_loopCount = cAnimationNone; + m_size = IntSize(-1, -1); +} + +void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) +{ + reset(); + ReadContext readContext(data, ReadContext::LoadIncrementally, m_imageList); + + if (debugImageDecoderQt) + qDebug() << " setData " << data.size() << " image bytes, complete=" << allDataReceived; + + const ReadContext::ReadResult readResult = readContext.read(allDataReceived); + + if (debugImageDecoderQt) + qDebug() << " read returns " << readResult; + + switch ( readResult) { + case ReadContext::ReadFailed: + m_failed = true; + break; + case ReadContext::ReadEOF: + case ReadContext::ReadPartial: + case ReadContext::ReadComplete: + // Did we read anything - try to set the size. + if (hasFirstImageHeader()) { + m_sizeAvailable = true; + m_size = m_imageList[0].m_image.size(); + + if (readContext.reader()->supportsAnimation()) { + if (readContext.reader()->loopCount() != -1) + m_loopCount = readContext.reader()->loopCount(); + else + m_loopCount = 0; //loop forever + } + } + break; + } +} + + +bool ImageDecoderQt::isSizeAvailable() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << m_sizeAvailable; + return m_sizeAvailable; +} + +int ImageDecoderQt::frameCount() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size(); + return m_imageList.size(); +} + + +int ImageDecoderQt::repetitionCount() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::repetitionCount() returns" << m_loopCount; + return m_loopCount; +} + + +bool ImageDecoderQt::supportsAlpha() const +{ + return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel(); +} + +int ImageDecoderQt::duration(size_t index) const +{ + if (index >= m_imageList.size()) + return 0; + return m_imageList[index].m_duration; +} + +RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) +{ + Q_ASSERT("use imageAtIndex instead"); + return 0; +} + +QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const +{ + if (debugImageDecoderQt) + qDebug() << "ImageDecoderQt::imageAtIndex(" << index << ')'; + + if (index >= m_imageList.size()) + return 0; + + if (!m_pixmapCache.contains(index)) { + m_pixmapCache.insert(index, + QPixmap::fromImage(m_imageList[index].m_image)); + } + return &m_pixmapCache[index]; +} + +void ImageDecoderQt::clearFrame(size_t index) +{ + if (m_imageList.size() < (int)index) + m_imageList[index].m_image = QImage(); + m_pixmapCache.take(index); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h new file mode 100644 index 0000000..32f91d1 --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com> + * Copyright (C) 2006 Trolltech ASA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageDecoderQt_h +#define ImageDecoderQt_h + +#include "ImageDecoder.h" +#include <QtGui/QImage> +#include <QtGui/QPixmap> +#include <QtCore/QList> +#include <QtCore/QHash> + +namespace WebCore { + + +class ImageDecoderQt : public ImageDecoder +{ + ImageDecoderQt(const ImageDecoderQt&); + ImageDecoderQt &operator=(const ImageDecoderQt&); +public: + ImageDecoderQt(); + ~ImageDecoderQt(); + + typedef Vector<char> IncomingData; + + virtual void setData(const IncomingData& data, bool allDataReceived); + + virtual bool isSizeAvailable() const; + + virtual int frameCount() const; + + + virtual int repetitionCount() const; + + + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + QPixmap* imageAtIndex(size_t index) const; + + virtual bool supportsAlpha() const; + + int duration(size_t index) const; + + void clearFrame(size_t index); +private: + class ReadContext; + void reset(); + bool hasFirstImageHeader() const; + + enum ImageState { + // Started image reading + ImagePartial, + // Header (size / alpha) are known + ImageHeaderValid, + // Image is complete + ImageComplete }; + + struct ImageData { + ImageData(const QImage& image, ImageState imageState = ImagePartial, int duration=0); + QImage m_image; + ImageState m_imageState; + int m_duration; + }; + + typedef QList<ImageData> ImageList; + ImageList m_imageList; + mutable QHash<int, QPixmap> m_pixmapCache; + int m_loopCount; +}; + + + +} + +#endif + diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp new file mode 100644 index 0000000..206aee3 --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" + +#include "BitmapImage.h" +#include "FloatRect.h" +#include "PlatformString.h" +#include "GraphicsContext.h" +#include "AffineTransform.h" +#include "NotImplemented.h" +#include "qwebsettings.h" + +#include <QPixmap> +#include <QPainter> +#include <QImage> +#include <QImageReader> +#if QT_VERSION >= 0x040300 +#include <QTransform> +#endif + +#include <QDebug> + +#include <math.h> + +// This function loads resources into WebKit +static QPixmap loadResourcePixmap(const char *name) +{ + const QString resource = name; + + QPixmap pixmap; + if (resource == "missingImage") + pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic); + else if (resource == "nullPlugin") + pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic); + else if (resource == "urlIcon") + pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFaviconGraphic); + else if (resource == "textAreaResizeCorner") + pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaResizeCornerGraphic); + + return pixmap; +} + +namespace WebCore { + +void FrameData::clear() +{ + if (m_frame) { + m_frame = 0; + m_duration = 0.0f; + m_hasAlpha = true; + } +} + + + +// ================================================ +// Image Class +// ================================================ + +Image* Image::loadPlatformResource(const char* name) +{ + BitmapImage* img = new BitmapImage(loadResourcePixmap(name)); + return img; +} + + +void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + 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) +{ + QPixmap* image = nativeImageForCurrentFrame(); + if (!image) + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(ctxt, dst, solidColor(), op); + return; + } + + IntSize selfSize = size(); + + ctxt->save(); + + // Set the compositing operation. + ctxt->setCompositeOperation(op); + + QPainter* painter(ctxt->platformContext()); + + // Test using example site at + // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html + painter->drawPixmap(dst, *image, src); + + ctxt->restore(); + + startAnimation(); +} + +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + QPixmap* framePixmap = nativeImageForCurrentFrame(); + if (!framePixmap) // If it's too early we won't have an image yet. + return; + + QPixmap pixmap = *framePixmap; + QRect tr = QRectF(tileRect).toRect(); + if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height()) { + pixmap = pixmap.copy(tr); + } + + 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(); + } +} + +void BitmapImage::checkForSolidColor() +{ + // FIXME: It's easy to implement this optimization. Just need to check the RGBA32 buffer to see if it is 1x1. + m_isSolidColor = false; +} + +QPixmap* BitmapImage::getPixmap() const +{ + if (!m_pixmap) + return const_cast<BitmapImage*>(this)->frameAtIndex(0); + else + return m_pixmap; +} + +} + + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp new file mode 100644 index 0000000..84d503f --- /dev/null +++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Trolltech ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageSource.h" +#include "ImageDecoderQt.h" +#include "SharedBuffer.h" + +#include <QImage> +#include <qdebug.h> + + +namespace WebCore { + enum ImageFormat { ImageFormat_None, ImageFormat_GIF, ImageFormat_PNG, ImageFormat_JPEG, + ImageFormat_BMP, ImageFormat_ICO, ImageFormat_XBM }; + +ImageFormat detectImageFormat(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; +} + +ImageDecoderQt* createDecoder(const SharedBuffer& data) { + if (detectImageFormat(data) != ImageFormat_None) + return new ImageDecoderQt(); + return 0; +} + +ImageSource::ImageSource() + : m_decoder(0) +{ +} + +ImageSource::~ImageSource() +{ + delete m_decoder; +} + +bool ImageSource::initialized() const +{ + return m_decoder; +} + +void ImageSource::setData(SharedBuffer* data, bool allDataReceived) +{ + // Make the decoder by sniffing the bytes. + // This method will examine the data and instantiate an instance of the appropriate decoder plugin. + // If insufficient bytes are available to determine the image type, no decoder plugin will be + // made. + if (!m_decoder) + m_decoder = createDecoder(*data); + + if (!m_decoder) + return; + + m_decoder->setData(data->buffer(), allDataReceived); +} + +bool ImageSource::isSizeAvailable() +{ + if (!m_decoder) + return false; + + return m_decoder->isSizeAvailable(); +} + +IntSize ImageSource::size() const +{ + if (!m_decoder) + return IntSize(); + + return m_decoder->size(); +} + +int ImageSource::repetitionCount() +{ + if (!m_decoder) + return cAnimationNone; + + return m_decoder->repetitionCount(); +} + +size_t ImageSource::frameCount() const +{ + if (!m_decoder) + return 0; + + return m_decoder->frameCount(); +} + +NativeImagePtr ImageSource::createFrameAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + return m_decoder->imageAtIndex(index); +} + +float ImageSource::frameDurationAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + // Many annoying ads specify a 0 duration to make an image flash as quickly + // as possible. We follow WinIE's behavior and use a duration of 100 ms + // for any frames that specify a duration of <= 50 ms. See + // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for + // more. + const float duration = m_decoder->duration(index) / 1000.0f; + return (duration < 0.051f) ? 0.100f : duration; +} + +bool ImageSource::frameHasAlphaAtIndex(size_t index) +{ + if (!m_decoder || !m_decoder->supportsAlpha()) + return false; + + const QPixmap* source = m_decoder->imageAtIndex( index); + if (!source) + return false; + + return source->hasAlphaChannel(); +} + +bool ImageSource::frameIsCompleteAtIndex(size_t index) +{ + return (m_decoder && m_decoder->imageAtIndex(index) != 0); +} + +void ImageSource::clear() +{ + delete m_decoder; + m_decoder = 0; +} + + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/IntPointQt.cpp b/WebCore/platform/graphics/qt/IntPointQt.cpp new file mode 100644 index 0000000..f9d336a --- /dev/null +++ b/WebCore/platform/graphics/qt/IntPointQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntPoint.h" + +#include <QPoint> + +namespace WebCore { + +IntPoint::IntPoint(const QPoint& p) + : m_x(p.x()) + , m_y(p.y()) +{ +} + +IntPoint::operator QPoint() const +{ + return QPoint(m_x, m_y); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/IntRectQt.cpp b/WebCore/platform/graphics/qt/IntRectQt.cpp new file mode 100644 index 0000000..ccc153e --- /dev/null +++ b/WebCore/platform/graphics/qt/IntRectQt.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntRect.h" + +#include <QRect> + +namespace WebCore { + +IntRect::IntRect(const QRect& r) + : m_location(r.topLeft()) + , m_size(r.width(), r.height()) +{ +} + +IntRect::operator QRect() const +{ + return QRect(x(), y(), width(), height()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/IntSizeQt.cpp b/WebCore/platform/graphics/qt/IntSizeQt.cpp new file mode 100644 index 0000000..4f2bf35 --- /dev/null +++ b/WebCore/platform/graphics/qt/IntSizeQt.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <QSize> + +#include "IntSize.h" + +namespace WebCore { + +IntSize::IntSize(const QSize& r) + : m_width(r.width()) + , m_height(r.height()) +{ +} + +IntSize::operator QSize() const +{ + return QSize(width(), height()); +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp new file mode 100644 index 0000000..240350f --- /dev/null +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * 2006 Rob Buis <buis@kde.org> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Path.h" + +#include "FloatRect.h" +#include "PlatformString.h" +#include "AffineTransform.h" +#include <QPainterPath> +#include <QMatrix> +#include <QString> + +#define _USE_MATH_DEFINES +#include <math.h> + +namespace WebCore { + +Path::Path() + : m_path(new QPainterPath()) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path::Path(const Path& other) + : m_path(new QPainterPath(*other.platformPath())) +{ +} + +Path& Path::operator=(const Path& other) +{ + if (&other != this) { + delete m_path; + m_path = new QPainterPath(*other.platformPath()); + } + + return *this; +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + Qt::FillRule savedRule = m_path->fillRule(); + m_path->setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); + + bool contains = m_path->contains(point); + + m_path->setFillRule(savedRule); + return contains; +} + +void Path::translate(const FloatSize& size) +{ + QMatrix matrix; + matrix.translate(size.width(), size.height()); + *m_path = (*m_path) * matrix; +} + +FloatRect Path::boundingRect() const +{ + return m_path->boundingRect(); +} + +void Path::moveTo(const FloatPoint& point) +{ + m_path->moveTo(point); +} + +void Path::addLineTo(const FloatPoint& p) +{ + m_path->lineTo(p); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + m_path->quadTo(cp, p); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + m_path->cubicTo(cp1, cp2, p); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + //FIXME: busted + qWarning("arcTo is busted"); + m_path->arcTo(p1.x(), p1.y(), p2.x(), p2.y(), radius, 90); +} + +void Path::closeSubpath() +{ + m_path->closeSubpath(); +} + +#define DEGREES(t) ((t) * 180.0 / M_PI) +void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise) +{ + qreal xc = p.x(); + qreal yc = p.y(); + qreal radius = r; + + + //### HACK + // In Qt we don't switch the coordinate system for degrees + // and still use the 0,0 as bottom left for degrees so we need + // to switch + sar = -sar; + ear = -ear; + anticlockwise = !anticlockwise; + //end hack + + float sa = DEGREES(sar); + float ea = DEGREES(ear); + + double span = 0; + + double xs = xc - radius; + double ys = yc - radius; + double width = radius*2; + double height = radius*2; + + if (!anticlockwise && (ea < sa)) + span += 360; + else if (anticlockwise && (sa < ea)) + span -= 360; + + // this is also due to switched coordinate system + // we would end up with a 0 span instead of 360 + if (!(qFuzzyCompare(span + (ea - sa), 0.0) && + qFuzzyCompare(qAbs(span), 360.0))) { + span += ea - sa; + } + + m_path->moveTo(QPointF(xc + radius * cos(sar), + yc - radius * sin(sar))); + + m_path->arcTo(xs, ys, width, height, sa, span); +} + +void Path::addRect(const FloatRect& r) +{ + m_path->addRect(r.x(), r.y(), r.width(), r.height()); +} + +void Path::addEllipse(const FloatRect& r) +{ + m_path->addEllipse(r.x(), r.y(), r.width(), r.height()); +} + +void Path::clear() +{ + *m_path = QPainterPath(); +} + +bool Path::isEmpty() const +{ + return m_path->isEmpty(); +} + +String Path::debugString() const +{ + QString ret; + for (int i = 0; i < m_path->elementCount(); ++i) { + const QPainterPath::Element &cur = m_path->elementAt(i); + + switch (cur.type) { + case QPainterPath::MoveToElement: + ret += QString("M %1 %2").arg(cur.x).arg(cur.y); + break; + case QPainterPath::LineToElement: + ret += QString("L %1 %2").arg(cur.x).arg(cur.y); + break; + case QPainterPath::CurveToElement: + { + const QPainterPath::Element &c1 = m_path->elementAt(i + 1); + const QPainterPath::Element &c2 = m_path->elementAt(i + 2); + + Q_ASSERT(c1.type == QPainterPath::CurveToDataElement); + Q_ASSERT(c2.type == QPainterPath::CurveToDataElement); + + ret += QString("C %1 %2 %3 %4 %5 %6").arg(cur.x).arg(cur.y).arg(c1.x).arg(c1.y).arg(c2.x).arg(c2.y); + + i += 2; + break; + } + case QPainterPath::CurveToDataElement: + Q_ASSERT(false); + break; + } + } + + return ret; +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + PathElement pelement; + FloatPoint points[3]; + pelement.points = points; + for (int i = 0; i < m_path->elementCount(); ++i) { + const QPainterPath::Element& cur = m_path->elementAt(i); + + switch (cur.type) { + case QPainterPath::MoveToElement: + pelement.type = PathElementMoveToPoint; + pelement.points[0] = QPointF(cur); + function(info, &pelement); + break; + case QPainterPath::LineToElement: + pelement.type = PathElementAddLineToPoint; + pelement.points[0] = QPointF(cur); + function(info, &pelement); + break; + case QPainterPath::CurveToElement: + { + const QPainterPath::Element& c1 = m_path->elementAt(i + 1); + const QPainterPath::Element& c2 = m_path->elementAt(i + 2); + + Q_ASSERT(c1.type == QPainterPath::CurveToDataElement); + Q_ASSERT(c2.type == QPainterPath::CurveToDataElement); + + pelement.type = PathElementAddCurveToPoint; + pelement.points[0] = QPointF(cur); + pelement.points[1] = QPointF(c1); + pelement.points[2] = QPointF(c2); + function(info, &pelement); + + i += 2; + break; + } + case QPainterPath::CurveToDataElement: + Q_ASSERT(false); + } + } +} + +void Path::transform(const AffineTransform& transform) +{ + if (m_path) { + QMatrix mat = transform; + QPainterPath temp = mat.map(*m_path); + delete m_path; + m_path = new QPainterPath(temp); + } +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp new file mode 100644 index 0000000..1a45ce4 --- /dev/null +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -0,0 +1,51 @@ +/* + Copyright (C) 2007 Trolltech ASA + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + This class provides all functionality needed for loading images, style sheets and html + pages from the web. It has a memory cache for these objects. +*/ +#include "config.h" +#include "SimpleFontData.h" + +namespace WebCore { + +SimpleFontData::SimpleFontData(const FontPlatformData& font, bool customFont, bool loading, SVGFontData*) + : m_font(font), m_isCustomFont(customFont), m_isLoading(loading) +{ +} + +SimpleFontData::~SimpleFontData() +{ +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + return true; +} + +const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const +{ + return this; +} + +bool SimpleFontData::isSegmented() const +{ + return false; +} + +} diff --git a/WebCore/platform/graphics/win/ColorSafari.cpp b/WebCore/platform/graphics/win/ColorSafari.cpp new file mode 100644 index 0000000..e7fbf47 --- /dev/null +++ b/WebCore/platform/graphics/win/ColorSafari.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +#include "NotImplemented.h" +#include <CoreGraphics/CGColor.h> +#include <SafariTheme/SafariTheme.h> +#include <wtf/Assertions.h> +#include <wtf/RetainPtr.h> + +using namespace SafariTheme; + +namespace WebCore { + +typedef CGColorRef (APIENTRY*stCopyThemeColorPtr)(unsigned, SafariTheme::ThemeControlState); +static const unsigned stFocusRingColorID = 4; + +static const unsigned aquaFocusRingColor = 0xFF7DADD9; + +static RGBA32 makeRGBAFromCGColor(CGColorRef c) +{ + const CGFloat* components = CGColorGetComponents(c); + return makeRGBA(255 * components[0], 255 * components[1], 255 * components[2], 255 * components[3]); +} + +Color focusRingColor() +{ + static Color focusRingColor; + focusRingColor.isValid(); + + if (!focusRingColor.isValid()) { + if (HMODULE module = LoadLibrary(SAFARITHEMEDLL)) + if (stCopyThemeColorPtr stCopyThemeColor = (stCopyThemeColorPtr)GetProcAddress(module, "STCopyThemeColor")) { + RetainPtr<CGColorRef> c(AdoptCF, stCopyThemeColor(stFocusRingColorID, SafariTheme::ActiveState)); + focusRingColor = makeRGBAFromCGColor(c.get()); + } + if (!focusRingColor.isValid()) + focusRingColor = aquaFocusRingColor; + } + + return focusRingColor; +} + +void setFocusRingColorChangeFunction(void (*)()) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp new file mode 100644 index 0000000..8b59a48 --- /dev/null +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "GlyphBuffer.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "SimpleFontData.h" +#include "UniscribeController.h" +#include <ApplicationServices/ApplicationServices.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#include <wtf/MathExtras.h> + +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 +{ + 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; + + // 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]; + } + + // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. + 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()); + + // Set the correct color. + HDC textDrawingDC = hdc; + SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); + + SetBkMode(hdc, TRANSPARENT); + SetTextAlign(hdc, TA_LEFT | TA_BASELINE); + + // Uniscribe gives us offsets to help refine the positioning of combining glyphs. + FloatSize translation = glyphBuffer.offsetAt(from); + if (translation.width() || translation.height()) { + XFORM xform; + xform.eM11 = 1.0; + xform.eM12 = 0; + xform.eM21 = 0; + xform.eM22 = 1.0; + xform.eDx = translation.width(); + xform.eDy = translation.height(); + ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); + } + ExtTextOut(hdc, point.x(), point.y(), ETO_GLYPH_INDEX, 0, (WCHAR*)glyphBuffer.glyphs(from), numGlyphs, gdiAdvances.data()); + + graphicsContext->releaseWindowsContext(hdc, textRect); + return; + } + + CGContextRef cgContext = graphicsContext->platformContext(); + + uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext); + + const FontPlatformData& platformData = font->platformData(); + + CGContextSetFont(cgContext, platformData.cgFont()); + + CGAffineTransform matrix = CGAffineTransformIdentity; + matrix.b = -matrix.b; + matrix.d = -matrix.d; + + if (platformData.syntheticOblique()) { + static float skew = -tanf(syntheticObliqueAngle * acosf(0) / 90.0f); + matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0)); + } + + // 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()); + CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + if (font->m_syntheticBoldOffset) { + CGContextSetTextPosition(cgContext, point.x() + font->m_syntheticBoldOffset, point.y()); + CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); + } + + wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); +} + +} diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp new file mode 100644 index 0000000..1ee6818 --- /dev/null +++ b/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include <winsock2.h> +#include "FontCache.h" +#include "Font.h" +#include "SimpleFontData.h" +#include "StringHash.h" +#include "UnicodeRange.h" +#include <windows.h> +#include <mlang.h> +#if PLATFORM(CG) +#include <ApplicationServices/ApplicationServices.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#endif + +using std::min; + +namespace WebCore +{ + +void FontCache::platformInit() +{ +#if PLATFORM(CG) + wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac. +#endif +} + +IMLangFontLink2* FontCache::getFontLinkInterface() +{ + static IMultiLanguage *multiLanguage; + if (!multiLanguage) { + if (CoCreateInstance(CLSID_CMultiLanguage, 0, CLSCTX_ALL, IID_IMultiLanguage, (void**)&multiLanguage) != S_OK) + return 0; + } + + static IMLangFontLink2* langFontLink; + if (!langFontLink) { + if (multiLanguage->QueryInterface(&langFontLink) != S_OK) + return 0; + } + + return langFontLink; +} + +static int CALLBACK metaFileEnumProc(HDC hdc, HANDLETABLE* table, CONST ENHMETARECORD* record, int tableEntries, LPARAM logFont) +{ + if (record->iType == EMR_EXTCREATEFONTINDIRECTW) { + const EMREXTCREATEFONTINDIRECTW* createFontRecord = reinterpret_cast<const EMREXTCREATEFONTINDIRECTW*>(record); + *reinterpret_cast<LOGFONT*>(logFont) = createFontRecord->elfw.elfLogFont; + } + return true; +} + +static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont) +{ + *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont); + return false; +} + +static const Vector<String>* getLinkedFonts(String& family) +{ + static HashMap<String, Vector<String>*> systemLinkMap; + Vector<String>* result = systemLinkMap.get(family); + if (result) + return result; + + result = new Vector<String>; + systemLinkMap.set(family, result); + HKEY fontLinkKey; + if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey))) + return result; + + DWORD linkedFontsBufferSize = 0; + RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, NULL, &linkedFontsBufferSize); + WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize)); + if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize))) { + unsigned i = 0; + unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts); + while (i < length) { + while (i < length && linkedFonts[i] != ',') + i++; + i++; + unsigned j = i; + while (j < length && linkedFonts[j]) + j++; + result->append(String(linkedFonts + i, j - i)); + i = j + 1; + } + } + free(linkedFonts); + RegCloseKey(fontLinkKey); + return result; +} + +static const Vector<DWORD, 4>& getCJKCodePageMasks() +{ + // The default order in which we look for a font for a CJK character. If the user's default code page is + // one of these, we will use it first. + static const UINT CJKCodePages[] = { + 932, /* Japanese */ + 936, /* Simplified Chinese */ + 950, /* Traditional Chinese */ + 949 /* Korean */ + }; + + static Vector<DWORD, 4> codePageMasks; + static bool initialized; + if (!initialized) { + initialized = true; + IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface(); + if (!langFontLink) + return codePageMasks; + + UINT defaultCodePage; + DWORD defaultCodePageMask = 0; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage))) + langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask); + + if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3]) + codePageMasks.append(defaultCodePageMask); + for (unsigned i = 0; i < 4; ++i) { + if (defaultCodePage != CJKCodePages[i]) { + DWORD codePageMask; + langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask); + codePageMasks.append(codePageMask); + } + } + } + return codePageMasks; +} + +static bool currentFontContainsCharacter(HDC hdc, UChar character) +{ + static Vector<char, 512> glyphsetBuffer; + glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); + GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data()); + GetFontUnicodeRanges(hdc, glyphset); + + // FIXME: Change this to a binary search. + unsigned i = 0; + while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character) + i++; + + return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > character; +} + +static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0) +{ + HFONT MLangFont; + HFONT hfont = 0; + if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont)) && MLangFont) { + LOGFONT lf; + GetObject(MLangFont, sizeof(LOGFONT), &lf); + langFontLink->ReleaseFont(MLangFont); + hfont = CreateFontIndirect(&lf); + } + return hfont; +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + UChar character = characters[0]; + SimpleFontData* fontData = 0; + HDC hdc = GetDC(0); + HFONT primaryFont = font.primaryFont()->fontDataForCharacter(character)->platformData().hfont(); + HGDIOBJ oldFont = SelectObject(hdc, primaryFont); + HFONT hfont = 0; + + if (IMLangFontLink2* langFontLink = getFontLinkInterface()) { + // Try MLang font linking first. + DWORD codePages = 0; + langFontLink->GetCharCodePages(character, &codePages); + + if (codePages && findCharUnicodeRange(character) == cRangeSetCJK) { + // The CJK character may belong to multiple code pages. We want to + // do font linking against a single one of them, preferring the default + // code page for the user's locale. + const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks(); + unsigned numCodePages = CJKCodePageMasks.size(); + for (unsigned i = 0; i < numCodePages && !hfont; ++i) { + hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]); + if (hfont && !(codePages & CJKCodePageMasks[i])) { + // We asked about a code page that is not one of the code pages + // returned by MLang, so the font might not contain the character. + SelectObject(hdc, hfont); + if (!currentFontContainsCharacter(hdc, character)) { + DeleteObject(hfont); + hfont = 0; + } + SelectObject(hdc, primaryFont); + } + } + } else + hfont = createMLangFont(langFontLink, hdc, codePages, character); + } + + // A font returned from MLang is trusted to contain the character. + bool containsCharacter = hfont; + + if (!hfont) { + // To find out what font Uniscribe would use, we make it draw into a metafile and intercept + // calls to CreateFontIndirect(). + HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL); + SelectObject(metaFileDc, primaryFont); + + bool scriptStringOutSucceeded = false; + SCRIPT_STRING_ANALYSIS ssa; + + // FIXME: If length is greater than 1, we actually return the font for the last character. + // This function should be renamed getFontDataForCharacter and take a single 32-bit character. + if (SUCCEEDED(ScriptStringAnalyse(metaFileDc, characters, length, 0, -1, SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK, + 0, NULL, NULL, NULL, NULL, NULL, &ssa))) { + scriptStringOutSucceeded = SUCCEEDED(ScriptStringOut(ssa, 0, 0, 0, NULL, 0, 0, FALSE)); + ScriptStringFree(&ssa); + } + HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDc); + if (scriptStringOutSucceeded) { + LOGFONT logFont; + logFont.lfFaceName[0] = 0; + EnumEnhMetaFile(0, metaFile, metaFileEnumProc, &logFont, NULL); + if (logFont.lfFaceName[0]) + hfont = CreateFontIndirect(&logFont); + } + DeleteEnhMetaFile(metaFile); + } + + String familyName; + const Vector<String>* linkedFonts = 0; + unsigned linkedFontIndex = 0; + while (hfont) { + SelectObject(hdc, hfont); + WCHAR name[LF_FACESIZE]; + GetTextFace(hdc, LF_FACESIZE, name); + familyName = name; + + if (containsCharacter || currentFontContainsCharacter(hdc, character)) + break; + + if (!linkedFonts) + linkedFonts = getLinkedFonts(familyName); + SelectObject(hdc, oldFont); + DeleteObject(hfont); + hfont = 0; + + if (linkedFonts->size() <= linkedFontIndex) + break; + + LOGFONT logFont; + logFont.lfCharSet = DEFAULT_CHARSET; + memcpy(logFont.lfFaceName, linkedFonts->at(linkedFontIndex).characters(), linkedFonts->at(linkedFontIndex).length() * sizeof(WCHAR)); + logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0; + EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<LPARAM>(&hfont), 0); + linkedFontIndex++; + } + + if (hfont) { + if (!familyName.isEmpty()) { + FontPlatformData* result = getCachedFontPlatformData(font.fontDescription(), familyName); + if (result) + fontData = getCachedFontData(result); + } + + SelectObject(hdc, oldFont); + DeleteObject(hfont); + } + + ReleaseDC(0, hdc); + return fontData; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) +{ + // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick + // the default that the user would get without changing any prefs. + static AtomicString timesStr("Times New Roman"); + return getCachedFontPlatformData(fontDescription, timesStr); +} + +bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family) +{ + 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; +#else + winfont.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); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + bool isLucidaGrande = false; + static AtomicString lucidaStr("Lucida Grande"); + if (equalIgnoringCase(family, lucidaStr)) + isLucidaGrande = true; + + bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande; + + 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); + return 0; + } + + FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), + fontDescription.bold(), fontDescription.italic(), useGDI); + +#if PLATFORM(CG) + bool fontCreationFailed = !result->cgFont(); +#elif PLATFORM(CAIRO) + bool fontCreationFailed = !result->fontFace(); +#endif + + if (fontCreationFailed) { + // The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make + // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next + // font. + delete result; + DeleteObject(hfont); + return 0; + } + + return result; +} + +} + diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp new file mode 100644 index 0000000..cf03502 --- /dev/null +++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include <wtf/RetainPtr.h> +#include <ApplicationServices/ApplicationServices.h> +#include "SharedBuffer.h" +#include "FontPlatformData.h" + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ + CGFontRelease(m_cgFont); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic) +{ + return FontPlatformData(m_cgFont, size, bold, italic); +} + +const void* getData(void* info) +{ + SharedBuffer* buffer = static_cast<SharedBuffer*>(info); + buffer->ref(); + return (void*)buffer->data(); +} + +void releaseData(void* info, const void* data) +{ + static_cast<SharedBuffer*>(info)->deref(); +} + +size_t getBytesWithOffset(void *info, void* buffer, size_t offset, size_t count) +{ + SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); + size_t availBytes = count; + if (offset + count > sharedBuffer->size()) + availBytes -= (offset + count) - sharedBuffer->size(); + memcpy(buffer, sharedBuffer->data() + offset, availBytes); + return availBytes; +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + // Get CG to create the font. + CGDataProviderDirectAccessCallbacks callbacks = { &getData, &releaseData, &getBytesWithOffset, NULL }; + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirectAccess(buffer, buffer->size(), &callbacks)); + CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider.get()); + if (!cgFont) + return 0; + return new FontCustomPlatformData(cgFont); +} + +} diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.h b/WebCore/platform/graphics/win/FontCustomPlatformData.h new file mode 100644 index 0000000..909b79e --- /dev/null +++ b/WebCore/platform/graphics/win/FontCustomPlatformData.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 FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include <wtf/Noncopyable.h> + +typedef struct CGFont* CGFontRef; + +namespace WebCore { + +class FontPlatformData; +class SharedBuffer; + +struct FontCustomPlatformData : Noncopyable { + FontCustomPlatformData(CGFontRef cgFont) + : m_cgFont(cgFont) + { + } + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic); + + CGFontRef m_cgFont; +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); + +} + +#endif diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp new file mode 100644 index 0000000..e54d85a --- /dev/null +++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007, 2008 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformDataCairo.h" + +#include "SharedBuffer.h" +#include "FontPlatformData.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +FontCustomPlatformDataCairo::~FontCustomPlatformDataCairo() +{ + cairo_font_face_destroy(m_fontFace); +} + +FontPlatformData FontCustomPlatformDataCairo::fontPlatformData(int size, bool bold, bool italic) +{ + return FontPlatformData(m_fontFace, size, bold, italic); +} + +static void releaseData(void* data) +{ + static_cast<SharedBuffer*>(data)->deref(); +} + +FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + buffer->ref(); + HFONT font = reinterpret_cast<HFONT>(buffer); + cairo_font_face_t* fontFace = cairo_win32_font_face_create_for_hfont(font); + if (!fontFace) + return 0; + + static cairo_user_data_key_t bufferKey; + cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData); + + return new FontCustomPlatformDataCairo(fontFace); +} + +} diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h new file mode 100644 index 0000000..87794b5 --- /dev/null +++ b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontCustomPlatformDataCairo_h +#define FontCustomPlatformDataCairo_h + +#include <wtf/Noncopyable.h> + +#include <cairo.h> + +namespace WebCore { + +class FontPlatformData; +class SharedBuffer; + +struct FontCustomPlatformDataCairo : Noncopyable { + FontCustomPlatformDataCairo(cairo_font_face_t* fontFace) + : m_fontFace(fontFace) + { + } + ~FontCustomPlatformDataCairo(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic); + + cairo_font_face_t* m_fontFace; +}; + +FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer*); + +} + +#endif diff --git a/WebCore/platform/graphics/win/FontDatabase.cpp b/WebCore/platform/graphics/win/FontDatabase.cpp new file mode 100644 index 0000000..1308ff0 --- /dev/null +++ b/WebCore/platform/graphics/win/FontDatabase.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontDatabase.h" + +#include "CString.h" +#include "FileSystem.h" +#include "PlatformString.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#include <shlobj.h> +#include <wtf/RetainPtr.h> + +namespace WebCore { + +static String systemFontsDirectory() +{ + static bool initialized; + static String directory; + + if (!initialized) { + initialized = true; + + Vector<UChar> buffer(MAX_PATH); + if (FAILED(SHGetFolderPath(0, CSIDL_FONTS | CSIDL_FLAG_CREATE, 0, 0, buffer.data()))) + return directory; + buffer.resize(wcslen(buffer.data())); + + directory = String::adopt(buffer); + } + + return directory; +} + +static String fontsPlistPath() +{ + static String path = pathByAppendingComponent(localUserSpecificStorageDirectory(), "FontsList.plist"); + return path; +} + +static bool systemHasFontsNewerThanFontsPlist() +{ + WIN32_FILE_ATTRIBUTE_DATA plistAttributes = {0}; + if (!GetFileAttributesEx(fontsPlistPath().charactersWithNullTermination(), GetFileExInfoStandard, &plistAttributes)) + return true; + + WIN32_FILE_ATTRIBUTE_DATA fontsDirectoryAttributes = {0}; + if (!GetFileAttributesEx(systemFontsDirectory().charactersWithNullTermination(), GetFileExInfoStandard, &fontsDirectoryAttributes)) + return true; + + return CompareFileTime(&plistAttributes.ftLastWriteTime, &fontsDirectoryAttributes.ftLastWriteTime) < 0; +} + +static RetainPtr<CFPropertyListRef> readFontPlist() +{ + CString plistPath = fontsPlistPath().utf8(); + + RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateFromFileSystemRepresentation(0, reinterpret_cast<const UInt8*>(plistPath.data()), plistPath.length(), false)); + if (!url) + return 0; + + RetainPtr<CFReadStreamRef> stream(AdoptCF, CFReadStreamCreateWithFile(0, url.get())); + if (!stream) + return 0; + + if (!CFReadStreamOpen(stream.get())) + return 0; + + CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0 | kCFPropertyListXMLFormat_v1_0; + RetainPtr<CFPropertyListRef> plist(AdoptCF, CFPropertyListCreateFromStream(0, stream.get(), 0, kCFPropertyListMutableContainersAndLeaves, &format, 0)); + + CFReadStreamClose(stream.get()); + + return plist; +} + +static bool populateFontDatabaseFromPlist() +{ + RetainPtr<CFPropertyListRef> plist = readFontPlist(); + if (!plist) + return false; + + RetainPtr<CFDataRef> data(AdoptCF, CFPropertyListCreateXMLData(0, plist.get())); + if (!data) + return false; + + wkAddFontsFromPlistRepresentation(data.get()); + return true; +} + +static bool populateFontDatabaseFromFileSystem() +{ + RetainPtr<CFStringRef> directory(AdoptCF, systemFontsDirectory().createCFString()); + if (!directory) + return false; + + wkAddFontsInDirectory(directory.get()); + return true; +} + +static void writeFontDatabaseToPlist() +{ + RetainPtr<CFDataRef> data(AdoptCF, wkCreateFontsPlistRepresentation()); + if (!data) + return; + + safeCreateFile(fontsPlistPath(), data.get()); +} + +void populateFontDatabase() +{ + static bool initialized; + if (initialized) + return; + initialized = true; + + if (!systemHasFontsNewerThanFontsPlist()) + if (populateFontDatabaseFromPlist()) + return; + + if (populateFontDatabaseFromFileSystem()) + writeFontDatabaseToPlist(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/win/FontDatabase.h b/WebCore/platform/graphics/win/FontDatabase.h new file mode 100644 index 0000000..4f76c9e --- /dev/null +++ b/WebCore/platform/graphics/win/FontDatabase.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontDatabase_h +#define FontDatabase_h + +namespace WebCore { + + void populateFontDatabase(); + +} // namespace WebCore + +#endif // !defined(FontDatabase_h) diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h new file mode 100644 index 0000000..5bbda2f --- /dev/null +++ b/WebCore/platform/graphics/win/FontPlatformData.h @@ -0,0 +1,137 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006, 2007, 2008 Apple Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontPlatformData_H +#define FontPlatformData_H + +#include "StringImpl.h" + +#if PLATFORM(CAIRO) +#include <cairo-win32.h> +#endif + +typedef struct HFONT__* HFONT; +typedef struct CGFont* CGFontRef; + +namespace WebCore { + +class FontDescription; + +class FontPlatformData +{ +public: + class Deleted {}; + + // Used for deleted values in the font cache's hash tables. + FontPlatformData(Deleted) + : m_font((HFONT)-1) +#if PLATFORM(CG) + , m_cgFont(0) +#elif PLATFORM(CAIRO) + , m_fontFace(0) +#endif + , m_size(0) + , m_syntheticBold(false) + , m_syntheticOblique(false) + , m_useGDI(false) + { + } + + FontPlatformData() + : m_font(0) +#if PLATFORM(CG) + , m_cgFont(0) +#elif PLATFORM(CAIRO) + , m_fontFace(0) +#endif + , m_size(0) + , m_syntheticBold(false) + , m_syntheticOblique(false) + , m_useGDI(false) + { + } + + FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI); + FontPlatformData(float size, bool bold, bool oblique); + +#if PLATFORM(CG) + FontPlatformData(CGFontRef, float size, bool bold, bool oblique); +#elif PLATFORM(CAIRO) + FontPlatformData(cairo_font_face_t*, float size, bool bold, bool oblique); +#endif + ~FontPlatformData(); + + void platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName); + + HFONT hfont() const { return m_font; } +#if PLATFORM(CG) + CGFontRef cgFont() const { return m_cgFont; } +#elif PLATFORM(CAIRO) + void setFont(cairo_t* ft) const; + cairo_font_face_t* fontFace() const { return m_fontFace; } + cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } +#endif + + float size() const { return m_size; } + void setSize(float size) { m_size = size; } + bool syntheticBold() const { return m_syntheticBold; } + bool syntheticOblique() const { return m_syntheticOblique; } + bool useGDI() const { return m_useGDI; } + + unsigned hash() const + { + return StringImpl::computeHash((UChar*)(&m_font), sizeof(HFONT) / sizeof(UChar)); + } + + bool operator==(const FontPlatformData& other) const + { + return m_font == other.m_font && +#if PLATFORM(CG) + m_cgFont == other.m_cgFont && +#elif PLATFORM(CAIRO) + m_fontFace == other.m_fontFace && + m_scaledFont == other.m_scaledFont && +#endif + m_size == other.m_size && + m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique && + m_useGDI == other.m_useGDI; + } + +private: + HFONT m_font; +#if PLATFORM(CG) + CGFontRef m_cgFont; +#elif PLATFORM(CAIRO) + cairo_font_face_t* m_fontFace; + cairo_scaled_font_t* m_scaledFont; +#endif + + float m_size; + bool m_syntheticBold; + bool m_syntheticOblique; + bool m_useGDI; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp new file mode 100644 index 0000000..ddd3104 --- /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 = CGFontCreateWithFontName(fullName.get()); + if (!m_cgFont) { + CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc); + if (postScriptName) { + m_cgFont = CGFontCreateWithFontName(postScriptName); + ASSERT(m_cgFont); + } + } +} + +FontPlatformData::FontPlatformData(CGFontRef font, float size, bool bold, bool oblique) + : m_font(0) + , m_size(size) + , m_cgFont(font) + , m_syntheticBold(bold) + , m_syntheticOblique(oblique) + , m_useGDI(false) +{ +} + +} diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp new file mode 100644 index 0000000..438d0a9 --- /dev/null +++ b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp @@ -0,0 +1,89 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006, 2007, 2008 Apple Inc. + * Copyright (C) 2007 Alp Toker + * Copyright (C) 2008 Brent Fulgham + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontPlatformData.h" + +#include "PlatformString.h" +#include "StringHash.h" +#include <wtf/HashMap.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> + +#include <cairo-win32.h> + +using std::min; + +namespace WebCore { + +void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName) +{ + m_fontFace = cairo_win32_font_face_create_for_hfont(font); + cairo_matrix_t sizeMatrix, ctm; + cairo_matrix_init_identity(&ctm); + cairo_matrix_init_scale(&sizeMatrix, size, size); + + static cairo_font_options_t* fontOptions = 0; + if (!fontOptions) + { + fontOptions = cairo_font_options_create(); + cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL); + } + + m_scaledFont = cairo_scaled_font_create(m_fontFace, &sizeMatrix, &ctm, fontOptions); +} + +FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool oblique) + : m_font(0) + , m_size(size) + , m_fontFace(fontFace) + , m_scaledFont(0) + , m_syntheticBold(bold) + , m_syntheticOblique(oblique) + , m_useGDI(false) +{ + cairo_matrix_t fontMatrix; + cairo_matrix_init_scale(&fontMatrix, size, size); + cairo_matrix_t ctm; + cairo_matrix_init_identity(&ctm); + cairo_font_options_t* options = cairo_font_options_create(); + + // We force antialiasing and disable hinting to provide consistent + // typographic qualities for custom fonts on all platforms. + cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); + + m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options); + cairo_font_options_destroy(options); +} + +void FontPlatformData::setFont(cairo_t* cr) const +{ + ASSERT(m_scaledFont); + + cairo_set_scaled_font(cr, m_scaledFont); +} + +} diff --git a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp new file mode 100644 index 0000000..f209dbf --- /dev/null +++ b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp @@ -0,0 +1,144 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006, 2007, 2008 Apple Inc. + * Copyright (C) 2008 Brent Fulgham + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontPlatformData.h" + +#include "PlatformString.h" +#include "StringHash.h" +#include <wtf/HashMap.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> + +using std::min; + +namespace WebCore { + +static const int Bold = (1 << 0); +static const int Italic = (1 << 1); +static const int BoldOblique = (1 << 2); + +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_size(size) +#if PLATFORM(CG) + , m_cgFont(0) +#elif PLATFORM(CAIRO) + , m_fontFace(0) + , m_scaledFont(0) +#endif + , m_syntheticBold(false) + , m_syntheticOblique(false) + , m_useGDI(useGDI) +{ + HDC hdc = GetDC(0); + SaveDC(hdc); + + SelectObject(hdc, font); + UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL); + + ASSERT_WITH_MESSAGE(bufferSize != 0, "Bitmap fonts not supported with CoreGraphics."); + + if (bufferSize != 0) { + 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); + + free(metrics); + } + + RestoreDC(hdc, -1); + ReleaseDC(0, hdc); +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) + : m_font(0) + , m_size(size) +#if PLATFORM(CG) + , m_cgFont(0) +#elif PLATFORM(CAIRO) + , m_fontFace(0) + , m_scaledFont(0) +#endif + , m_syntheticBold(bold) + , m_syntheticOblique(oblique) + , m_useGDI(false) +{ +} + +FontPlatformData::~FontPlatformData() +{ +} + +} diff --git a/WebCore/platform/graphics/win/FontWin.cpp b/WebCore/platform/graphics/win/FontWin.cpp new file mode 100644 index 0000000..5e423e0 --- /dev/null +++ b/WebCore/platform/graphics/win/FontWin.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "FontFallbackList.h" +#include "GlyphBuffer.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" +#include "UniscribeController.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, + int from, int to) const +{ + UniscribeController it(this, run); + it.advance(from); + float beforeWidth = it.runWidthSoFar(); + it.advance(to); + float afterWidth = it.runWidthSoFar(); + + // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning + if (run.rtl()) { + it.advance(run.length()); + float totalWidth = it.runWidthSoFar(); + return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); + } + + return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, + int from, int to) const +{ + // This glyph buffer holds our glyphs + advances + font data for each glyph. + GlyphBuffer glyphBuffer; + + float startX = point.x(); + UniscribeController controller(this, run); + controller.advance(from); + float beforeWidth = controller.runWidthSoFar(); + controller.advance(to, &glyphBuffer); + + // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) + return; + + float afterWidth = controller.runWidthSoFar(); + + if (run.rtl()) { + controller.advance(run.length()); + startX += controller.runWidthSoFar() - afterWidth; + } else + startX += beforeWidth; + + // Draw the glyph buffer now at the starting point returned in startX. + FloatPoint startPoint(startX, point.y()); + drawGlyphBuffer(context, glyphBuffer, run, startPoint); +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + UniscribeController controller(this, run); + controller.advance(run.length()); + return controller.runWidthSoFar(); +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const +{ + UniscribeController controller(this, run); + return controller.offsetForPosition(x, includePartialGlyphs); +} + +} diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp new file mode 100644 index 0000000..c11fc1b --- /dev/null +++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphPageTreeNode.h" + +#include "SimpleFontData.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> + +namespace WebCore { + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs. + // We won't support this for now. + if (bufferLength > length) + return false; + + bool haveGlyphs = false; + CGGlyph localGlyphBuffer[GlyphPage::size]; + wkGetGlyphs(fontData->platformData().cgFont(), buffer, localGlyphBuffer, bufferLength); + for (unsigned i = 0; i < length; i++) { + Glyph glyph = localGlyphBuffer[i]; + if (!glyph) + setGlyphDataForIndex(offset + i, 0, 0); + else { + setGlyphDataForIndex(offset + i, glyph, fontData); + haveGlyphs = true; + } + } + return haveGlyphs; +} + +} diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp new file mode 100644 index 0000000..b679ced --- /dev/null +++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphPageTreeNode.h" + +#include "SimpleFontData.h" + +namespace WebCore { + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs. + // We won't support this for now. + if (bufferLength > length) + return false; + + bool haveGlyphs = false; + + HDC dc = GetDC((HWND)0); + SaveDC(dc); + SelectObject(dc, fontData->platformData().hfont()); + + TEXTMETRIC tm; + GetTextMetrics(dc, &tm); + + WORD localGlyphBuffer[GlyphPage::size * 2]; + DWORD result = GetGlyphIndices(dc, buffer, bufferLength, localGlyphBuffer, 0); + bool success = result != GDI_ERROR && static_cast<unsigned>(result) == bufferLength; + if (success) { + for (unsigned i = 0; i < length; i++) { + Glyph glyph = localGlyphBuffer[i]; + if (!glyph) + setGlyphDataForIndex(offset + i, 0, 0); + else { + setGlyphDataForIndex(offset + i, glyph, fontData); + haveGlyphs = true; + } + } + } + RestoreDC(dc, -1); + ReleaseDC(0, dc); + + return haveGlyphs; +} + +} diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp new file mode 100644 index 0000000..99d528d --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#include "AffineTransform.h" +#include "NotImplemented.h" +#include "Path.h" + +#include <CoreGraphics/CGBitmapContext.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#include "GraphicsContextPlatformPrivateCG.h" + +using namespace std; + +namespace WebCore { + +static CGContextRef CGContextWithHDC(HDC hdc) +{ + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); + BITMAP info; + + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, + info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst); + CGColorSpaceRelease(deviceRGB); + + // Flip coords + CGContextTranslateCTM(context, 0, info.bmHeight); + CGContextScaleCTM(context, 1, -1); + + // Put the HDC In advanced mode so it will honor affine transforms. + SetGraphicsMode(hdc, GM_ADVANCED); + + return context; +} + +GraphicsContext::GraphicsContext(HDC hdc) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc))) +{ + CGContextRelease(m_data->m_cgContext); + m_data->m_hdc = hdc; + setPaintingDisabled(!m_data->m_cgContext); + if (m_data->m_cgContext) { + // Make sure the context starts in sync with our state. + setPlatformFillColor(fillColor()); + setPlatformStrokeColor(strokeColor()); + } +} + +bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; } + +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend) +{ + if (inTransparencyLayer()) { + if (dstRect.isEmpty()) + return 0; + + // Create a bitmap DC in which to draw. + BITMAPINFO bitmapInfo; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = dstRect.width(); + bitmapInfo.bmiHeader.biHeight = dstRect.height(); + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = 0; + bitmapInfo.bmiHeader.biXPelsPerMeter = 0; + bitmapInfo.bmiHeader.biYPelsPerMeter = 0; + bitmapInfo.bmiHeader.biClrUsed = 0; + bitmapInfo.bmiHeader.biClrImportant = 0; + + void* pixels = 0; + HBITMAP bitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); + if (!bitmap) + return 0; + + HDC bitmapDC = ::CreateCompatibleDC(m_data->m_hdc); + ::SelectObject(bitmapDC, bitmap); + + // Fill our buffer with clear if we're going to alpha blend. + if (supportAlphaBlend) { + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 0, bufferSize); + } + + // Make sure we can do world transforms. + SetGraphicsMode(bitmapDC, GM_ADVANCED); + + // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap. + XFORM xform; + xform.eM11 = 1.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 1.0f; + xform.eDx = -dstRect.x(); + xform.eDy = -dstRect.y(); + ::SetWorldTransform(bitmapDC, &xform); + + return bitmapDC; + } + + CGContextFlush(platformContext()); + m_data->save(); + return m_data->m_hdc; +} + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend) +{ + if (hdc && inTransparencyLayer()) { + if (dstRect.isEmpty()) + return; + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + + // Need to make a CGImage out of the bitmap's pixel buffer and then draw + // it into our context. + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); + CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, + info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | + (supportAlphaBlend ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst)); + CGColorSpaceRelease(deviceRGB); + + CGImageRef image = CGBitmapContextCreateImage(bitmapContext); + CGContextDrawImage(m_data->m_cgContext, dstRect, image); + + // Delete all our junk. + CGImageRelease(image); + CGContextRelease(bitmapContext); + ::DeleteDC(hdc); + ::DeleteObject(bitmap); + + return; + } + + m_data->restore(); +} + +void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform) +{ + if (!m_hdc) + return; + + CGAffineTransform mat = transform; + XFORM xform; + xform.eM11 = mat.a; + xform.eM12 = mat.b; + xform.eM21 = mat.c; + xform.eM22 = mat.d; + xform.eDx = mat.tx; + xform.eDy = mat.ty; + + ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY); +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + float radius = (focusRingWidth() - 1) / 2.0f; + int offset = radius + focusRingOffset(); + CGColorRef colorRef = color.isValid() ? cgColor(color) : 0; + + CGMutablePathRef focusRingPath = CGPathCreateMutable(); + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + for (unsigned i = 0; i < rectCount; i++) + CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset)); + + CGContextRef context = platformContext(); + CGContextSaveGState(context); + + CGContextBeginPath(context); + CGContextAddPath(context, focusRingPath); + + wkDrawFocusRing(context, colorRef, radius); + + CGColorRelease(colorRef); + + CGPathRelease(focusRingPath); + + CGContextRestoreGState(context); +} + +// Pulled from GraphicsContextCG +static void setCGStrokeColor(CGContextRef context, const Color& color) +{ + CGFloat red, green, blue, alpha; + color.getRGBA(red, green, blue, alpha); + CGContextSetRGBStrokeColor(context, red, green, blue, alpha); +} + +static const Color& spellingPatternColor() { + static const Color spellingColor(255, 0, 0); + return spellingColor; +} + +static const Color& grammarPatternColor() { + static const Color grammarColor(0, 128, 0); + return grammarColor; +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar) +{ + if (paintingDisabled()) + return; + + // These are the same for misspelling or bad grammar + const int patternHeight = 3; // 3 rows + ASSERT(cMisspellingLineThickness == patternHeight); + const int patternWidth = 4; // 4 pixels + ASSERT(patternWidth == cMisspellingLinePatternWidth); + + // Make sure to draw only complete dots. + // NOTE: Code here used to shift the underline to the left and increase the width + // to make sure everything gets underlined, but that results in drawing out of + // bounds (e.g. when at the edge of a view) and could make it appear that the + // space between adjacent misspelled words was underlined. + // allow slightly more considering that the pattern ends with a transparent pixel + int widthMod = width % patternWidth; + if (patternWidth - widthMod > cMisspellingLinePatternGapWidth) + width -= widthMod; + + // Draw the underline + CGContextRef context = platformContext(); + CGContextSaveGState(context); + + const Color& patternColor = grammar ? grammarPatternColor() : spellingPatternColor(); + setCGStrokeColor(context, patternColor); + + wkSetPatternPhaseInUserSpace(context, point); + CGContextSetBlendMode(context, kCGBlendModeNormal); + + // 3 rows, each offset by half a pixel for blending purposes + const CGPoint upperPoints [] = {{point.x(), point.y() + patternHeight - 2.5 }, {point.x() + width, point.y() + patternHeight - 2.5}}; + const CGPoint middlePoints [] = {{point.x(), point.y() + patternHeight - 1.5 }, {point.x() + width, point.y() + patternHeight - 1.5}}; + const CGPoint lowerPoints [] = {{point.x(), point.y() + patternHeight - 0.5 }, {point.x() + width, point.y() + patternHeight - 0.5 }}; + + // Dash lengths for the top and bottom of the error underline are the same. + // These are magic. + static const float edge_dash_lengths[] = {2.0f, 2.0f}; + static const float middle_dash_lengths[] = {2.76f, 1.24f}; + static const float edge_offset = -(edge_dash_lengths[1] - 1.0f) / 2.0f; + static const float middle_offset = -(middle_dash_lengths[1] - 1.0f) / 2.0f; + + // Line opacities. Once again, these are magic. + const float upperOpacity = 0.33f; + const float middleOpacity = 0.75f; + const float lowerOpacity = 0.88f; + + //Top line + CGContextSetLineDash(context, edge_offset, edge_dash_lengths, + sizeof(edge_dash_lengths) / sizeof(edge_dash_lengths[0])); + CGContextSetAlpha(context, upperOpacity); + CGContextStrokeLineSegments(context, upperPoints, 2); + + // Middle line + CGContextSetLineDash(context, middle_offset, middle_dash_lengths, + sizeof(middle_dash_lengths) / sizeof(middle_dash_lengths[0])); + CGContextSetAlpha(context, middleOpacity); + CGContextStrokeLineSegments(context, middlePoints, 2); + + // Bottom line + CGContextSetLineDash(context, edge_offset, edge_dash_lengths, + sizeof(edge_dash_lengths) / sizeof(edge_dash_lengths[0])); + CGContextSetAlpha(context, lowerOpacity); + CGContextStrokeLineSegments(context, lowerPoints, 2); + + CGContextRestoreGState(context); +} + +} diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp new file mode 100644 index 0000000..0e9c636 --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#include "AffineTransform.h" +#include "NotImplemented.h" +#include "Path.h" + +#include <cairo-win32.h> +#include "GraphicsContextPlatformPrivateCairo.h" + +using namespace std; + +namespace WebCore { + +GraphicsContext::GraphicsContext(HDC dc) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate) +{ + if (dc) { + cairo_surface_t* surface = cairo_win32_surface_create(dc); + m_data->cr = cairo_create(surface); + m_data->m_hdc = dc; + } else { + setPaintingDisabled(true); + m_data->cr = 0; + m_data->m_hdc = 0; + } + + if (m_data->cr) { + // Make sure the context starts in sync with our state. + setPlatformFillColor(fillColor()); + setPlatformStrokeColor(strokeColor()); + } +} + +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend) +{ + // This is probably wrong, and definitely out of date. Pulled from old SVN + cairo_surface_t* surface = cairo_get_target(platformContext()); + HDC hdc = cairo_win32_surface_get_dc(surface); + SaveDC(hdc); + + // FIXME: We need to make sure a clip is really set on the HDC. + // Call SetWorldTransform to honor the current Cairo transform. + SetGraphicsMode(hdc, GM_ADVANCED); // We need this call for themes to honor world transforms. + cairo_matrix_t mat; + cairo_get_matrix(platformContext(), &mat); + XFORM xform; + xform.eM11 = mat.xx; + xform.eM12 = mat.xy; + xform.eM21 = mat.yx; + xform.eM22 = mat.yy; + xform.eDx = mat.x0; + xform.eDy = mat.y0; + SetWorldTransform(hdc, &xform); + + return hdc; +} + +bool GraphicsContext::inTransparencyLayer() const { return m_data->m_transparencyCount; } + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend) +{ + cairo_surface_t* surface = cairo_get_target(platformContext()); + HDC hdc2 = cairo_win32_surface_get_dc(surface); + RestoreDC(hdc2, -1); + cairo_surface_mark_dirty(surface); +} + +void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform) +{ + cairo_surface_t* surface = cairo_get_target(cr); + HDC hdc = cairo_win32_surface_get_dc(surface); + SaveDC(hdc); + + const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform); + + XFORM xform; + xform.eM11 = matrix->xx; + xform.eM12 = matrix->xy; + xform.eM21 = matrix->yx; + xform.eM22 = matrix->yy; + xform.eDx = matrix->x0; + xform.eDy = matrix->y0; + + ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); +} + +} diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp new file mode 100644 index 0000000..373d2cf --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#if PLATFORM(CG) +#include "GraphicsContextPlatformPrivateCG.h" +#elif PLATFORM(CAIRO) +#include "GraphicsContextPlatformPrivateCairo.h" +#endif + +#include "AffineTransform.h" +#include "NotImplemented.h" +#include "Path.h" +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +class SVGResourceImage; + +void GraphicsContextPlatformPrivate::save() +{ + if (!m_hdc) + return; + SaveDC(m_hdc); +} + +void GraphicsContextPlatformPrivate::restore() +{ + if (!m_hdc) + return; + RestoreDC(m_hdc, -1); +} + +void GraphicsContextPlatformPrivate::clip(const IntRect& clipRect) +{ + if (!m_hdc) + return; + IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom()); +} + +void GraphicsContextPlatformPrivate::clip(const Path&) +{ + notImplemented(); +} + +void GraphicsContextPlatformPrivate::scale(const FloatSize& size) +{ + if (!m_hdc) + return; + XFORM xform; + xform.eM11 = size.width(); + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = size.height(); + xform.eDx = 0.0f; + xform.eDy = 0.0f; + ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY); +} + +static const double deg2rad = 0.017453292519943295769; // pi/180 + +void GraphicsContextPlatformPrivate::rotate(float degreesAngle) +{ + float radiansAngle = degreesAngle * deg2rad; + float cosAngle = cosf(radiansAngle); + float sinAngle = sinf(radiansAngle); + XFORM xform; + xform.eM11 = cosAngle; + xform.eM12 = -sinAngle; + xform.eM21 = sinAngle; + xform.eM22 = cosAngle; + xform.eDx = 0.0f; + xform.eDy = 0.0f; + ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY); +} + +void GraphicsContextPlatformPrivate::translate(float x , float y) +{ + if (!m_hdc) + return; + XFORM xform; + xform.eM11 = 1.0f; + xform.eM12 = 0.0f; + xform.eM21 = 0.0f; + xform.eM22 = 1.0f; + xform.eDx = x; + xform.eDy = y; + ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY); +} + +#if ENABLE(SVG) +GraphicsContext* contextForImage(SVGResourceImage*) +{ + // FIXME: This should go in GraphicsContextCG.cpp + notImplemented(); + return 0; +} +#endif + +} diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp new file mode 100644 index 0000000..b6bc926 --- /dev/null +++ b/WebCore/platform/graphics/win/IconWin.cpp @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2006, 2007 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 "Icon.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include <windows.h> + +namespace WebCore { + +Icon::Icon() + : RefCounted<Icon>(0) + , m_hIcon(0) +{ +} + +Icon::Icon(HICON icon) + : RefCounted<Icon>(0) + , m_hIcon(icon) +{ +} + +Icon::~Icon() +{ + if (m_hIcon) + DestroyIcon(m_hIcon); +} + +PassRefPtr<Icon> Icon::newIconForFile(const String& filename) +{ + SHFILEINFO sfi; + memset(&sfi, 0, sizeof(sfi)); + + String tmpFilename = filename; + if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + return 0; + + Icon* icon = new Icon(); + icon->m_hIcon = sfi.hIcon; + return icon; +} + +void Icon::paint(GraphicsContext* context, const IntRect& r) +{ + if (context->paintingDisabled()) + return; + + HDC hdc = context->getWindowsContext(r); + + DrawIconEx(hdc, r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL); + + context->releaseWindowsContext(hdc, r); +} + +} diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp new file mode 100644 index 0000000..752729c --- /dev/null +++ b/WebCore/platform/graphics/win/ImageCGWin.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" +#include "BitmapImage.h" +#include "GraphicsContext.h" +#include <ApplicationServices/ApplicationServices.h> + +#include <windows.h> +#include "PlatformString.h" + +namespace WebCore { + +bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) +{ + ASSERT(bmp); + + BITMAP bmpInfo; + GetObject(bmp, sizeof(BITMAP), &bmpInfo); + + ASSERT(bmpInfo.bmBitsPixel == 32); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + + CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); + CGContextRef cgContext = CGBitmapContextCreate(bmpInfo.bmBits, bmpInfo.bmWidth, bmpInfo.bmHeight, + 8, bmpInfo.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); + + GraphicsContext gc(cgContext); + + IntSize imageSize = BitmapImage::size(); + if (size) + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + else + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + + // Do cleanup + CGContextRelease(cgContext); + CGColorSpaceRelease(deviceRGB); + + return true; +} + +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +{ + int frames = frameCount(); + for (int i = 0; i < frames; ++i) { + CGImageRef image = frameAtIndex(i); + if (CGImageGetHeight(image) == static_cast<size_t>(srcSize.height()) && CGImageGetWidth(image) == static_cast<size_t>(srcSize.width())) { + size_t currentFrame = m_currentFrame; + m_currentFrame = i; + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp); + m_currentFrame = currentFrame; + return; + } + } + + // No image of the correct size was found, fallback to drawing the current frame + IntSize imageSize = BitmapImage::size(); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp new file mode 100644 index 0000000..95bb7bc --- /dev/null +++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" +#include "BitmapImage.h" +#include "GraphicsContext.h" +#include <cairo.h> + +#include <windows.h> +#include "PlatformString.h" + +namespace WebCore { + +bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) +{ + ASSERT(bmp); + + BITMAP bmpInfo; + GetObject(bmp, sizeof(BITMAP), &bmpInfo); + + // If this is a 32bpp bitmap, which it always should be, we'll clear it so alpha-wise it will be visible + if (bmpInfo.bmBitsPixel == 32) { + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 255, bufferSize); + } + + HDC tempDC = CreateCompatibleDC(0); + if (!tempDC) { + LOG_ERROR("Failed to create in-memory DC for Image::blit()"); + return false; + } + SelectObject(tempDC, bmp); + GraphicsContext gc(tempDC); + + IntSize imageSize = BitmapImage::size(); + if (size) + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + else + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + + // Do cleanup + DeleteDC(tempDC); + + return true; +} + +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +{ + int frames = frameCount(); + for (int i = 0; i < frames; ++i) { + cairo_surface_t* image = frameAtIndex(i); + if (cairo_image_surface_get_height(image) == static_cast<size_t>(srcSize.height()) && cairo_image_surface_get_width(image) == static_cast<size_t>(srcSize.width())) { + size_t currentFrame = m_currentFrame; + m_currentFrame = i; + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp); + m_currentFrame = currentFrame; + return; + } + } + + // No image of the correct size was found, fallback to drawing the current frame + IntSize imageSize = BitmapImage::size(); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/win/ImageWin.cpp b/WebCore/platform/graphics/win/ImageWin.cpp new file mode 100644 index 0000000..2d3a87a --- /dev/null +++ b/WebCore/platform/graphics/win/ImageWin.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" +#include "BitmapImage.h" + +#include "SharedBuffer.h" + +// This function loads resources from WebKit +PassRefPtr<WebCore::SharedBuffer> loadResourceIntoBuffer(const char*); + +namespace WebCore { + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +Image* Image::loadPlatformResource(const char *name) +{ + RefPtr<SharedBuffer> buffer = loadResourceIntoBuffer(name); + BitmapImage* img = new BitmapImage; + img->setData(buffer.release(), true); + return img; +} + +bool BitmapImage::getHBITMAP(HBITMAP bmp) +{ + return getHBITMAPOfSize(bmp, 0); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/win/IntPointWin.cpp b/WebCore/platform/graphics/win/IntPointWin.cpp new file mode 100644 index 0000000..a6ce0bb --- /dev/null +++ b/WebCore/platform/graphics/win/IntPointWin.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IntPoint.h" + +#include <windows.h> + +namespace WebCore { + +IntPoint::IntPoint(const POINT& p) + : m_x(p.x) + , m_y(p.y) +{ +} + +IntPoint::operator POINT() const +{ + POINT p = {m_x, m_y}; + return p; +} + +IntPoint::IntPoint(const POINTS& p) + : m_x(p.x) + , m_y(p.y) +{ +} + +IntPoint::operator POINTS() const +{ + POINTS p = {m_x, m_y}; + return p; +} + +} diff --git a/WebCore/platform/graphics/win/IntRectWin.cpp b/WebCore/platform/graphics/win/IntRectWin.cpp new file mode 100644 index 0000000..6228be8 --- /dev/null +++ b/WebCore/platform/graphics/win/IntRectWin.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IntRect.h" + +#include <windows.h> + +namespace WebCore { + +IntRect::IntRect(const RECT& r) + : m_location(IntPoint(r.left, r.top)), m_size(IntSize(r.right-r.left, r.bottom-r.top)) +{ +} + +IntRect::operator RECT() const +{ + RECT rect = { x(), y(), right(), bottom() }; + return rect; +} + +} diff --git a/WebCore/platform/graphics/win/IntSizeWin.cpp b/WebCore/platform/graphics/win/IntSizeWin.cpp new file mode 100644 index 0000000..8a27cdb --- /dev/null +++ b/WebCore/platform/graphics/win/IntSizeWin.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "IntSize.h" + +#include <windows.h> + +namespace WebCore { + +IntSize::IntSize(const SIZE& s) + : m_width(s.cx) + , m_height(s.cy) +{ +} + +IntSize::operator SIZE() const +{ + SIZE s = {m_width, m_height}; + return s; +} + +} diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp new file mode 100644 index 0000000..c7d3bf8 --- /dev/null +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(VIDEO) +#include "MediaPlayerPrivateQuickTimeWin.h" + +#include "GraphicsContext.h" +#include "KURL.h" +#include "QTMovieWin.h" +#include "ScrollView.h" +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +static const double endPointTimerInterval = 0.020; + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player) + , m_seekTo(-1) + , m_endTime(numeric_limits<float>::infinity()) + , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired) + , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::DataUnavailable) + , m_startedPlaying(false) + , m_isStreaming(false) +{ +} + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ +} + +void MediaPlayerPrivate::load(const String& url) +{ + if (!QTMovieWin::initializeQuickTime()) { + m_networkState = MediaPlayer::LoadFailed; + m_player->networkStateChanged(); + return; + } + + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::DataUnavailable) { + m_readyState = MediaPlayer::DataUnavailable; + m_player->readyStateChanged(); + } + cancelSeek(); + m_endPointTimer.stop(); + + m_qtMovie.set(new QTMovieWin(this)); + m_qtMovie->load(url.characters(), url.length()); + m_qtMovie->setVolume(m_player->m_volume); + m_qtMovie->setVisible(m_player->m_visible); +} + +void MediaPlayerPrivate::play() +{ + if (!m_qtMovie) + return; + m_startedPlaying = true; + + m_qtMovie->play(); + startEndPointTimerIfNeeded(); +} + +void MediaPlayerPrivate::pause() +{ + if (!m_qtMovie) + return; + m_startedPlaying = false; + m_qtMovie->pause(); + m_endPointTimer.stop(); +} + +float MediaPlayerPrivate::duration() const +{ + if (!m_qtMovie) + return 0; + return m_qtMovie->duration(); +} + +float MediaPlayerPrivate::currentTime() const +{ + if (!m_qtMovie) + return 0; + return min(m_qtMovie->currentTime(), m_endTime); +} + +void MediaPlayerPrivate::seek(float time) +{ + cancelSeek(); + + if (!m_qtMovie) + return; + + if (time > duration()) + time = duration(); + + m_seekTo = time; + if (maxTimeLoaded() >= m_seekTo) + doSeek(); + else + m_seekTimer.start(0, 0.5f); +} + +void MediaPlayerPrivate::doSeek() +{ + float oldRate = m_qtMovie->rate(); + m_qtMovie->setRate(0); + m_qtMovie->setCurrentTime(m_seekTo); + float timeAfterSeek = currentTime(); + // restore playback only if not at end, othewise QTMovie will loop + if (timeAfterSeek < duration() && timeAfterSeek < m_endTime) + m_qtMovie->setRate(oldRate); + cancelSeek(); +} + +void MediaPlayerPrivate::cancelSeek() +{ + m_seekTo = -1; + m_seekTimer.stop(); +} + +void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*) +{ + if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) { + cancelSeek(); + updateStates(); + m_player->timeChanged(); + return; + } + + if (maxTimeLoaded() >= m_seekTo) + doSeek(); + else { + MediaPlayer::NetworkState state = networkState(); + if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) { + cancelSeek(); + updateStates(); + m_player->timeChanged(); + } + } +} + +void MediaPlayerPrivate::setEndTime(float time) +{ + m_endTime = time; + startEndPointTimerIfNeeded(); +} + +void MediaPlayerPrivate::startEndPointTimerIfNeeded() +{ + if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive()) + m_endPointTimer.startRepeating(endPointTimerInterval); +} + +void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) +{ + float time = currentTime(); + if (time >= m_endTime) { + pause(); + didEnd(); + } +} + +bool MediaPlayerPrivate::paused() const +{ + if (!m_qtMovie) + return true; + return m_qtMovie->rate() == 0.0f; +} + +bool MediaPlayerPrivate::seeking() const +{ + if (!m_qtMovie) + return false; + return m_seekTo >= 0; +} + +IntSize MediaPlayerPrivate::naturalSize() const +{ + if (!m_qtMovie) + return IntSize(); + int width; + int height; + m_qtMovie->getNaturalSize(width, height); + return IntSize(width, height); +} + +bool MediaPlayerPrivate::hasVideo() const +{ + // This is not used at the moment + return true; +} + +void MediaPlayerPrivate::setVolume(float volume) +{ + if (!m_qtMovie) + return; + m_qtMovie->setVolume(volume); +} + +void MediaPlayerPrivate::setRate(float rate) +{ + if (!m_qtMovie) + return; + if (!paused()) + m_qtMovie->setRate(rate); +} + +int MediaPlayerPrivate::dataRate() const +{ + // This is not used at the moment + return 0; +} + +float MediaPlayerPrivate::maxTimeBuffered() const +{ + // rtsp streams are not buffered + return m_isStreaming ? 0 : maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeSeekable() const +{ + // infinite duration means live stream + return !isfinite(duration()) ? 0 : maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeLoaded() const +{ + if (!m_qtMovie) + return 0; + return m_qtMovie->maxTimeLoaded(); +} + +unsigned MediaPlayerPrivate::bytesLoaded() const +{ + if (!m_qtMovie) + return 0; + float dur = duration(); + float maxTime = maxTimeLoaded(); + if (!dur) + return 0; + return totalBytes() * maxTime / dur; +} + +bool MediaPlayerPrivate::totalBytesKnown() const +{ + return totalBytes() > 0; +} + +unsigned MediaPlayerPrivate::totalBytes() const +{ + if (!m_qtMovie) + return 0; + return m_qtMovie->dataSize(); +} + +void MediaPlayerPrivate::cancelLoad() +{ + if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded) + return; + + // Cancel the load by destroying the movie. + m_qtMovie.clear(); + + updateStates(); +} + +void MediaPlayerPrivate::updateStates() +{ + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + + long loadState = m_qtMovie ? m_qtMovie->loadState() : QTMovieLoadStateError; + + if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData) { + unsigned enabledTrackCount; + m_qtMovie->disableUnsupportedTracks(enabledTrackCount); + // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692> + if (!enabledTrackCount) + loadState = QTMovieLoadStateError; + } + + // "Loaded" is reserved for fully buffered movies, never the case when streaming + if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) { + if (m_networkState < MediaPlayer::Loaded) + m_networkState = MediaPlayer::Loaded; + m_readyState = MediaPlayer::CanPlayThrough; + } else if (loadState >= QTMovieLoadStatePlaythroughOK) { + if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking()) + m_networkState = MediaPlayer::LoadedFirstFrame; + m_readyState = MediaPlayer::CanPlayThrough; + } else if (loadState >= QTMovieLoadStatePlayable) { + if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking()) + m_networkState = MediaPlayer::LoadedFirstFrame; + m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable; + } else if (loadState >= QTMovieLoadStateLoaded) { + if (m_networkState < MediaPlayer::LoadedMetaData) + m_networkState = MediaPlayer::LoadedMetaData; + m_readyState = MediaPlayer::DataUnavailable; + } else if (loadState > QTMovieLoadStateError) { + if (m_networkState < MediaPlayer::Loading) + m_networkState = MediaPlayer::Loading; + m_readyState = MediaPlayer::DataUnavailable; + } else { + m_networkState = MediaPlayer::LoadFailed; + m_readyState = MediaPlayer::DataUnavailable; + } + + if (seeking()) + m_readyState = MediaPlayer::DataUnavailable; + + if (m_networkState != oldNetworkState) + m_player->networkStateChanged(); + if (m_readyState != oldReadyState) + m_player->readyStateChanged(); +} + + +void MediaPlayerPrivate::didEnd() +{ + m_endPointTimer.stop(); + m_startedPlaying = false; + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivate::setRect(const IntRect& r) +{ + if (m_qtMovie) + m_qtMovie->setSize(r.width(), r.height()); +} + +void MediaPlayerPrivate::setVisible(bool b) +{ + if (!m_qtMovie) + return; + m_qtMovie->setVisible(b); +} + +void MediaPlayerPrivate::paint(GraphicsContext* p, const IntRect& r) +{ + if (p->paintingDisabled() || !m_qtMovie) + return; + HDC hdc = p->getWindowsContext(r); + m_qtMovie->paint(hdc, r.x(), r.y()); + p->releaseWindowsContext(hdc, r); +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +{ + unsigned count = QTMovieWin::countSupportedTypes(); + for (unsigned n = 0; n < count; n++) { + const UChar* character; + unsigned len; + QTMovieWin::getSupportedType(n, character, len); + if (len) + types.add(String(character, len)); + } +} + +bool MediaPlayerPrivate::isAvailable() +{ + return QTMovieWin::initializeQuickTime(); +} + +void MediaPlayerPrivate::movieEnded(QTMovieWin* movie) +{ + ASSERT(m_qtMovie.get() == movie); + didEnd(); +} + +void MediaPlayerPrivate::movieLoadStateChanged(QTMovieWin* movie) +{ + ASSERT(m_qtMovie.get() == movie); + updateStates(); +} + +void MediaPlayerPrivate::movieTimeChanged(QTMovieWin* movie) +{ + ASSERT(m_qtMovie.get() == movie); + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivate::movieNewImageAvailable(QTMovieWin* movie) +{ + ASSERT(m_qtMovie.get() == movie); + m_player->repaint(); +} + +} + +#endif + diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h new file mode 100644 index 0000000..37b5b05 --- /dev/null +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MediaPlayerPrivateQTKit_h +#define MediaPlayerPrivateQTKit_h + +#if ENABLE(VIDEO) + +#include "MediaPlayer.h" +#include "Timer.h" +#include <QTMovieWin.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class GraphicsContext; +class IntSize; +class IntRect; +class String; + +class MediaPlayerPrivate : QTMovieWinClient, Noncopyable { +public: + MediaPlayerPrivate(MediaPlayer*); + ~MediaPlayerPrivate(); + + IntSize naturalSize() const; + bool hasVideo() const; + + void load(const String& url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + + int dataRate() const; + + MediaPlayer::NetworkState networkState() const { return m_networkState; } + MediaPlayer::ReadyState readyState() const { return m_readyState; } + + float maxTimeBuffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + bool totalBytesKnown() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setRect(const IntRect&); + + void loadStateChanged(); + void didEnd(); + + void paint(GraphicsContext*, const IntRect&); + + static void getSupportedTypes(HashSet<String>& types); + static bool isAvailable(); + +private: + void updateStates(); + void doSeek(); + void cancelSeek(); + void seekTimerFired(Timer<MediaPlayerPrivate>*); + void endPointTimerFired(Timer<MediaPlayerPrivate>*); + float maxTimeLoaded() const; + void startEndPointTimerIfNeeded(); + + virtual void movieEnded(QTMovieWin*); + virtual void movieLoadStateChanged(QTMovieWin*); + virtual void movieTimeChanged(QTMovieWin*); + virtual void movieNewImageAvailable(QTMovieWin*); + + MediaPlayer* m_player; + OwnPtr<QTMovieWin> m_qtMovie; + float m_seekTo; + float m_endTime; + Timer<MediaPlayerPrivate> m_seekTimer; + Timer<MediaPlayerPrivate> m_endPointTimer; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + bool m_startedPlaying; + bool m_isStreaming; +}; + +} + +#endif +#endif diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp new file mode 100644 index 0000000..80c6d50 --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -0,0 +1,711 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include <windows.h> + +#include "QTMovieWin.h" + +// Put Movies.h first so build failures here point clearly to QuickTime +#include <Movies.h> +#include <GXMath.h> +#include <QTML.h> + +#include "QTMovieWinTimer.h" + +#include <wtf/Assertions.h> +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +using namespace std; + +static const long minimumQuickTimeVersion = 0x07300000; // 7.3 + +// Resizing GWorlds is slow, give them a minimum size so size of small +// videos can be animated smoothly +static const int cGWorldMinWidth = 640; +static const int cGWorldMinHeight = 360; + +static const float cNonContinuousTimeChange = 0.2f; + +union UppParam { + long longValue; + void* ptr; +}; + +static MovieDrawingCompleteUPP gMovieDrawingCompleteUPP = 0; +static HashSet<QTMovieWinPrivate*>* gTaskList; +static Vector<CFStringRef>* gSupportedTypes = 0; + +static void updateTaskTimer(int maxInterval = 1000) +{ + if (!gTaskList->size()) { + stopSharedTimer(); + return; + } + + long intervalInMS; + QTGetTimeUntilNextTask(&intervalInMS, 1000); + if (intervalInMS > maxInterval) + intervalInMS = maxInterval; + setSharedTimerFireDelay(static_cast<float>(intervalInMS) / 1000); +} + +class QTMovieWinPrivate : Noncopyable { +public: + QTMovieWinPrivate(); + ~QTMovieWinPrivate(); + void task(); + void startTask(); + void endTask(); + + void registerDrawingCallback(); + void drawingComplete(); + void updateGWorld(); + void createGWorld(); + void deleteGWorld(); + + void setSize(int, int); + + QTMovieWin* m_movieWin; + Movie m_movie; + bool m_tasking; + QTMovieWinClient* m_client; + long m_loadState; + bool m_ended; + bool m_seeking; + float m_lastMediaTime; + double m_lastLoadStateCheckTime; + int m_width; + int m_height; + bool m_visible; + GWorldPtr m_gWorld; + int m_gWorldWidth; + int m_gWorldHeight; + GWorldPtr m_savedGWorld; + long m_loadError; +}; + +QTMovieWinPrivate::QTMovieWinPrivate() + : m_movieWin(0) + , m_movie(0) + , m_tasking(false) + , m_client(0) + , m_loadState(0) + , m_ended(false) + , m_seeking(false) + , m_lastMediaTime(0) + , m_lastLoadStateCheckTime(0) + , m_width(0) + , m_height(0) + , m_visible(false) + , m_gWorld(0) + , m_gWorldWidth(0) + , m_gWorldHeight(0) + , m_savedGWorld(0) + , m_loadError(0) +{ +} + +QTMovieWinPrivate::~QTMovieWinPrivate() +{ + endTask(); + if (m_gWorld) + deleteGWorld(); + if (m_movie) + DisposeMovie(m_movie); +} + +static void taskTimerFired() +{ + // The hash content might change during task() + Vector<QTMovieWinPrivate*> tasks; + copyToVector(*gTaskList, tasks); + size_t count = tasks.size(); + for (unsigned n = 0; n < count; ++n) + tasks[n]->task(); + + updateTaskTimer(); +} + +void QTMovieWinPrivate::startTask() +{ + if (m_tasking) + return; + if (!gTaskList) + gTaskList = new HashSet<QTMovieWinPrivate*>; + gTaskList->add(this); + m_tasking = true; + updateTaskTimer(); +} + +void QTMovieWinPrivate::endTask() +{ + if (!m_tasking) + return; + gTaskList->remove(this); + m_tasking = false; + updateTaskTimer(); +} + +void QTMovieWinPrivate::task() +{ + ASSERT(m_tasking); + + if (!m_loadError) + MoviesTask(m_movie, 0); + + // GetMovieLoadState documentation says that you should not call it more often than every quarter of a second. + if (systemTime() >= m_lastLoadStateCheckTime + 0.25 || m_loadError) { + // If load fails QT's load state is kMovieLoadStateComplete. + // This is different from QTKit API and seems strange. + long loadState = m_loadError ? kMovieLoadStateError : GetMovieLoadState(m_movie); + if (loadState != m_loadState) { + m_loadState = loadState; + m_client->movieLoadStateChanged(m_movieWin); + } + m_lastLoadStateCheckTime = systemTime(); + } + + bool ended = !!IsMovieDone(m_movie); + if (ended != m_ended) { + m_ended = ended; + if (m_client && ended) + m_client->movieEnded(m_movieWin); + } + + float time = m_movieWin->currentTime(); + if (time < m_lastMediaTime || time >= m_lastMediaTime + cNonContinuousTimeChange || m_seeking) { + m_seeking = false; + if (m_client) + m_client->movieTimeChanged(m_movieWin); + } + m_lastMediaTime = time; + + if (m_loadError) + endTask(); +} + +void QTMovieWinPrivate::registerDrawingCallback() +{ + UppParam param; + param.ptr = this; + SetMovieDrawingCompleteProc(m_movie, movieDrawingCallWhenChanged, gMovieDrawingCompleteUPP, param.longValue); +} + +void QTMovieWinPrivate::drawingComplete() +{ + if (!m_gWorld) + return; + m_client->movieNewImageAvailable(m_movieWin); +} + +void QTMovieWinPrivate::updateGWorld() +{ + bool shouldBeVisible = m_visible; + if (!m_height || !m_width) + shouldBeVisible = false; + + if (shouldBeVisible && !m_gWorld) + createGWorld(); + else if (!shouldBeVisible && m_gWorld) + deleteGWorld(); + else if (m_gWorld && (m_width > m_gWorldWidth || m_height > m_gWorldHeight)) { + // need a bigger, better gWorld + deleteGWorld(); + createGWorld(); + } +} + +void QTMovieWinPrivate::createGWorld() +{ + ASSERT(!m_gWorld); + if (!m_movie) + return; + + m_gWorldWidth = max(cGWorldMinWidth, m_width); + m_gWorldHeight = max(cGWorldMinHeight, m_height); + Rect bounds; + bounds.top = 0; + bounds.left = 0; + bounds.right = m_gWorldWidth; + bounds.bottom = m_gWorldHeight; + OSErr err = QTNewGWorld(&m_gWorld, k32BGRAPixelFormat, &bounds, NULL, NULL, NULL); + if (err) + return; + GetMovieGWorld(m_movie, &m_savedGWorld, 0); + SetMovieGWorld(m_movie, m_gWorld, 0); + bounds.right = m_width; + bounds.bottom = m_height; + SetMovieBox(m_movie, &bounds); +} + +void QTMovieWinPrivate::setSize(int width, int height) +{ + if (m_width == width && m_height == height) + return; + m_width = width; + m_height = height; + if (!m_movie) + return; + Rect bounds; + bounds.top = 0; + bounds.left = 0; + bounds.right = width; + bounds.bottom = height; + SetMovieBox(m_movie, &bounds); + updateGWorld(); +} + +void QTMovieWinPrivate::deleteGWorld() +{ + ASSERT(m_gWorld); + if (m_movie) + SetMovieGWorld(m_movie, m_savedGWorld, 0); + m_savedGWorld = 0; + DisposeGWorld(m_gWorld); + m_gWorld = 0; + m_gWorldWidth = 0; + m_gWorldHeight = 0; +} + + +QTMovieWin::QTMovieWin(QTMovieWinClient* client) + : m_private(new QTMovieWinPrivate()) +{ + m_private->m_movieWin = this; + m_private->m_client = client; + initializeQuickTime(); +} + +QTMovieWin::~QTMovieWin() +{ + delete m_private; +} + +void QTMovieWin::play() +{ + StartMovie(m_private->m_movie); + m_private->startTask(); +} + +void QTMovieWin::pause() +{ + StopMovie(m_private->m_movie); + updateTaskTimer(); +} + +float QTMovieWin::rate() const +{ + return FixedToFloat(GetMovieRate(m_private->m_movie)); +} + +void QTMovieWin::setRate(float rate) +{ + SetMovieRate(m_private->m_movie, FloatToFixed(rate)); + updateTaskTimer(); +} + +float QTMovieWin::duration() const +{ + if (!m_private->m_movie) + return 0; + TimeValue val = GetMovieDuration(m_private->m_movie); + TimeScale scale = GetMovieTimeScale(m_private->m_movie); + return static_cast<float>(val) / scale; +} + +float QTMovieWin::currentTime() const +{ + if (!m_private->m_movie) + return 0; + TimeValue val = GetMovieTime(m_private->m_movie, 0); + TimeScale scale = GetMovieTimeScale(m_private->m_movie); + return static_cast<float>(val) / scale; +} + +void QTMovieWin::setCurrentTime(float time) const +{ + if (!m_private->m_movie) + return; + m_private->m_seeking = true; + TimeScale scale = GetMovieTimeScale(m_private->m_movie); + SetMovieTimeValue(m_private->m_movie, TimeValue(time * scale)); + updateTaskTimer(); +} + +void QTMovieWin::setVolume(float volume) +{ + SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256)); +} + +unsigned QTMovieWin::dataSize() const +{ + // FIXME: How to get this? + return 1000; +} + +float QTMovieWin::maxTimeLoaded() const +{ + if (!m_private->m_movie) + return 0; + TimeValue val; + GetMaxLoadedTimeInMovie(m_private->m_movie, &val); + TimeScale scale = GetMovieTimeScale(m_private->m_movie); + return static_cast<float>(val) / scale; +} + +long QTMovieWin::loadState() const +{ + return m_private->m_loadState; +} + +void QTMovieWin::getNaturalSize(int& width, int& height) +{ + Rect rect; + GetMovieNaturalBoundsRect(m_private->m_movie, &rect); + width = rect.right; + height = rect.bottom; +} + +void QTMovieWin::setSize(int width, int height) +{ + m_private->setSize(width, height); + updateTaskTimer(0); +} + +void QTMovieWin::setVisible(bool b) +{ + m_private->m_visible = b; + m_private->updateGWorld(); +} + +void QTMovieWin::paint(HDC hdc, int x, int y) +{ + if (!m_private->m_gWorld) + return; + + HDC hdcSrc = static_cast<HDC>(GetPortHDC(reinterpret_cast<GrafPtr>(m_private->m_gWorld))); + if (!hdcSrc) + return; + + // FIXME: If we could determine the movie has no alpha, we could use BitBlt for those cases, which might be faster. + BLENDFUNCTION blendFunction; + blendFunction.BlendOp = AC_SRC_OVER; + blendFunction.BlendFlags = 0; + blendFunction.SourceConstantAlpha = 255; + blendFunction.AlphaFormat = AC_SRC_ALPHA; + AlphaBlend(hdc, x, y, m_private->m_width, m_private->m_height, hdcSrc, + 0, 0, m_private->m_width, m_private->m_height, blendFunction); +} + +void QTMovieWin::load(const UChar* url, int len) +{ + if (m_private->m_movie) { + m_private->endTask(); + if (m_private->m_gWorld) + m_private->deleteGWorld(); + DisposeMovie(m_private->m_movie); + m_private->m_movie = 0; + } + + // Define a property array for NewMovieFromProperties. 8 should be enough for our needs. + QTNewMoviePropertyElement movieProps[8]; + ItemCount moviePropCount = 0; + + bool boolTrue = true; + + // Create a URL data reference of type CFURL + CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len); + + // Disable streaming support for now. + if (CFStringHasPrefix(urlStringRef, CFSTR("rtsp:"))) { + m_private->m_loadError = noMovieFound; + goto end; + } + + CFURLRef urlRef = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0); + + // Add the movie data location to the property array + movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation; + movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL; + movieProps[moviePropCount].propValueSize = sizeof(urlRef); + movieProps[moviePropCount].propValueAddress = &urlRef; + movieProps[moviePropCount].propStatus = 0; + moviePropCount++; + + movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; + movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs; + movieProps[moviePropCount].propValueSize = sizeof(boolTrue); + movieProps[moviePropCount].propValueAddress = &boolTrue; + movieProps[moviePropCount].propStatus = 0; + moviePropCount++; + + movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; + movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_AsyncOK; + movieProps[moviePropCount].propValueSize = sizeof(boolTrue); + movieProps[moviePropCount].propValueAddress = &boolTrue; + movieProps[moviePropCount].propStatus = 0; + moviePropCount++; + + movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty; + movieProps[moviePropCount].propID = kQTNewMoviePropertyID_Active; + movieProps[moviePropCount].propValueSize = sizeof(boolTrue); + movieProps[moviePropCount].propValueAddress = &boolTrue; + movieProps[moviePropCount].propStatus = 0; + moviePropCount++; + + movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty; + movieProps[moviePropCount].propID = kQTNewMoviePropertyID_DontInteractWithUser; + movieProps[moviePropCount].propValueSize = sizeof(boolTrue); + movieProps[moviePropCount].propValueAddress = &boolTrue; + movieProps[moviePropCount].propStatus = 0; + moviePropCount++; + + movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; + movieProps[moviePropCount].propID = '!url'; + movieProps[moviePropCount].propValueSize = sizeof(boolTrue); + movieProps[moviePropCount].propValueAddress = &boolTrue; + movieProps[moviePropCount].propStatus = 0; + moviePropCount++; + + movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; + movieProps[moviePropCount].propID = 'site'; + movieProps[moviePropCount].propValueSize = sizeof(boolTrue); + movieProps[moviePropCount].propValueAddress = &boolTrue; + movieProps[moviePropCount].propStatus = 0; + moviePropCount++; + + m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie); + + CFRelease(urlRef); +end: + m_private->startTask(); + // get the load fail callback quickly + if (m_private->m_loadError) + updateTaskTimer(0); + else + m_private->registerDrawingCallback(); + + CFRelease(urlStringRef); +} + +void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) +{ + if (!m_private->m_movie) { + enabledTrackCount = 0; + return; + } + + static HashSet<OSType>* allowedTrackTypes = 0; + if (!allowedTrackTypes) { + allowedTrackTypes = new HashSet<OSType>; + allowedTrackTypes->add(VideoMediaType); + allowedTrackTypes->add(SoundMediaType); + allowedTrackTypes->add(TextMediaType); + allowedTrackTypes->add(BaseMediaType); + allowedTrackTypes->add('clcp'); // Closed caption + allowedTrackTypes->add('sbtl'); // Subtitle + } + + long trackCount = GetMovieTrackCount(m_private->m_movie); + enabledTrackCount = trackCount; + + // Track indexes are 1-based. yuck. These things must descend from old- + // school mac resources or something. + for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) { + // Grab the track at the current index. If there isn't one there, then + // we can move onto the next one. + Track currentTrack = GetMovieIndTrack(m_private->m_movie, trackIndex); + if (!currentTrack) + continue; + + // Check to see if the track is disabled already, we should move along. + // We don't need to re-disable it. + if (!GetTrackEnabled(currentTrack)) + continue; + + // Grab the track's media. We're going to check to see if we need to + // disable the tracks. They could be unsupported. + Media trackMedia = GetTrackMedia(currentTrack); + if (!trackMedia) + continue; + + // Grab the media type for this track. Make sure that we don't + // get an error in doing so. If we do, then something really funky is + // wrong. + OSType mediaType; + GetMediaHandlerDescription(trackMedia, &mediaType, nil, nil); + OSErr mediaErr = GetMoviesError(); + if (mediaErr != noErr) + continue; + + if (!allowedTrackTypes->contains(mediaType)) { + SetTrackEnabled(currentTrack, false); + --enabledTrackCount; + } + + // Grab the track reference count for chapters. This will tell us if it + // has chapter tracks in it. If there aren't any references, then we + // can move on the next track. + long referenceCount = GetTrackReferenceCount(currentTrack, kTrackReferenceChapterList); + if (referenceCount <= 0) + continue; + + long referenceIndex = 0; + while (1) { + // If we get nothing here, we've overstepped our bounds and can stop + // looking. Chapter indices here are 1-based as well - hence, the + // pre-increment. + referenceIndex++; + Track chapterTrack = GetTrackReference(currentTrack, kTrackReferenceChapterList, referenceIndex); + if (!chapterTrack) + break; + + // Try to grab the media for the track. + Media chapterMedia = GetTrackMedia(chapterTrack); + if (!chapterMedia) + continue; + + // Grab the media type for this track. Make sure that we don't + // get an error in doing so. If we do, then something really + // funky is wrong. + OSType mediaType; + GetMediaHandlerDescription(chapterMedia, &mediaType, nil, nil); + OSErr mediaErr = GetMoviesError(); + if (mediaErr != noErr) + continue; + + // Check to see if the track is a video track. We don't care about + // other non-video tracks. + if (mediaType != VideoMediaType) + continue; + + // Check to see if the track is already disabled. If it is, we + // should move along. + if (!GetTrackEnabled(chapterTrack)) + continue; + + // Disabled the evil, evil track. + SetTrackEnabled(chapterTrack, false); + --enabledTrackCount; + } + } +} + +pascal OSErr movieDrawingCompleteProc(Movie movie, long data) +{ + UppParam param; + param.longValue = data; + QTMovieWinPrivate* mp = static_cast<QTMovieWinPrivate*>(param.ptr); + if (mp) + mp->drawingComplete(); + return 0; +} + +static void initializeSupportedTypes() +{ + if (gSupportedTypes) + return; + // 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")); + 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")); +} + +unsigned QTMovieWin::countSupportedTypes() +{ + initializeSupportedTypes(); + return static_cast<unsigned>(gSupportedTypes->size()); +} + +void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& len) +{ + initializeSupportedTypes(); + ASSERT(index < gSupportedTypes->size()); + + // Allocate sufficient buffer to hold any MIME type + static UniChar* staticBuffer = 0; + if (!staticBuffer) + staticBuffer = new UniChar[32]; + + CFStringRef cfstr = gSupportedTypes->at(index); + len = CFStringGetLength(cfstr); + CFRange range = { 0, len }; + CFStringGetCharacters(cfstr, range, staticBuffer); + str = reinterpret_cast<const UChar*>(staticBuffer); + +} + +bool QTMovieWin::initializeQuickTime() +{ + static bool initialized = false; + static bool initializationSucceeded = false; + if (!initialized) { + initialized = true; + // Initialize and check QuickTime version + OSErr result = InitializeQTML(0); + SInt32 version = 0; + if (result == noErr) + result = Gestalt(gestaltQuickTime, &version); + if (result != noErr) { + LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support."); + return false; + } + if (version < minimumQuickTimeVersion) { + LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", version, minimumQuickTimeVersion); + return false; + } + EnterMovies(); + setSharedTimerFiredFunction(taskTimerFired); + gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc); + initializationSucceeded = true; + } + return initializationSucceeded; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + setSharedTimerInstanceHandle(hinstDLL); + return TRUE; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + return FALSE; + } + ASSERT_NOT_REACHED(); + return FALSE; +} diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h new file mode 100644 index 0000000..e31780a --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QTMovieWin_h +#define QTMovieWin_h + +#include <Unicode.h> + +#ifdef QTMOVIEWIN_EXPORTS +#define QTMOVIEWIN_API __declspec(dllexport) +#else +#define QTMOVIEWIN_API __declspec(dllimport) +#endif + +class QTMovieWin; +class QTMovieWinPrivate; + +class QTMovieWinClient { +public: + virtual void movieEnded(QTMovieWin*) = 0; + virtual void movieLoadStateChanged(QTMovieWin*) = 0; + virtual void movieTimeChanged(QTMovieWin*) = 0; + virtual void movieNewImageAvailable(QTMovieWin*) = 0; +}; + +enum { + QTMovieLoadStateError = -1L, + QTMovieLoadStateLoaded = 2000L, + QTMovieLoadStatePlayable = 10000L, + QTMovieLoadStatePlaythroughOK = 20000L, + QTMovieLoadStateComplete = 100000L +}; + +class QTMOVIEWIN_API QTMovieWin { +public: + static bool initializeQuickTime(); + + QTMovieWin(QTMovieWinClient*); + ~QTMovieWin(); + + void load(const UChar* url, int len); + long loadState() const; + float maxTimeLoaded() const; + + void play(); + void pause(); + + float rate() const; + void setRate(float); + + float duration() const; + float currentTime() const; + void setCurrentTime(float) const; + + void setVolume(float); + + unsigned dataSize() const; + + void getNaturalSize(int& width, int& height); + void setSize(int width, int height); + + void setVisible(bool); + void paint(HDC, int x, int y); + + void disableUnsupportedTracks(unsigned& enabledTrackCount); + + static unsigned countSupportedTypes(); + static void getSupportedType(unsigned index, const UChar*& str, unsigned& len); + +private: + QTMovieWinPrivate* m_private; + friend class QTMovieWinPrivate; +}; + +#endif diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.cpp b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp new file mode 100644 index 0000000..d0aa3e6 --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieWinTimer.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include <windows.h> + +#include "QTMovieWinTimer.h" + +#include <wtf/Assertions.h> + +// This file is used by the QuickTime access DLL. It copies some WebCore code +// which can't be used directly due to dependency issues. + +// FIXME: Find a way to do timers that can manage <10ms resolution properly too. + +static UINT_PTR timerID; +static void (*sharedTimerFiredFunction)(); + +static HINSTANCE instanceHandle = 0; + +static HWND timerWindowHandle = 0; +static UINT timerFiredMessage = 0; +static const LPCWSTR kTimerWindowClassName = L"TimerWindowClass"; +static bool processingCustomTimerMessage = false; + +static LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == timerFiredMessage) { + processingCustomTimerMessage = true; + sharedTimerFiredFunction(); + processingCustomTimerMessage = false; + } else + return DefWindowProc(hWnd, message, wParam, lParam); + return 0; +} + +static void initializeOffScreenTimerWindow() +{ + if (timerWindowHandle) + return; + + WNDCLASSEX wcex; + memset(&wcex, 0, sizeof(WNDCLASSEX)); + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.lpfnWndProc = TimerWindowWndProc; + wcex.hInstance = instanceHandle; + wcex.lpszClassName = kTimerWindowClassName; + RegisterClassEx(&wcex); + + timerWindowHandle = CreateWindow(kTimerWindowClassName, 0, 0, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, instanceHandle, 0); + timerFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.TimerFired"); +} + +void setSharedTimerFiredFunction(void (*f)()) +{ + sharedTimerFiredFunction = f; +} + +static void CALLBACK timerFired(HWND, UINT, UINT_PTR, DWORD) +{ + sharedTimerFiredFunction(); +} + +void setSharedTimerFireDelay(double interval) +{ + ASSERT(sharedTimerFiredFunction); + + unsigned intervalInMS; + if (interval < 0) + intervalInMS = 0; + else { + interval *= 1000; + if (interval > USER_TIMER_MAXIMUM) + intervalInMS = USER_TIMER_MAXIMUM; + else + intervalInMS = (unsigned)interval; + } + + if (timerID) { + KillTimer(0, timerID); + timerID = 0; + } + + // We don't allow nested PostMessages, since the custom messages will effectively starve + // painting and user input. (Win32 has a tri-level queue with application messages > + // user input > WM_PAINT/WM_TIMER.) + // In addition, if the queue contains input events that have been there since the last call to + // GetQueueStatus, PeekMessage or GetMessage we favor timers. + if (intervalInMS < USER_TIMER_MINIMUM && processingCustomTimerMessage && + !LOWORD(::GetQueueStatus(QS_ALLINPUT))) { + // Windows SetTimer does not allow timeouts smaller than 10ms (USER_TIMER_MINIMUM) + initializeOffScreenTimerWindow(); + PostMessage(timerWindowHandle, timerFiredMessage, 0, 0); + } else + timerID = SetTimer(0, 0, intervalInMS, timerFired); +} + +void stopSharedTimer() +{ + if (timerID) { + KillTimer(0, timerID); + timerID = 0; + } +} + +void setSharedTimerInstanceHandle(HINSTANCE handle) +{ + instanceHandle = handle; +} + +double systemTime() +{ + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + ULARGE_INTEGER t; + memcpy(&t, &ft, sizeof(t)); + return t.QuadPart * 0.0000001 - 11644473600.0; +} diff --git a/WebCore/platform/graphics/win/QTMovieWinTimer.h b/WebCore/platform/graphics/win/QTMovieWinTimer.h new file mode 100644 index 0000000..3e3c2bc --- /dev/null +++ b/WebCore/platform/graphics/win/QTMovieWinTimer.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QTMovieViewTimer_h +#define QTMovieViewTimer_h + +// This header should not be included from WebCore. +// It is used by the QuickTime access DLL. It copies some WebCore code +// which can't be used directly due to dependency issues. + +void setSharedTimerFiredFunction(void (*)()); +void setSharedTimerFireDelay(double delay); +void stopSharedTimer(); +void setSharedTimerInstanceHandle(HINSTANCE handle); +double systemTime(); + +#endif diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp new file mode 100644 index 0000000..4040ed8 --- /dev/null +++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include <winsock2.h> +#include "Font.h" +#include "FontCache.h" +#include "FloatRect.h" +#include "FontDescription.h" +#include <wtf/MathExtras.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <ApplicationServices/ApplicationServices.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> +#include <mlang.h> +#include <tchar.h> + +namespace WebCore { + +using std::max; + +static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x; } + +void SimpleFontData::platformInit() +{ + m_syntheticBoldOffset = m_font.syntheticBold() ? 1.0f : 0.f; + m_scriptCache = 0; + m_scriptFontProperties = 0; + m_isSystemFont = false; + + if (m_font.useGDI()) + return initGDIFont(); + + CGFontRef font = m_font.cgFont(); + int iAscent = CGFontGetAscent(font); + int iDescent = CGFontGetDescent(font); + int iLineGap = CGFontGetLeading(font); + m_unitsPerEm = CGFontGetUnitsPerEm(font); + float pointSize = m_font.size(); + float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize; + float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize; + float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize; + + if (!isCustomFont()) { + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + int faceLength = GetTextFace(dc, 0, 0); + Vector<TCHAR> faceName(faceLength); + GetTextFace(dc, faceLength, faceName.data()); + m_isSystemFont = !_tcscmp(faceName.data(), _T("Lucida Grande")); + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + + if (shouldApplyMacAscentHack()) { + // This code comes from FontDataMac.mm. We only ever do this when running regression tests so that our metrics will match Mac. + + // We need to adjust Times, Helvetica, and Courier to closely match the + // vertical metrics of their Microsoft counterparts that are the de facto + // web standard. The AppKit adjustment of 20% is too big and is + // incorrectly added to line spacing, so we use a 15% adjustment instead + // and add it to the ascent. + if (!_tcscmp(faceName.data(), _T("Times")) || !_tcscmp(faceName.data(), _T("Helvetica")) || !_tcscmp(faceName.data(), _T("Courier"))) + fAscent += floorf(((fAscent + fDescent) * 0.15f) + 0.5f); + } + } + + m_ascent = lroundf(fAscent); + m_descent = lroundf(fDescent); + m_lineGap = lroundf(fLineGap); + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + // Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font. + // Unfortunately, NSFont will round this for us so we don't quite get the right value. + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + Glyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0; + if (xGlyph) { + CGRect xBox; + CGFontGetGlyphBBoxes(font, &xGlyph, 1, &xBox); + // Use the maximum of either width or height because "x" is nearly square + // and web pages that foolishly use this metric for width will be laid out + // poorly if we return an accurate height. Classic case is Times 13 point, + // which has an "x" that is 7x6 pixels. + m_xHeight = scaleEmToUnits(max(CGRectGetMaxX(xBox), CGRectGetMaxY(xBox)), m_unitsPerEm) * pointSize; + } else { + int iXHeight = CGFontGetXHeight(font); + m_xHeight = scaleEmToUnits(iXHeight, m_unitsPerEm) * pointSize; + } +} + +void SimpleFontData::platformDestroy() +{ + if (!isCustomFont()) { + DeleteObject(m_font.hfont()); + CGFontRelease(m_font.cgFont()); + } + + platformCommonDestroy(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + if (m_font.useGDI()) + return widthForGDIGlyph(glyph); + + CGFontRef font = m_font.cgFont(); + float pointSize = m_font.size(); + CGSize advance; + CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize); + + // FIXME: Need to add real support for printer fonts. + bool isPrinterFont = false; + wkGetGlyphAdvances(font, m, m_isSystemFont, isPrinterFont, glyph, advance); + + return advance.width + m_syntheticBoldOffset; +} + +} diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp new file mode 100644 index 0000000..fd017b4 --- /dev/null +++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include <windows.h> + +#include "Font.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "MathExtras.h" +#include "NotImplemented.h" +#include <cairo.h> +#include <cairo-win32.h> +#include <mlang.h> +#include <tchar.h> + +namespace WebCore { + +void SimpleFontData::platformInit() +{ + m_scriptCache = 0; + m_scriptFontProperties = 0; + m_isSystemFont = false; + + if (m_font.useGDI()) + return initGDIFont(); + + HDC hdc = GetDC(0); + SaveDC(hdc); + + cairo_scaled_font_t* scaledFont = m_font.scaledFont(); + const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size(); + + cairo_win32_scaled_font_select_font(scaledFont, hdc); + + TEXTMETRIC textMetrics; + GetTextMetrics(hdc, &textMetrics); + m_ascent = lroundf(textMetrics.tmAscent * metricsMultiplier); + m_descent = lroundf(textMetrics.tmDescent * metricsMultiplier); + m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. + m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier); + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + OUTLINETEXTMETRIC metrics; + if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) { + // This is a TrueType font. We might be able to get an accurate xHeight + GLYPHMETRICS gm; + MAT2 mat = { 1, 0, 0, 1 }; + DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat); + if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) + m_xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier; + } + + cairo_win32_scaled_font_done_font(scaledFont); + + m_isSystemFont = false; + m_scriptCache = 0; + m_scriptFontProperties = 0; + + RestoreDC(hdc, -1); + ReleaseDC(0, hdc); +} + +void SimpleFontData::platformDestroy() +{ + cairo_font_face_destroy(m_font.fontFace()); + cairo_scaled_font_destroy(m_font.scaledFont()); + + DeleteObject(m_font.hfont()); + + platformCommonDestroy(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + if (m_font.useGDI()) + return widthForGDIGlyph(glyph); + + HDC hdc = GetDC(0); + SaveDC(hdc); + + cairo_scaled_font_t* scaledFont = m_font.scaledFont(); + cairo_win32_scaled_font_select_font(scaledFont, hdc); + + int width; + GetCharWidthI(hdc, glyph, 1, 0, &width); + + cairo_win32_scaled_font_done_font(scaledFont); + + RestoreDC(hdc, -1); + ReleaseDC(0, hdc); + + const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size(); + return width * metricsMultiplier; +} + +void SimpleFontData::setFont(cairo_t* cr) const +{ + ASSERT(cr); + m_font.setFont(cr); +} + +} diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp new file mode 100644 index 0000000..6d1c417 --- /dev/null +++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include <winsock2.h> +#include "Font.h" +#include "FontCache.h" +#include "FloatRect.h" +#include "FontDescription.h" +#include <wtf/MathExtras.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <ApplicationServices/ApplicationServices.h> +#include <mlang.h> +#include <tchar.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> + +namespace WebCore { + +using std::max; + +const float cSmallCapsFontSizeMultiplier = 0.7f; + +static bool g_shouldApplyMacAscentHack; + +void SimpleFontData::setShouldApplyMacAscentHack(bool b) +{ + g_shouldApplyMacAscentHack = b; +} + +bool SimpleFontData::shouldApplyMacAscentHack() +{ + return g_shouldApplyMacAscentHack; +} + +void SimpleFontData::initGDIFont() +{ + HDC hdc = GetDC(0); + HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont()); + OUTLINETEXTMETRIC metrics; + GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); + TEXTMETRIC& textMetrics = metrics.otmTextMetrics; + m_ascent = textMetrics.tmAscent; + m_descent = textMetrics.tmDescent; + m_lineGap = textMetrics.tmExternalLeading; + m_lineSpacing = m_ascent + m_descent + m_lineGap; + m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present. + + GLYPHMETRICS gm; + MAT2 mat = { 1, 0, 0, 1 }; + DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat); + if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) + m_xHeight = gm.gmptGlyphOrigin.y; + + m_unitsPerEm = metrics.otmEMSquare; + + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + + return; +} + +void SimpleFontData::platformCommonDestroy() +{ + // We don't hash this on Win32, so it's effectively owned by us. + delete m_smallCapsFontData; + + ScriptFreeCache(&m_scriptCache); + delete m_scriptFontProperties; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + float smallCapsHeight = cSmallCapsFontSizeMultiplier * m_font.size(); + if (isCustomFont()) { + FontPlatformData smallCapsFontData(m_font); + smallCapsFontData.setSize(smallCapsHeight); + m_smallCapsFontData = new SimpleFontData(smallCapsFontData, true, false); + } else { + LOGFONT winfont; + GetObject(m_font.hfont(), sizeof(LOGFONT), &winfont); + winfont.lfHeight = -lroundf(smallCapsHeight * (m_font.useGDI() ? 1 : 32)); + HFONT hfont = CreateFontIndirect(&winfont); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(hfont, smallCapsHeight, fontDescription.bold(), fontDescription.italic(), m_font.useGDI())); + } + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + // FIXME: Support custom fonts. + if (isCustomFont()) + return false; + + // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC + // merely by testing code page intersection. This seems suspect though. Can't a font only partially + // cover a given code page? + IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface(); + if (!langFontLink) + return false; + + HDC dc = GetDC(0); + + DWORD acpCodePages; + langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages); + + DWORD fontCodePages; + langFontLink->GetFontCodePages(dc, m_font.hfont(), &fontCodePages); + + DWORD actualCodePages; + long numCharactersProcessed; + long offset = 0; + while (offset < length) { + langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &numCharactersProcessed); + if ((actualCodePages & fontCodePages) == 0) + return false; + offset += numCharactersProcessed; + } + + ReleaseDC(0, dc); + + return true; +} + +void SimpleFontData::determinePitch() +{ + if (isCustomFont()) { + m_treatAsFixedPitch = false; + return; + } + + // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. + HDC dc = GetDC(0); + SaveDC(dc); + SelectObject(dc, m_font.hfont()); + + // Yes, this looks backwards, but the fixed pitch bit is actually set if the font + // is *not* fixed pitch. Unbelievable but true. + TEXTMETRIC tm; + GetTextMetrics(dc, &tm); + m_treatAsFixedPitch = ((tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); + + RestoreDC(dc, -1); + ReleaseDC(0, dc); +} + +float SimpleFontData::widthForGDIGlyph(Glyph glyph) const +{ + HDC hdc = GetDC(0); + HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont()); + int width; + GetCharWidthI(hdc, glyph, 1, 0, &width); + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + return width; +} + +SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const +{ + if (!m_scriptFontProperties) { + m_scriptFontProperties = new SCRIPT_FONTPROPERTIES; + memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES)); + m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES); + HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties); + if (result == E_PENDING) { + HDC dc = GetDC(0); + SaveDC(dc); + SelectObject(dc, m_font.hfont()); + ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties); + RestoreDC(dc, -1); + ReleaseDC(0, dc); + } + } + return m_scriptFontProperties; +} + +} diff --git a/WebCore/platform/graphics/win/UniscribeController.cpp b/WebCore/platform/graphics/win/UniscribeController.cpp new file mode 100644 index 0000000..876ff43 --- /dev/null +++ b/WebCore/platform/graphics/win/UniscribeController.cpp @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "UniscribeController.h" +#include "Font.h" +#include "SimpleFontData.h" +#include <wtf/MathExtras.h> + +namespace WebCore { + +// FIXME: Rearchitect this to be more like WidthIterator in Font.cpp. Have an advance() method +// that does stuff in that method instead of doing everything in the constructor. Have advance() +// take the GlyphBuffer as an arg so that we don't have to populate the glyph buffer when +// measuring. +UniscribeController::UniscribeController(const Font* font, const TextRun& run) +: m_font(*font) +, m_run(run) +, m_end(run.length()) +, m_currentCharacter(0) +, m_runWidthSoFar(0) +, m_computingOffsetPosition(false) +, m_includePartialGlyphs(false) +, m_offsetX(0) +, m_offsetPosition(0) +{ + m_padding = m_run.padding(); + if (!m_padding) + m_padPerSpace = 0; + else { + float numSpaces = 0; + for (int s = 0; s < m_run.length(); s++) + if (Font::treatAsSpace(m_run[s])) + numSpaces++; + + if (numSpaces == 0) + m_padPerSpace = 0; + else + m_padPerSpace = ceilf(m_run.padding() / numSpaces); + } + + // Null out our uniscribe structs + resetControlAndState(); +} + +int UniscribeController::offsetForPosition(int x, bool includePartialGlyphs) +{ + m_computingOffsetPosition = true; + m_includePartialGlyphs = includePartialGlyphs; + m_offsetX = x; + m_offsetPosition = 0; + advance(m_run.length()); + if (m_computingOffsetPosition) { + // The point is to the left or to the right of the entire run. + if (m_offsetX >= m_runWidthSoFar && m_run.ltr() || m_offsetX < 0 && m_run.rtl()) + m_offsetPosition = m_end; + } + m_computingOffsetPosition = false; + return m_offsetPosition; +} + +void UniscribeController::advance(unsigned offset, GlyphBuffer* glyphBuffer) +{ + // FIXME: We really want to be using a newer version of Uniscribe that supports the new OpenType + // functions. Those functions would allow us to turn off kerning and ligatures. Without being able + // to do that, we will have buggy line breaking and metrics when simple and complex text are close + // together (the complex code path will narrow the text because of kerning and ligatures and then + // when bidi processing splits into multiple runs, the simple portions will get wider and cause us to + // spill off the edge of a line). + if (static_cast<int>(offset) > m_end) + offset = m_end; + + // Itemize the string. + const UChar* cp = m_run.data(m_currentCharacter); + int length = offset - m_currentCharacter; + if (length <= 0) + return; + + unsigned baseCharacter = m_currentCharacter; + + // We break up itemization of the string by fontData and (if needed) the use of small caps. + + // FIXME: It's inconsistent that we use logical order when itemizing, since this + // does not match normal RTL. + + // FIXME: This function should decode surrogate pairs. Currently it makes little difference that + // it does not because the font cache on Windows does not support non-BMP characters. + Vector<UChar, 256> smallCapsBuffer; + if (m_font.isSmallCaps()) + smallCapsBuffer.resize(length); + + unsigned indexOfFontTransition = m_run.rtl() ? length - 1 : 0; + const UChar* curr = m_run.rtl() ? cp + length - 1 : cp; + const UChar* end = m_run.rtl() ? cp - 1 : cp + length; + + const SimpleFontData* fontData; + const SimpleFontData* nextFontData = m_font.glyphDataForCharacter(*curr, false).fontData; + + UChar newC = 0; + + bool isSmallCaps; + bool nextIsSmallCaps = m_font.isSmallCaps() && !(U_GET_GC_MASK(*curr) & U_GC_M_MASK) && (newC = u_toupper(*curr)) != *curr; + + if (nextIsSmallCaps) + smallCapsBuffer[curr - cp] = newC; + + while (true) { + curr = m_run.rtl() ? curr - 1 : curr + 1; + if (curr == end) + break; + + fontData = nextFontData; + isSmallCaps = nextIsSmallCaps; + int index = curr - cp; + UChar c = *curr; + + bool forceSmallCaps = isSmallCaps && (U_GET_GC_MASK(c) & U_GC_M_MASK); + nextFontData = m_font.glyphDataForCharacter(*curr, false, forceSmallCaps).fontData; + if (m_font.isSmallCaps()) { + nextIsSmallCaps = forceSmallCaps || (newC = u_toupper(c)) != c; + if (nextIsSmallCaps) + smallCapsBuffer[index] = forceSmallCaps ? c : newC; + } + + if (nextFontData != fontData || nextIsSmallCaps != isSmallCaps) { + int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition; + int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition; + m_currentCharacter = baseCharacter + itemStart; + itemizeShapeAndPlace((isSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, fontData, glyphBuffer); + indexOfFontTransition = index; + } + } + + int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : length - indexOfFontTransition; + if (itemLength) { + int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; + m_currentCharacter = baseCharacter + itemStart; + itemizeShapeAndPlace((nextIsSmallCaps ? smallCapsBuffer.data() : cp) + itemStart, itemLength, nextFontData, glyphBuffer); + } + + m_currentCharacter = baseCharacter + length; +} + +void UniscribeController::itemizeShapeAndPlace(const UChar* cp, unsigned length, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer) +{ + // ScriptItemize (in Windows XP versions prior to SP2) can overflow by 1. This is why there is an extra empty item + // hanging out at the end of the array + m_items.resize(6); + int numItems = 0; + while (ScriptItemize(cp, length, m_items.size() - 1, &m_control, &m_state, m_items.data(), &numItems) == E_OUTOFMEMORY) { + m_items.resize(m_items.size() * 2); + resetControlAndState(); + } + m_items.resize(numItems + 1); + + if (m_run.rtl()) { + for (int i = m_items.size() - 2; i >= 0; i--) { + if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer)) + return; + } + } else { + for (unsigned i = 0; i < m_items.size() - 1; i++) { + if (!shapeAndPlaceItem(cp, i, fontData, glyphBuffer)) + return; + } + } +} + +void UniscribeController::resetControlAndState() +{ + memset(&m_control, 0, sizeof(SCRIPT_CONTROL)); + memset(&m_state, 0, sizeof(SCRIPT_STATE)); + + // Set up the correct direction for the run. + m_state.uBidiLevel = m_run.rtl(); + + // Lock the correct directional override. + m_state.fOverrideDirection = m_run.directionalOverride(); +} + +bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const SimpleFontData* fontData, GlyphBuffer* glyphBuffer) +{ + // Determine the string for this item. + const UChar* str = cp + m_items[i].iCharPos; + int len = m_items[i+1].iCharPos - m_items[i].iCharPos; + SCRIPT_ITEM item = m_items[i]; + + // Set up buffers to hold the results of shaping the item. + Vector<WORD> glyphs; + Vector<WORD> clusters; + Vector<SCRIPT_VISATTR> visualAttributes; + clusters.resize(len); + + // Shape the item. + // The recommended size for the glyph buffer is 1.5 * the character length + 16 in the uniscribe docs. + // Apparently this is a good size to avoid having to make repeated calls to ScriptShape. + glyphs.resize(1.5 * len + 16); + visualAttributes.resize(glyphs.size()); + + if (!shape(str, len, item, fontData, glyphs, clusters, visualAttributes)) + return true; + + // We now have a collection of glyphs. + Vector<GOFFSET> offsets; + Vector<int> advances; + offsets.resize(glyphs.size()); + advances.resize(glyphs.size()); + int glyphCount = 0; + HRESULT placeResult = ScriptPlace(0, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(), + &item.a, advances.data(), offsets.data(), 0); + if (placeResult == E_PENDING) { + // The script cache isn't primed with enough info yet. We need to select our HFONT into + // a DC and pass the DC in to ScriptPlace. + HDC hdc = GetDC(0); + HFONT hfont = fontData->platformData().hfont(); + HFONT oldFont = (HFONT)SelectObject(hdc, hfont); + placeResult = ScriptPlace(hdc, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(), + &item.a, advances.data(), offsets.data(), 0); + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + } + + if (FAILED(placeResult) || glyphs.isEmpty()) + return true; + + // Convert all chars that should be treated as spaces to use the space glyph. + // We also create a map that allows us to quickly go from space glyphs or rounding + // hack glyphs back to their corresponding characters. + Vector<int> spaceCharacters(glyphs.size()); + spaceCharacters.fill(-1); + Vector<int> roundingHackCharacters(glyphs.size()); + roundingHackCharacters.fill(-1); + Vector<int> roundingHackWordBoundaries(glyphs.size()); + roundingHackWordBoundaries.fill(-1); + + const float cLogicalScale = fontData->m_font.useGDI() ? 1.0f : 32.0f; + unsigned logicalSpaceWidth = fontData->m_spaceWidth * cLogicalScale; + float roundedSpaceWidth = roundf(fontData->m_spaceWidth); + + for (int k = 0; k < len; k++) { + UChar ch = *(str + k); + if (Font::treatAsSpace(ch)) { + // Substitute in the space glyph at the appropriate place in the glyphs + // array. + glyphs[clusters[k]] = fontData->m_spaceGlyph; + advances[clusters[k]] = logicalSpaceWidth; + spaceCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos; + } + + if (Font::isRoundingHackCharacter(ch)) + roundingHackCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos; + + int boundary = k + m_currentCharacter + item.iCharPos; + if (boundary < m_run.length() && + Font::isRoundingHackCharacter(*(str + k + 1))) + roundingHackWordBoundaries[clusters[k]] = boundary; + } + + // Populate our glyph buffer with this information. + bool hasExtraSpacing = m_font.letterSpacing() || m_font.wordSpacing() || m_padding; + + float leftEdge = m_runWidthSoFar; + + for (unsigned k = 0; k < glyphs.size(); k++) { + Glyph glyph = glyphs[k]; + float advance = advances[k] / cLogicalScale; + float offsetX = offsets[k].du / cLogicalScale; + float offsetY = offsets[k].dv / cLogicalScale; + + // Match AppKit's rules for the integer vs. non-integer rendering modes. + float roundedAdvance = roundf(advance); + if (!m_font.isPrinterFont() && !fontData->isSystemFont()) { + advance = roundedAdvance; + offsetX = roundf(offsetX); + offsetY = roundf(offsetY); + } + + // We special case spaces in two ways when applying word rounding. + // First, we round spaces to an adjusted width in all fonts. + // Second, in fixed-pitch fonts we ensure that all glyphs that + // match the width of the space glyph have the same width as the space glyph. + if (roundedAdvance == roundedSpaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && + m_run.applyWordRounding()) + advance = fontData->m_adjustedSpaceWidth; + + if (hasExtraSpacing) { + // If we're a glyph with an advance, go ahead and add in letter-spacing. + // That way we weed out zero width lurkers. This behavior matches the fast text code path. + if (advance && m_font.letterSpacing()) + advance += m_font.letterSpacing(); + + // Handle justification and word-spacing. + if (glyph == fontData->m_spaceGlyph) { + // Account for padding. WebCore uses space padding to justify text. + // We distribute the specified padding over the available spaces in the run. + if (m_padding) { + // Use leftover padding if not evenly divisible by number of spaces. + if (m_padding < m_padPerSpace) { + advance += m_padding; + m_padding = 0; + } else { + advance += m_padPerSpace; + m_padding -= m_padPerSpace; + } + } + + // Account for word-spacing. + int characterIndex = spaceCharacters[k]; + if (characterIndex > 0 && !Font::treatAsSpace(*m_run.data(characterIndex - 1)) && m_font.wordSpacing()) + advance += m_font.wordSpacing(); + } + } + + // Deal with the float/integer impedance mismatch between CG and WebCore. "Words" (characters + // followed by a character defined by isRoundingHackCharacter()) are always an integer width. + // We adjust the width of the last character of a "word" to ensure an integer width. + // Force characters that are used to determine word boundaries for the rounding hack + // to be integer width, so the following words will start on an integer boundary. + int roundingHackIndex = roundingHackCharacters[k]; + if (m_run.applyWordRounding() && roundingHackIndex != -1) + advance = ceilf(advance); + + // Check to see if the next character is a "rounding hack character", if so, adjust the + // width so that the total run width will be on an integer boundary. + int position = m_currentCharacter + len; + bool lastGlyph = (k == glyphs.size() - 1) && (m_run.rtl() ? i == 0 : i == m_items.size() - 2) && (position >= m_end); + if ((m_run.applyWordRounding() && roundingHackWordBoundaries[k] != -1) || + (m_run.applyRunRounding() && lastGlyph)) { + float totalWidth = m_runWidthSoFar + advance; + advance += ceilf(totalWidth) - totalWidth; + } + + m_runWidthSoFar += advance; + + // FIXME: We need to take the GOFFSETS for combining glyphs and store them in the glyph buffer + // as well, so that when the time comes to draw those glyphs, we can apply the appropriate + // translation. + if (glyphBuffer) { + FloatSize size(offsetX, offsetY); + glyphBuffer->add(glyph, fontData, advance, &size); + } + + // Mutate the glyph array to contain our altered advances. + if (m_computingOffsetPosition) + advances[k] = advance; + } + + while (m_computingOffsetPosition && m_offsetX >= leftEdge && m_offsetX < m_runWidthSoFar) { + // The position is somewhere inside this run. + int trailing = 0; + ScriptXtoCP(m_offsetX - leftEdge, clusters.size(), glyphs.size(), clusters.data(), visualAttributes.data(), + advances.data(), &item.a, &m_offsetPosition, &trailing); + if (trailing && m_includePartialGlyphs && m_offsetPosition < len - 1) { + m_offsetPosition += m_currentCharacter + m_items[i].iCharPos; + m_offsetX += m_run.rtl() ? -trailing : trailing; + } else { + m_computingOffsetPosition = false; + m_offsetPosition += m_currentCharacter + m_items[i].iCharPos; + if (trailing && m_includePartialGlyphs) + m_offsetPosition++; + return false; + } + } + + return true; +} + +bool UniscribeController::shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData, + Vector<WORD>& glyphs, Vector<WORD>& clusters, + Vector<SCRIPT_VISATTR>& visualAttributes) +{ + HDC hdc = 0; + HFONT oldFont = 0; + HRESULT shapeResult = E_PENDING; + int glyphCount = 0; + do { + shapeResult = ScriptShape(hdc, fontData->scriptCache(), str, len, glyphs.size(), &item.a, + glyphs.data(), clusters.data(), visualAttributes.data(), &glyphCount); + if (shapeResult == E_PENDING) { + // The script cache isn't primed with enough info yet. We need to select our HFONT into + // a DC and pass the DC in to ScriptShape. + ASSERT(!hdc); + hdc = GetDC(0); + HFONT hfont = fontData->platformData().hfont(); + oldFont = (HFONT)SelectObject(hdc, hfont); + } else if (shapeResult == E_OUTOFMEMORY) { + // Need to resize our buffers. + glyphs.resize(glyphs.size() * 2); + visualAttributes.resize(glyphs.size()); + } + } while (shapeResult == E_PENDING || shapeResult == E_OUTOFMEMORY); + + if (hdc) { + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + } + + if (FAILED(shapeResult)) + return false; + + // 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); + + return true; +} + +} diff --git a/WebCore/platform/graphics/win/UniscribeController.h b/WebCore/platform/graphics/win/UniscribeController.h new file mode 100644 index 0000000..6ea45e1 --- /dev/null +++ b/WebCore/platform/graphics/win/UniscribeController.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UniscribeController_h +#define UniscribeController_h + +#include <usp10.h> +#include "Font.h" +#include "GlyphBuffer.h" +#include "Vector.h" + +namespace WebCore { + +class UniscribeController { +public: + UniscribeController(const Font*, const TextRun&); + + // Advance and measure/place up to the specified character. + void advance(unsigned to, GlyphBuffer* = 0); + + // Compute the character offset for a given x coordinate. + int offsetForPosition(int x, bool includePartialGlyphs); + + // Returns the width of everything we've consumed so far. + float runWidthSoFar() const { return m_runWidthSoFar; } + +private: + void resetControlAndState(); + + void itemizeShapeAndPlace(const UChar*, unsigned length, const SimpleFontData*, GlyphBuffer*); + bool shapeAndPlaceItem(const UChar*, unsigned index, const SimpleFontData*, GlyphBuffer*); + bool shape(const UChar* str, int len, SCRIPT_ITEM item, const SimpleFontData* fontData, + Vector<WORD>& glyphs, Vector<WORD>& clusters, + Vector<SCRIPT_VISATTR>& visualAttributes); + + const Font& m_font; + const TextRun& m_run; + + SCRIPT_CONTROL m_control; + SCRIPT_STATE m_state; + Vector<SCRIPT_ITEM> m_items; + + unsigned m_currentCharacter; + int m_end; + + float m_runWidthSoFar; + float m_padding; + float m_padPerSpace; + + bool m_computingOffsetPosition; + bool m_includePartialGlyphs; + float m_offsetX; + int m_offsetPosition; +}; + +} +#endif diff --git a/WebCore/platform/graphics/wx/AffineTransformWx.cpp b/WebCore/platform/graphics/wx/AffineTransformWx.cpp new file mode 100644 index 0000000..b9c504d --- /dev/null +++ b/WebCore/platform/graphics/wx/AffineTransformWx.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007 Kevin Ollivier All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "AffineTransform.h" + +#include "FloatRect.h" +#include "IntRect.h" +#include "NotImplemented.h" + +#include <stdio.h> +#include <wx/defs.h> +#include <wx/graphics.h> + +namespace WebCore { + +#if USE(WXGC) +AffineTransform::AffineTransform(const wxGraphicsMatrix &matrix) +{ + m_transform = matrix; +} +#endif + +AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f) +{ +#if USE(WXGC) + wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); + m_transform = renderer->CreateMatrix(); + m_transform.Set(a, b, c, d, e, f); +#endif +} + +AffineTransform::AffineTransform() +{ + // NB: If we ever support using Cairo backend on Win/Mac, this will need to be + // changed somehow (though I'm not sure how as we don't have a reference to the + // graphics context here. +#if USE(WXGC) + wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); + m_transform = renderer->CreateMatrix(); +#endif +} + +AffineTransform AffineTransform::inverse() const +{ + notImplemented(); + return *this; +} + +void AffineTransform::map(double x, double y, double *x2, double *y2) const +{ + notImplemented(); +} + +IntRect AffineTransform::mapRect(const IntRect &rect) const +{ + notImplemented(); + return IntRect(); +} + +FloatRect AffineTransform::mapRect(const FloatRect &rect) const +{ + notImplemented(); + return FloatRect(); +} + + +AffineTransform& AffineTransform::scale(double sx, double sy) +{ +#if USE(WXGC) + m_transform.Scale((wxDouble)sx, (wxDouble)sy); +#endif + return *this; +} + +void AffineTransform::reset() +{ + notImplemented(); +} + +AffineTransform& AffineTransform::rotate(double d) +{ +#if USE(WXGC) + m_transform.Rotate((wxDouble)d); +#endif + return *this; +} + +AffineTransform& AffineTransform::translate(double tx, double ty) +{ +#if USE(WXGC) + m_transform.Translate((wxDouble)tx, (wxDouble)ty); +#endif + return *this; +} + +AffineTransform& AffineTransform::shear(double sx, double sy) +{ + notImplemented(); + return *this; +} + +AffineTransform& AffineTransform::operator*=(const AffineTransform& other) +{ + notImplemented(); + return *this; +} + +bool AffineTransform::operator== (const AffineTransform &other) const +{ +#if USE(WXGC) + return m_transform.IsEqual((wxGraphicsMatrix)other); +#endif +} + +AffineTransform AffineTransform::operator* (const AffineTransform &other) +{ + notImplemented(); + return *this; //m_transform * other.m_transform; +} + +double AffineTransform::det() const +{ + notImplemented(); + return 0; +} + +#if USE(WXGC) +AffineTransform::operator wxGraphicsMatrix() const +{ + return m_transform; +} +#endif + +} diff --git a/WebCore/platform/graphics/wx/ColorWx.cpp b/WebCore/platform/graphics/wx/ColorWx.cpp new file mode 100644 index 0000000..0381c59 --- /dev/null +++ b/WebCore/platform/graphics/wx/ColorWx.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2006, 2007 Kevin Ollivier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +#include <wx/defs.h> +#include <wx/colour.h> + +namespace WebCore { + +Color::Color(const wxColour& color) +{ + m_color = makeRGBA((int)color.Red(), (int)color.Green(), (int)color.Blue(), (int)color.Alpha()); +} + +Color::operator wxColour() const +{ + return wxColour(red(), green(), blue(), alpha()); +} + +} diff --git a/WebCore/platform/graphics/wx/FloatRectWx.cpp b/WebCore/platform/graphics/wx/FloatRectWx.cpp new file mode 100644 index 0000000..bb460e5 --- /dev/null +++ b/WebCore/platform/graphics/wx/FloatRectWx.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 Kevin Ollivier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatRect.h" + +#include <wx/defs.h> +#include <wx/graphics.h> + +namespace WebCore { + +#if USE(WXGC) +FloatRect::FloatRect(const wxRect2DDouble& r) + : m_location(FloatPoint(r.m_x, r.m_y)) + , m_size(FloatSize(r.m_width, r.m_height)) +{ +} + +FloatRect::operator wxRect2DDouble() const +{ + return wxRect2DDouble(x(), y(), width(), height()); +} +#endif + +} diff --git a/WebCore/platform/graphics/wx/FontCacheWx.cpp b/WebCore/platform/graphics/wx/FontCacheWx.cpp new file mode 100755 index 0000000..eb41c89 --- /dev/null +++ b/WebCore/platform/graphics/wx/FontCacheWx.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontCache.h" +#include "Font.h" +#include "FontPlatformData.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" + +namespace WebCore { + +void FontCache::platformInit() +{ +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + SimpleFontData* fontData = 0; + fontData = new SimpleFontData(FontPlatformData(font.fontDescription(), font.family().family())); + return fontData; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return new FontPlatformData(font.fontDescription(), font.family().family()); +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) +{ + // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick + // the default that the user would get without changing any prefs. + static AtomicString timesStr("systemfont"); + return getCachedFontPlatformData(fontDescription, timesStr); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + return new FontPlatformData(fontDescription,family); +} + +bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family) +{ + notImplemented(); + return true; +} + +} diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h new file mode 100644 index 0000000..0f4c29b --- /dev/null +++ b/WebCore/platform/graphics/wx/FontPlatformData.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2006 Kevin Ollivier All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontPlatformData_H +#define FontPlatformData_H + +#include "FontDescription.h" +#include "CString.h" +#include "AtomicString.h" +#include "StringImpl.h" + +#include <wx/defs.h> +#include <wx/font.h> + +namespace WebCore { + +class FontPlatformData { +public: + class Deleted {}; + + enum FontState { UNINITIALIZED, DELETED, VALID }; + + FontPlatformData(Deleted) + : m_fontState(DELETED) + { } + + ~FontPlatformData(); + + FontPlatformData(wxFont f) + : m_font(f) + , m_fontState(VALID) + { + m_fontHash = computeHash(); + } + + FontPlatformData(const FontDescription&, const AtomicString&); + + FontPlatformData() + : m_fontState(UNINITIALIZED) + { + } + + wxFont font() const { + return m_font; + } + + unsigned hash() const { + switch (m_fontState) { + case DELETED: + return -1; + case UNINITIALIZED: + return 0; + case VALID: + return computeHash(); + } + } + + bool operator==(const FontPlatformData& other) const + { + if (m_fontState == VALID) + return other.m_fontState == VALID && m_font.Ok() && other.m_font.Ok() && m_font.IsSameAs(other.m_font); + else + return m_fontState == other.m_fontState; + } + + unsigned computeHash() const { + ASSERT(m_font.Ok()); + return reinterpret_cast<unsigned>(&m_font); + } + +private: + wxFont m_font; + FontState m_fontState; + unsigned m_fontHash; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp new file mode 100755 index 0000000..8e7c621 --- /dev/null +++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FontPlatformData.h" + +#include "FontDescription.h" + +#include <wx/defs.h> +#include <wx/gdicmn.h> +#include <wx/font.h> + +namespace WebCore { + +static wxFontFamily fontFamilyToWxFontFamily(const int family) +{ + switch (family) { + case FontDescription::StandardFamily: + return wxFONTFAMILY_DEFAULT; + case FontDescription::SerifFamily: + return wxFONTFAMILY_ROMAN; + case FontDescription::SansSerifFamily: + return wxFONTFAMILY_MODERN; + case FontDescription::MonospaceFamily: + return wxFONTFAMILY_TELETYPE; // TODO: Check these are equivalent + case FontDescription::CursiveFamily: + return wxFONTFAMILY_SCRIPT; + case FontDescription::FantasyFamily: + return wxFONTFAMILY_DECORATIVE; + default: + return wxFONTFAMILY_DEFAULT; + } +} + +static wxFontWeight fontWeightToWxFontWeight(bool isBold) +{ + if (isBold) + return wxFONTWEIGHT_BOLD; + + return wxFONTWEIGHT_NORMAL; +} + +static int italicToWxFontStyle(bool isItalic) +{ + if (isItalic) + return wxFONTSTYLE_ITALIC; + + return wxFONTSTYLE_NORMAL; +} + +FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicString& family) +{ +// NB: The Windows wxFont constructor has two forms, one taking a wxSize (with pixels) +// and one taking an int (points). When points are used, Windows calculates +// a pixel size using an algorithm which causes the size to be way off. However, +// this is a moot issue on Linux and Mac as they only accept the point argument. So, +// we use the pixel size constructor on Windows, but we use point size on Linux and Mac. +#if __WXMSW__ + m_font = wxFont( wxSize(0, -desc.computedPixelSize()), + fontFamilyToWxFontFamily(desc.genericFamily()), + italicToWxFontStyle(desc.italic()), + fontWeightToWxFontWeight(desc.bold()), + false, + family.string() + ); +#else + m_font = wxFont( desc.computedPixelSize(), + fontFamilyToWxFontFamily(desc.genericFamily()), + italicToWxFontStyle(desc.italic()), + fontWeightToWxFontWeight(desc.bold()), + false, + family.string() + ); +#endif + m_fontState = VALID; + m_fontHash = computeHash(); + +} + +FontPlatformData::~FontPlatformData() +{ + m_fontState = UNINITIALIZED; +} + +} diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp new file mode 100644 index 0000000..07223e9 --- /dev/null +++ b/WebCore/platform/graphics/wx/FontWx.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2007 Kevin Ollivier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "FontFallbackList.h" +#include "GlyphBuffer.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" + +#include <wx/dcclient.h> +#include "fontprops.h" +#include "non-kerned-drawing.h" + +namespace WebCore { + +void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, + int from, int numGlyphs, const FloatPoint& point) const +{ + // prepare DC + Color color = graphicsContext->fillColor(); + + // We can't use wx drawing methods on Win/Linux because they automatically kern text + // so we've created a function with platform dependent drawing implementations that + // will hopefully be folded into wx once the API has solidified. + // see platform/wx/wxcode/<platform> for the implementations. + drawTextWithSpacing(graphicsContext, font, color, glyphBuffer, from, numGlyphs, point); +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const +{ + notImplemented(); + return FloatRect(); +} + +void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + notImplemented(); +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + notImplemented(); + return 0; +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const +{ + notImplemented(); + return 0; +} + +} diff --git a/WebCore/platform/graphics/wx/GlyphMapWx.cpp b/WebCore/platform/graphics/wx/GlyphMapWx.cpp new file mode 100755 index 0000000..ebf86e4 --- /dev/null +++ b/WebCore/platform/graphics/wx/GlyphMapWx.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GlyphPageTreeNode.h" + +#include "SimpleFontData.h" +#include <unicode/utf16.h> + +namespace WebCore +{ + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + bool isUtf16 = bufferLength != length; + + for (unsigned i = 0; i < length; i++) { + UChar32 character; + + if(isUtf16) { + UChar lead = buffer[i * 2]; + UChar trail = buffer[i * 2 + 1]; + character = U16_GET_SUPPLEMENTARY(lead, trail); + } else { + character = buffer[i]; + } + + setGlyphDataForIndex(offset + i, character, fontData); + } + + return true; +} + +}
\ No newline at end of file diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp new file mode 100644 index 0000000..951d3a3 --- /dev/null +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#include "AffineTransform.h" +#include "FloatRect.h" +#include "Font.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "Pen.h" +#include <wtf/MathExtras.h> + +#include <math.h> +#include <stdio.h> + +#include <wx/defs.h> +#include <wx/window.h> +#include <wx/dcclient.h> +#include <wx/dcgraph.h> +#include <wx/graphics.h> + +#if __WXMAC__ +#include <Carbon/Carbon.h> +#elif __WXMSW__ +#include <windows.h> +#endif + +namespace WebCore { + +int getWxCompositingOperation(CompositeOperator op, bool hasAlpha) +{ + // FIXME: Add support for more operators. + if (op == CompositeSourceOver && !hasAlpha) + op = CompositeCopy; + + int function; + switch (op) { + case CompositeClear: + function = wxCLEAR; + case CompositeCopy: + function = wxCOPY; + break; + default: + function = wxCOPY; + } + return function; +} + +static int strokeStyleToWxPenStyle(int p) +{ + if (p == SolidStroke) + return wxSOLID; + if (p == DottedStroke) + return wxDOT; + if (p == DashedStroke) + return wxLONG_DASH; + if (p == NoStroke) + return wxTRANSPARENT; + + return wxSOLID; +} + +class GraphicsContextPlatformPrivate { +public: + GraphicsContextPlatformPrivate(); + ~GraphicsContextPlatformPrivate(); + +#if USE(WXGC) + wxGCDC* context; +#else + wxWindowDC* context; +#endif + int mswDCStateID; + wxRegion gtkCurrentClipRgn; + wxRegion gtkPaintClipRgn; +}; + +GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate() : + context(0), + mswDCStateID(0), + gtkCurrentClipRgn(wxRegion()), + gtkPaintClipRgn(wxRegion()) +{ +} + +GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() +{ +} + + +GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate) +{ + setPaintingDisabled(!context); + if (context) { + // Make sure the context starts in sync with our state. + setPlatformFillColor(fillColor()); + setPlatformStrokeColor(strokeColor()); + } +#if USE(WXGC) + m_data->context = (wxGCDC*)context; +#else + m_data->context = (wxWindowDC*)context; +#endif +} + +GraphicsContext::~GraphicsContext() +{ + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + return (PlatformGraphicsContext*)m_data->context; +} + +void GraphicsContext::savePlatformState() +{ + if (m_data->context) + { +#if USE(WXGC) + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + gc->PushState(); +#else + // when everything is working with USE_WXGC, we can remove this + #if __WXMAC__ + CGContextRef context; + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) + context = (CGContextRef)gc->GetNativeContext(); + if (context) + CGContextSaveGState(context); + #elif __WXMSW__ + HDC dc = (HDC)m_data->context->GetHDC(); + m_data->mswDCStateID = ::SaveDC(dc); + #elif __WXGTK__ + m_data->gtkCurrentClipRgn = m_data->context->m_currentClippingRegion; + m_data->gtkPaintClipRgn = m_data->context->m_paintClippingRegion; + #endif +#endif // __WXMAC__ + } +} + +void GraphicsContext::restorePlatformState() +{ + if (m_data->context) + { +#if USE(WXGC) + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + gc->PopState(); +#else + #if __WXMAC__ + CGContextRef context; + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + if (gc) + context = (CGContextRef)gc->GetNativeContext(); + if (context) + CGContextRestoreGState(context); + #elif __WXMSW__ + HDC dc = (HDC)m_data->context->GetHDC(); + ::RestoreDC(dc, m_data->mswDCStateID); + #elif __WXGTK__ + m_data->context->m_currentClippingRegion = m_data->gtkCurrentClipRgn; + m_data->context->m_paintClippingRegion = m_data->gtkPaintClipRgn; + #endif + +#endif // USE_WXGC + } +} + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle()))); + m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height()); +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + FloatPoint p1 = point1; + FloatPoint p2 = point2; + + m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle()))); + m_data->context->DrawLine(point1.x(), point1.y(), point2.x(), point2.y()); +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle()))); + m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height()); +} + +void GraphicsContext::drawImage(WebCore::ImageBuffer*, WebCore::FloatRect const&, WebCore::FloatRect const&) +{ + notImplemented(); +} + +void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) +{ + if (paintingDisabled()) + return; + + m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle()))); + m_data->context->DrawEllipticArc(rect.x(), rect.y(), rect.width(), rect.height(), startAngle, angleSpan); +} + +void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + if (npoints <= 1) + return; + + wxPoint* polygon = new wxPoint[npoints]; + for (size_t i = 0; i < npoints; i++) + polygon[i] = wxPoint(points[i].x(), points[i].y()); + m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle()))); + m_data->context->DrawPolygon((int)npoints, polygon); + delete [] polygon; +} + +void GraphicsContext::fillRect(const 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->SetBrush(wxBrush(color)); + m_data->context->DrawRectangle(rect.x(), rect.y(), rect.width(), rect.height()); +} + +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clip(const IntRect& r) +{ + wxWindowDC* windc = dynamic_cast<wxWindowDC*>(m_data->context); + wxPoint pos(0, 0); + + if (windc) { +#ifndef __WXGTK__ + wxWindow* window = windc->GetWindow(); +#else + wxWindow* window = windc->m_owner; +#endif + if (window) { + wxWindow* parent = window->GetParent(); + // we need to convert from WebView "global" to WebFrame "local" coords. + // FIXME: We only want to go to the top WebView. + while (parent) { + pos += window->GetPosition(); + parent = parent->GetParent(); + } + } + } + + m_data->context->SetClippingRegion(r.x() - pos.x, r.y() - pos.y, r.width() + pos.x, r.height() + pos.y); +} + +void GraphicsContext::clipOut(const Path&) +{ + notImplemented(); +} + +void GraphicsContext::clipOut(const IntRect&) +{ + notImplemented(); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect&) +{ + notImplemented(); +} + +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +{ + if (paintingDisabled()) + return; + + IntPoint endPoint = origin + IntSize(width, 0); + m_data->context->SetPen(wxPen(strokeColor(), strokeThickness(), strokeStyleToWxPenStyle(strokeStyle()))); + m_data->context->DrawLine(origin.x(), origin.y(), endPoint.x(), endPoint.y()); +} + + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin, int width, bool grammar) +{ + if (grammar) + m_data->context->SetPen(wxPen(*wxGREEN, 2, wxLONG_DASH)); + else + m_data->context->SetPen(wxPen(*wxRED, 2, wxLONG_DASH)); + + m_data->context->DrawLine(origin.x(), origin.y(), origin.x() + width, origin.y()); +} + +void GraphicsContext::clip(const Path&) +{ + notImplemented(); +} + +AffineTransform GraphicsContext::getCTM() const +{ + notImplemented(); + return AffineTransform(); +} + +void GraphicsContext::translate(float tx, float ty) +{ +#if USE(WXGC) + if (m_data->context) { + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + gc->Translate(tx, ty); + } +#endif +} + +void GraphicsContext::rotate(float angle) +{ +#if USE(WXGC) + if (m_data->context) { + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + gc->Rotate(angle); + } +#endif +} + +void GraphicsContext::scale(const FloatSize& scale) +{ +#if USE(WXGC) + if (m_data->context) { + wxGraphicsContext* gc = m_data->context->GetGraphicsContext(); + gc->Scale(scale.width(), scale.height()); + } +#endif +} + + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) +{ + FloatRect result; + + wxCoord x = (wxCoord)frect.x(); + wxCoord y = (wxCoord)frect.y(); + + x = m_data->context->LogicalToDeviceX(x); + y = m_data->context->LogicalToDeviceY(y); + result.setX((float)x); + result.setY((float)y); + x = (wxCoord)frect.width(); + y = (wxCoord)frect.height(); + x = m_data->context->LogicalToDeviceXRel(x); + y = m_data->context->LogicalToDeviceYRel(y); + result.setWidth((float)x); + result.setHeight((float)y); + return result; +} + +void GraphicsContext::setURLForRect(const KURL&, const IntRect&) +{ + notImplemented(); +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (m_data->context) + m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false)); +} + +void GraphicsContext::beginPath() +{ + notImplemented(); +} + +void GraphicsContext::addPath(const Path& path) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& color) +{ + if (paintingDisabled()) + return; + + if (m_data->context) + m_data->context->SetPen(wxPen(color, strokeThickness(), strokeStyleToWxPenStyle(strokeStyle()))); +} + +void GraphicsContext::setPlatformStrokeThickness(float thickness) +{ + if (paintingDisabled()) + return; + + if (m_data->context) + m_data->context->SetPen(wxPen(strokeColor(), thickness, strokeStyleToWxPenStyle(strokeStyle()))); + +} + +void GraphicsContext::setPlatformFillColor(const Color& color) +{ + if (paintingDisabled()) + return; + + if (m_data->context) + m_data->context->SetBrush(wxBrush(color)); +} + +void GraphicsContext::concatCTM(const AffineTransform& transform) +{ + if (paintingDisabled()) + return; + + notImplemented(); + return; +} + +void GraphicsContext::setUseAntialiasing(bool enable) +{ + if (paintingDisabled()) + return; + notImplemented(); +} + +void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r) +{ + if (paintingDisabled()) + return; + notImplemented(); +} + +} diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp new file mode 100644 index 0000000..0c832ea --- /dev/null +++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageBuffer.h" + +#include "GraphicsContext.h" +#include "ImageData.h" +#include "NotImplemented.h" + +namespace WebCore { + +std::auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize&, bool grayScale) +{ + return std::auto_ptr<ImageBuffer>(new ImageBuffer()); +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + return 0; +} + +PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&) +{ + notImplemented(); +} + +} diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp new file mode 100644 index 0000000..fc36635 --- /dev/null +++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Kevin Ollivier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageSource.h" + +#include "BMPImageDecoder.h" +#include "GIFImageDecoder.h" +#include "ICOImageDecoder.h" +#include "JPEGImageDecoder.h" +#include "PNGImageDecoder.h" +#include "SharedBuffer.h" +#include "XBMImageDecoder.h" + +#include <wx/defs.h> +#include <wx/bitmap.h> +#include <wx/image.h> +#include <wx/rawbmp.h> + +namespace WebCore { + +ImageDecoder* createDecoder(const SharedBuffer& data) +{ + // We need at least 4 bytes to figure out what kind of image we're dealing with. + int length = data.size(); + if (length < 4) + return 0; + + const unsigned char* uContents = (const unsigned char*)data.data(); + const char* contents = data.data(); + + // GIFs begin with GIF8(7 or 9). + if (strncmp(contents, "GIF8", 4) == 0) + return new GIFImageDecoder(); + + // Test for PNG. + if (uContents[0]==0x89 && + uContents[1]==0x50 && + uContents[2]==0x4E && + uContents[3]==0x47) + return new PNGImageDecoder(); + + // JPEG + if (uContents[0]==0xFF && + uContents[1]==0xD8 && + uContents[2]==0xFF) + return new JPEGImageDecoder(); + + // BMP + if (strncmp(contents, "BM", 2) == 0) + return new BMPImageDecoder(); + + // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. + // CURs begin with 2-byte 0 followed by 2-byte 2. + if (!memcmp(contents, "\000\000\001\000", 4) || + !memcmp(contents, "\000\000\002\000", 4)) + return new ICOImageDecoder(); + + // XBMs require 8 bytes of info. + if (length >= 8 && strncmp(contents, "#define ", 8) == 0) + return new XBMImageDecoder(); + + // Give up. We don't know what the heck this is. + return 0; +} + +ImageSource::ImageSource() + : m_decoder(0) +{} + +ImageSource::~ImageSource() +{ + delete m_decoder; +} + +bool ImageSource::initialized() const +{ + return m_decoder; +} + +void ImageSource::setData(SharedBuffer* data, bool allDataReceived) +{ + // Make the decoder by sniffing the bytes. + // This method will examine the data and instantiate an instance of the appropriate decoder plugin. + // If insufficient bytes are available to determine the image type, no decoder plugin will be + // made. + m_decoder = createDecoder(*data); + if (!m_decoder) + return; + m_decoder->setData(data, allDataReceived); +} + +bool ImageSource::isSizeAvailable() +{ + if (!m_decoder) + return false; + + return m_decoder->isSizeAvailable(); +} + +IntSize ImageSource::size() const +{ + if (!m_decoder) + return IntSize(); + + return m_decoder->size(); +} + +int ImageSource::repetitionCount() +{ + if (!m_decoder) + return cAnimationNone; + + return m_decoder->repetitionCount(); +} + +size_t ImageSource::frameCount() const +{ + return m_decoder ? m_decoder->frameCount() : 0; +} + +bool ImageSource::frameIsCompleteAtIndex(size_t index) +{ + // FIXME: should we be testing the RGBA32Buffer's status as well? + return (m_decoder && m_decoder->frameBufferAtIndex(index) != 0); +} + +void ImageSource::clear() +{ + delete m_decoder; + m_decoder = 0; +} + +NativeImagePtr ImageSource::createFrameAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) + return 0; + + IntRect imageRect = buffer->rect(); + unsigned char* bytes = (unsigned char*)buffer->bytes().data(); + long colorSize = buffer->bytes().size(); + + typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> PixelData; + + int width = size().width(); + int height = size().height(); + + wxBitmap* bmp = new wxBitmap(width, height, 32); + PixelData data(*bmp); + + int rowCounter = 0; + long pixelCounter = 0; + + PixelData::Iterator p(data); + + PixelData::Iterator rowStart = p; + + // NB: It appears that the data is in BGRA format instead of RGBA format. + // This code works properly on both ppc and intel, meaning the issue is + // likely not an issue of byte order getting mixed up on different archs. + for (long i = 0; i < buffer->bytes().size()*4; i+=4) { + p.Red() = bytes[i+2]; + p.Green() = bytes[i+1]; + p.Blue() = bytes[i+0]; + p.Alpha() = bytes[i+3]; + + p++; + + pixelCounter++; + if ( (pixelCounter % width ) == 0 ) { + rowCounter++; + p = rowStart; + p.MoveTo(data, 0, rowCounter); + } + + } + + bmp->UseAlpha(); + ASSERT(bmp->IsOk()); + return bmp; +} + +float ImageSource::frameDurationAtIndex(size_t index) +{ + if (!m_decoder) + return 0; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) + return 0; + + return buffer->duration() / 1000.0f; +} + +bool ImageSource::frameHasAlphaAtIndex(size_t index) +{ + if (!m_decoder || !m_decoder->supportsAlpha()) + return false; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) + return false; + + return buffer->hasAlpha(); +} + +} diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp new file mode 100644 index 0000000..785466c --- /dev/null +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2007 Apple Computer, Kevin Ollivier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" + +#include "AffineTransform.h" +#include "BitmapImage.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" + +#include <math.h> +#include <stdio.h> + +#include <wx/defs.h> +#include <wx/bitmap.h> +#include <wx/dc.h> +#include <wx/dcmemory.h> +#include <wx/dcgraph.h> +#include <wx/graphics.h> +#include <wx/image.h> +#include <wx/thread.h> + +// This function loads resources from WebKit +Vector<char> loadResourceIntoArray(const char*); + +namespace WebCore { + +// this is in GraphicsContextWx.cpp +int getWxCompositingOperation(CompositeOperator op, bool hasAlpha); + +void FrameData::clear() +{ + if (m_frame) { + delete m_frame; + m_frame = 0; + m_duration = 0.; + m_hasAlpha = true; + } +} + +// ================================================ +// Image Class +// ================================================ + +Image* Image::loadPlatformResource(const char *name) +{ + Vector<char> arr = loadResourceIntoArray(name); + Image* img = new BitmapImage(); + RefPtr<SharedBuffer> buffer = new SharedBuffer(arr.data(), arr.size()); + img->setData(buffer, true); + return img; +} + +void BitmapImage::initPlatformData() +{ + // FIXME: NYI +} + +// Drawing Routines + +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +{ + if (!m_source.initialized()) + return; + +#if USE(WXGC) + wxGCDC* context = (wxGCDC*)ctxt->platformContext(); +#else + wxWindowDC* context = ctxt->platformContext(); +#endif + + 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 + + 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); + mydc.SelectObject(wxNullBitmap); + + // NB: delete is causing crashes during page load, but not during the deletion + // itself. It occurs later on when a valid bitmap created in frameAtIndex + // suddenly becomes invalid after returning. It's possible these errors deal + // with reentrancy and threding problems. + //delete bitmap; + startAnimation(); +} + + +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) +{ + if (!m_source.initialized()) + return; + +#if USE(WXGC) + wxGCDC* context = (wxGCDC*)ctxt->platformContext(); +#else + wxWindowDC* context = ctxt->platformContext(); +#endif + + ctxt->save(); + ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height())); + wxBitmap* bitmap = frameAtIndex(m_currentFrame); + if (!bitmap) // If it's too early we won't have an image yet. + return; + + float currentW = 0; + float currentH = 0; + +#if USE(WXGC) + wxGraphicsContext* gc = context->GetGraphicsContext(); + gc->ConcatTransform(patternTransform); +#endif + + wxMemoryDC mydc; + mydc.SelectObject(*bitmap); + + while ( currentW < dstRect.width() ) { + while ( currentH < dstRect.height() ) { + context->Blit((wxCoord)dstRect.x() + currentW, (wxCoord)dstRect.y() + currentH, + (wxCoord)srcRect.width(), (wxCoord)srcRect.height(), &mydc, + (wxCoord)srcRect.x(), (wxCoord)srcRect.y(), wxCOPY, true); + currentH += srcRect.height(); + } + currentW += srcRect.width(); + currentH = 0; + } + ctxt->restore(); + mydc.SelectObject(wxNullBitmap); + + // NB: delete is causing crashes during page load, but not during the deletion + // itself. It occurs later on when a valid bitmap created in frameAtIndex + // suddenly becomes invalid after returning. It's possible these errors deal + // with reentrancy and threding problems. + //delete bitmap; + + startAnimation(); + +} + +void BitmapImage::checkForSolidColor() +{ + +} + +void BitmapImage::invalidatePlatformData() +{ + +} + +} diff --git a/WebCore/platform/graphics/wx/IntPointWx.cpp b/WebCore/platform/graphics/wx/IntPointWx.cpp new file mode 100644 index 0000000..389ac9f --- /dev/null +++ b/WebCore/platform/graphics/wx/IntPointWx.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2006, 2007 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntPoint.h" + +#include <wx/defs.h> +#include <wx/gdicmn.h> + +namespace WebCore { + +IntPoint::IntPoint(const wxPoint& p) + : m_x(p.x) + , m_y(p.y) +{ +} + +IntPoint::operator wxPoint() const +{ + return wxPoint(m_x, m_y); +} + +} diff --git a/WebCore/platform/graphics/wx/IntRectWx.cpp b/WebCore/platform/graphics/wx/IntRectWx.cpp new file mode 100644 index 0000000..10c1b55 --- /dev/null +++ b/WebCore/platform/graphics/wx/IntRectWx.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2006, 2007 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntRect.h" + +#include <wx/defs.h> +#include <wx/gdicmn.h> + +namespace WebCore { + +IntRect::IntRect(const wxRect& r) + : m_location(IntPoint(r.x, r.y)) + , m_size(IntSize(r.width, r.height)) +{ +} + +IntRect::operator wxRect() const +{ + return wxRect(x(), y(), width(), height()); +} + +} diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp new file mode 100644 index 0000000..5ff9914 --- /dev/null +++ b/WebCore/platform/graphics/wx/PathWx.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2007 Kevin Ollivier All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Path.h" + +#include "AffineTransform.h" +#include "FloatPoint.h" +#include "FloatRect.h" +#include "NotImplemented.h" + +#include <stdio.h> + +#include <wx/defs.h> +#include <wx/graphics.h> + +namespace WebCore { + +int getWxWindRuleForWindRule(WindRule rule) +{ + if (rule == RULE_EVENODD) + return wxODDEVEN_RULE; + + return wxWINDING_RULE; +} + +Path::Path() +{ + m_path = 0; + // NB: This only supports the 'default' renderer as determined by wx on + // each platform. If an app uses a non-default renderer (e.g. Cairo on Win), + // there will be problems, but there's no way we can determine which + // renderer an app is using right now with wx API, so we will just handle + // the common case. +#if USE(WXGC) + wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); + if (renderer) { + wxGraphicsPath path = renderer->CreatePath(); + m_path = new wxGraphicsPath(path); + } +#endif +} + +Path::~Path() +{ +} + +Path::Path(const Path& path) +{ + m_path = (PlatformPath*)&path.m_path; +} + +bool Path::contains(const FloatPoint& point, const WindRule rule) const +{ + return false; +} + +void Path::translate(const FloatSize&) +{ + notImplemented(); +} + +FloatRect Path::boundingRect() const +{ +#if USE(WXGC) + if (m_path) { + return m_path->GetBox(); + } +#endif + + return FloatRect(); +} + +Path& Path::operator=(const Path&) +{ + notImplemented(); + return*this; +} + +void Path::clear() +{ + if (m_path) + delete m_path; + +#if USE(WXGC) + wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); + if (renderer) { + wxGraphicsPath path = renderer->CreatePath(); + m_path = new wxGraphicsPath(path); + } +#endif +} + +void Path::moveTo(const FloatPoint& point) +{ +#if USE(WXGC) + if (m_path) + m_path->MoveToPoint(point.x(), point.y()); +#endif +} + +void Path::addLineTo(const FloatPoint&) +{ + notImplemented(); +} + +void Path::addQuadCurveTo(const FloatPoint&, const FloatPoint&) +{ + notImplemented(); +} + +void Path::addBezierCurveTo(const FloatPoint&, const FloatPoint&, const FloatPoint&) +{ + notImplemented(); +} + +void Path::addArcTo(const FloatPoint&, const FloatPoint&, float) +{ + notImplemented(); +} + +void Path::closeSubpath() +{ + notImplemented(); +} + +void Path::addArc(const FloatPoint&, float, float, float, bool) +{ + notImplemented(); +} + +void Path::addRect(const FloatRect&) +{ + notImplemented(); +} + +void Path::addEllipse(const FloatRect&) +{ + notImplemented(); +} + +void Path::transform(const AffineTransform&) +{ + notImplemented(); +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + notImplemented(); +} + +bool Path::isEmpty() const +{ + notImplemented(); + return false; +} + +} diff --git a/WebCore/platform/graphics/wx/PenWx.cpp b/WebCore/platform/graphics/wx/PenWx.cpp new file mode 100644 index 0000000..5a131e3 --- /dev/null +++ b/WebCore/platform/graphics/wx/PenWx.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Pen.h" + +#include <wx/defs.h> +#include <wx/pen.h> +#include <wx/colour.h> + +namespace WebCore { + +// Pen style conversion functions +static int penStyleToWxPenStyle(int p) +{ + if (p == Pen::SolidLine) + return wxSOLID; + if (p == Pen::DotLine) + return wxDOT; + if (p == Pen::DashLine) + return wxLONG_DASH; + if (p == Pen::NoPen) + return wxTRANSPARENT; + + return wxSOLID; +} + +static Pen::PenStyle wxPenStyleToPenStyle(int p) +{ + if (p == wxSOLID) + return Pen::SolidLine; + if (p == wxDOT) + return Pen::DotLine; + if (p == wxLONG_DASH || p == wxSHORT_DASH || p == wxDOT_DASH || p == wxUSER_DASH) + return Pen::DashLine; + if (p == wxTRANSPARENT) + return Pen::NoPen; + + return Pen::SolidLine; +} + +Pen::Pen(const wxPen& p) +{ + wxColour color = p.GetColour(); + setColor(Color(color.Red(), color.Green(), color.Blue())); + setWidth(p.GetWidth()); + setStyle(wxPenStyleToPenStyle(p.GetStyle())); +} + +Pen::operator wxPen() const +{ + return wxPen(wxColour(m_color.red(), m_color.blue(), m_color.green()), width(), penStyleToWxPenStyle(style())); +} + +} diff --git a/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp new file mode 100755 index 0000000..a509933 --- /dev/null +++ b/WebCore/platform/graphics/wx/SimpleFontDataWx.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SimpleFontData.h" + +#include "FontCache.h" +#include "FloatRect.h" +#include "FontDescription.h" +#include <wtf/MathExtras.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> + +#include <wx/defs.h> +#include <wx/dcscreen.h> +#include "fontprops.h" + +namespace WebCore +{ + +void SimpleFontData::platformInit() +{ + wxFont font = m_font.font(); + wxFontProperties props = wxFontProperties(&font); + m_ascent = props.GetAscent(); + m_descent = props.GetDescent(); + m_lineSpacing = props.GetLineSpacing(); + m_xHeight = props.GetXHeight(); + m_unitsPerEm = 1; // FIXME! + m_lineGap = props.GetLineGap(); +} + +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData){ + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(0.70f*fontDescription.computedSize()); + const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family()); + m_smallCapsFontData = new SimpleFontData(*pdata); + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + // FIXME: We will need to implement this to load non-ASCII encoding sites + return true; +} + +void SimpleFontData::determinePitch() +{ + if (m_font.font().Ok()) + m_treatAsFixedPitch = m_font.font().IsFixedWidth(); + else + m_treatAsFixedPitch = false; +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + // TODO: fix this! Make GetTextExtents a method of wxFont in 2.9 + int width = 10; + GetTextExtent(m_font.font(), (wxChar)glyph, &width, NULL); + return width; +} + +} |