diff options
| author | Steve Block <steveblock@google.com> | 2009-12-17 09:55:06 -0800 |
|---|---|---|
| committer | Android Git Automerger <android-git-automerger@android.com> | 2009-12-17 09:55:06 -0800 |
| commit | b880d713c04257ca40abfef97c300afdead423b8 (patch) | |
| tree | 6982576c228bcd1a7efe98afed544d840751094c /WebCore/platform/graphics | |
| parent | e2e7a5c57b53f01e63a0245b4420d54b454cb373 (diff) | |
| parent | 643ca7872b450ea4efacab6188849e5aac2ba161 (diff) | |
| download | external_webkit-b880d713c04257ca40abfef97c300afdead423b8.zip external_webkit-b880d713c04257ca40abfef97c300afdead423b8.tar.gz external_webkit-b880d713c04257ca40abfef97c300afdead423b8.tar.bz2 | |
am 643ca787: Merge webkit.org at r51976 : Initial merge by git.
Merge commit '643ca7872b450ea4efacab6188849e5aac2ba161' into eclair-mr2-plus-aosp
* commit '643ca7872b450ea4efacab6188849e5aac2ba161':
Merge webkit.org at r51976 : Initial merge by git.
Diffstat (limited to 'WebCore/platform/graphics')
126 files changed, 5425 insertions, 3307 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index 13641d2..a07daf2 100644 --- a/WebCore/platform/graphics/BitmapImage.h +++ b/WebCore/platform/graphics/BitmapImage.h @@ -140,8 +140,10 @@ public: virtual CGImageRef getCGImageRef(); #endif -#if PLATFORM(WIN) +#if PLATFORM(WIN) || (PLATFORM(QT) && PLATFORM(WIN_OS)) static PassRefPtr<BitmapImage> create(HBITMAP); +#endif +#if PLATFORM(WIN) virtual bool getHBITMAP(HBITMAP); virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE); #endif @@ -167,13 +169,13 @@ protected: BitmapImage(ImageObserver* = 0); #if PLATFORM(WIN) - virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator); + virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator); #endif - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); #if PLATFORM(WX) || (PLATFORM(WINCE) && !PLATFORM(QT)) virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); #endif #if PLATFORM(HAIKU) diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index 8e51b95..c348166 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -26,6 +26,7 @@ #ifndef Color_h #define Color_h +#include <wtf/FastAllocBase.h> #include <wtf/Platform.h> #if PLATFORM(CG) @@ -68,7 +69,7 @@ RGBA32 makeRGBAFromCMYKA(float c, float m, float y, float k, float a); int differenceSquared(const Color&, const Color&); -class Color { +class Color : public FastAllocBase { public: Color() : m_color(0), m_valid(false) { } Color(RGBA32 col) : m_color(col), m_valid(true) { } diff --git a/WebCore/platform/graphics/ColorSpace.h b/WebCore/platform/graphics/ColorSpace.h new file mode 100644 index 0000000..1bad58c --- /dev/null +++ b/WebCore/platform/graphics/ColorSpace.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ColorSpace_h +#define ColorSpace_h + +namespace WebCore { + + enum ColorSpace { DeviceColorSpace, sRGBColorSpace }; + +} // namespace WebCore + +#endif // ColorSpace_h diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp index 532f719..7a54f21 100644 --- a/WebCore/platform/graphics/FloatRect.cpp +++ b/WebCore/platform/graphics/FloatRect.cpp @@ -102,12 +102,12 @@ void FloatRect::unite(const FloatRect& other) m_size.setHeight(b - t); } -void FloatRect::scale(float s) +void FloatRect::scale(float sx, float sy) { - m_location.setX(x() * s); - m_location.setY(y() * s); - m_size.setWidth(width() * s); - m_size.setHeight(height() * s); + m_location.setX(x() * sx); + m_location.setY(y() * sy); + m_size.setWidth(width() * sx); + m_size.setHeight(height() * sy); } IntRect enclosingIntRect(const FloatRect& rect) diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index 50cb095..4b4694f 100644 --- a/WebCore/platform/graphics/FloatRect.h +++ b/WebCore/platform/graphics/FloatRect.h @@ -120,7 +120,8 @@ public: m_size.setHeight(m_size.height() + dy + dy); } void inflate(float d) { inflateX(d); inflateY(d); } - void scale(float s); + void scale(float s) { scale(s, s); } + void scale(float sx, float sy); #if PLATFORM(CG) FloatRect(const CGRect&); diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h index b88305f..4a6222b 100644 --- a/WebCore/platform/graphics/FontCache.h +++ b/WebCore/platform/graphics/FontCache.h @@ -50,7 +50,7 @@ class FontDescription; class FontSelector; class SimpleFontData; -class FontCache { +class FontCache : public Noncopyable { public: friend FontCache* fontCache(); diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp index bac9da0..eec7ffb 100644 --- a/WebCore/platform/graphics/GeneratedImage.cpp +++ b/WebCore/platform/graphics/GeneratedImage.cpp @@ -34,7 +34,7 @@ using namespace std; namespace WebCore { -void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp) +void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp) { context->save(); context->setCompositeOperation(compositeOp); @@ -48,7 +48,7 @@ void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, co } void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { // Create a BitmapImage and call drawPattern on it. OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size); @@ -62,7 +62,7 @@ void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcR Image* bitmap = imageBuffer->image(); // Now just call drawTiled on that image. - bitmap->drawPattern(context, srcRect, patternTransform, phase, compositeOp, destRect); + bitmap->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, compositeOp, destRect); } } diff --git a/WebCore/platform/graphics/GeneratedImage.h b/WebCore/platform/graphics/GeneratedImage.h index dea0c54..a4583e3 100644 --- a/WebCore/platform/graphics/GeneratedImage.h +++ b/WebCore/platform/graphics/GeneratedImage.h @@ -57,9 +57,9 @@ public: virtual unsigned decodedSize() const { return 0; } protected: - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); GeneratedImage(PassRefPtr<Generator> generator, const IntSize& size) : m_generator(generator) diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index ccdce08..fee05ee 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -120,24 +120,21 @@ void GraphicsContext::setStrokeStyle(const StrokeStyle& style) setPlatformStrokeStyle(style); } -void GraphicsContext::setStrokeColor(const Color& color) +void GraphicsContext::setStrokeColor(const Color& color, ColorSpace colorSpace) { - m_common->state.strokeColorSpace = SolidColorSpace; m_common->state.strokeColor = color; - setPlatformStrokeColor(color); + m_common->state.strokeColorSpace = colorSpace; + m_common->state.strokeGradient.clear(); + m_common->state.strokePattern.clear(); + setPlatformStrokeColor(color, colorSpace); } -ColorSpace GraphicsContext::strokeColorSpace() const -{ - return m_common->state.strokeColorSpace; -} - -void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color) +void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace) { m_common->state.shadowSize = size; m_common->state.shadowBlur = blur; m_common->state.shadowColor = color; - setPlatformShadow(size, blur, color); + setPlatformShadow(size, blur, color, colorSpace); } void GraphicsContext::clearShadow() @@ -172,6 +169,11 @@ Color GraphicsContext::strokeColor() const return m_common->state.strokeColor; } +ColorSpace GraphicsContext::strokeColorSpace() const +{ + return m_common->state.strokeColorSpace; +} + WindRule GraphicsContext::fillRule() const { return m_common->state.fillRule; @@ -182,11 +184,13 @@ void GraphicsContext::setFillRule(WindRule fillRule) m_common->state.fillRule = fillRule; } -void GraphicsContext::setFillColor(const Color& color) +void GraphicsContext::setFillColor(const Color& color, ColorSpace colorSpace) { - m_common->state.fillColorSpace = SolidColorSpace; m_common->state.fillColor = color; - setPlatformFillColor(color); + m_common->state.fillColorSpace = colorSpace; + m_common->state.fillGradient.clear(); + m_common->state.fillPattern.clear(); + setPlatformFillColor(color, colorSpace); } Color GraphicsContext::fillColor() const @@ -194,6 +198,11 @@ Color GraphicsContext::fillColor() const return m_common->state.fillColor; } +ColorSpace GraphicsContext::fillColorSpace() const +{ + return m_common->state.fillColorSpace; +} + void GraphicsContext::setShouldAntialias(bool b) { m_common->state.shouldAntialias = b; @@ -209,10 +218,10 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setStrokeColor(Color::black); + setStrokeColor(Color::black, DeviceColorSpace); return; } - m_common->state.strokeColorSpace = PatternColorSpace; + m_common->state.strokeGradient.clear(); m_common->state.strokePattern = pattern; setPlatformStrokePattern(m_common->state.strokePattern.get()); } @@ -221,10 +230,10 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setFillColor(Color::black); + setFillColor(Color::black, DeviceColorSpace); return; } - m_common->state.fillColorSpace = PatternColorSpace; + m_common->state.fillGradient.clear(); m_common->state.fillPattern = pattern; setPlatformFillPattern(m_common->state.fillPattern.get()); } @@ -233,11 +242,11 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setStrokeColor(Color::black); + setStrokeColor(Color::black, DeviceColorSpace); return; } - m_common->state.strokeColorSpace = GradientColorSpace; m_common->state.strokeGradient = gradient; + m_common->state.strokePattern.clear(); setPlatformStrokeGradient(m_common->state.strokeGradient.get()); } @@ -245,11 +254,11 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setFillColor(Color::black); + setFillColor(Color::black, DeviceColorSpace); return; } - m_common->state.fillColorSpace = GradientColorSpace; m_common->state.fillGradient = gradient; + m_common->state.fillPattern.clear(); setPlatformFillGradient(m_common->state.fillGradient.get()); } @@ -258,11 +267,6 @@ Gradient* GraphicsContext::fillGradient() const return m_common->state.fillGradient.get(); } -ColorSpace GraphicsContext::fillColorSpace() const -{ - return m_common->state.fillColorSpace; -} - Gradient* GraphicsContext::strokeGradient() const { return m_common->state.strokeGradient.get(); @@ -304,24 +308,24 @@ bool GraphicsContext::paintingDisabled() const return m_common->state.paintingDisabled; } -void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& p, CompositeOperator op) { - drawImage(image, p, IntRect(0, 0, -1, -1), op); + drawImage(image, styleColorSpace, p, IntRect(0, 0, -1, -1), op); } -void GraphicsContext::drawImage(Image* image, const IntRect& r, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& r, CompositeOperator op, bool useLowQualityScale) { - drawImage(image, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); + drawImage(image, styleColorSpace, r, IntRect(0, 0, -1, -1), op, useLowQualityScale); } -void GraphicsContext::drawImage(Image* image, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntPoint& dest, const IntRect& srcRect, CompositeOperator op) { - drawImage(image, IntRect(dest, srcRect.size()), srcRect, op); + drawImage(image, styleColorSpace, IntRect(dest, srcRect.size()), srcRect, op); } -void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, CompositeOperator op, bool useLowQualityScale) { - drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale); + drawImage(image, styleColorSpace, FloatRect(dest), srcRect, op, useLowQualityScale); } #if !PLATFORM(WINCE) || PLATFORM(QT) @@ -370,12 +374,12 @@ void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const F bidiResolver.deleteRuns(); } -void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to) +void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, ColorSpace colorSpace, int from, int to) { if (paintingDisabled()) return; - fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor); + fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor, colorSpace); } void GraphicsContext::initFocusRing(int width, int offset) @@ -427,7 +431,7 @@ const Vector<IntRect>& GraphicsContext::focusRingRects() const return m_common->m_focusRingRects; } -void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) +void GraphicsContext::drawImage(Image* image, ColorSpace styleColorSpace, const FloatRect& dest, const FloatRect& src, CompositeOperator op, bool useLowQualityScale) { if (paintingDisabled() || !image) return; @@ -451,29 +455,29 @@ void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const Float save(); setImageInterpolationQuality(InterpolationNone); } - image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), op); + image->draw(this, FloatRect(dest.location(), FloatSize(tw, th)), FloatRect(src.location(), FloatSize(tsw, tsh)), styleColorSpace, op); if (useLowQualityScale) restore(); } -void GraphicsContext::drawTiledImage(Image* image, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) +void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& rect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator op) { if (paintingDisabled() || !image) return; - image->drawTiled(this, rect, srcPoint, tileSize, op); + image->drawTiled(this, rect, srcPoint, tileSize, styleColorSpace, op); } -void GraphicsContext::drawTiledImage(Image* image, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) +void GraphicsContext::drawTiledImage(Image* image, ColorSpace styleColorSpace, const IntRect& dest, const IntRect& srcRect, Image::TileRule hRule, Image::TileRule vRule, CompositeOperator op) { if (paintingDisabled() || !image) return; if (hRule == Image::StretchTile && vRule == Image::StretchTile) // Just do a scale. - return drawImage(image, dest, srcRect, op); + return drawImage(image, styleColorSpace, dest, srcRect, op); - image->drawTiled(this, dest, srcRect, hRule, vRule, op); + image->drawTiled(this, dest, srcRect, hRule, vRule, styleColorSpace, op); } void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 3ffc211..96a6221 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008-2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without @@ -27,6 +27,7 @@ #ifndef GraphicsContext_h #define GraphicsContext_h +#include "ColorSpace.h" #include "DashArray.h" #include "FloatRect.h" #include "Image.h" @@ -111,17 +112,17 @@ namespace WebCore { const int cMisspellingLinePatternWidth = 4; const int cMisspellingLinePatternGapWidth = 1; - class TransformationMatrix; class Font; class Generator; class Gradient; - class GraphicsContextPrivate; class GraphicsContextPlatformPrivate; + class GraphicsContextPrivate; class ImageBuffer; class KURL; class Path; class Pattern; class TextRun; + class TransformationMatrix; // These bits can be ORed together for a total of 8 possible text drawing modes. const int cTextInvisible = 0; @@ -136,18 +137,6 @@ namespace WebCore { DashedStroke }; - // FIXME: This is a place-holder until we decide to add - // real color space support to WebCore. At that time, ColorSpace will be a - // class and instances will be held off of Colors. There will be - // special singleton Gradient and Pattern color spaces to mark when - // a fill or stroke is using a gradient or pattern instead of a solid color. - // https://bugs.webkit.org/show_bug.cgi?id=20558 - enum ColorSpace { - SolidColorSpace, - PatternColorSpace, - GradientColorSpace - }; - enum InterpolationQuality { InterpolationDefault, InterpolationNone, @@ -170,9 +159,8 @@ namespace WebCore { StrokeStyle strokeStyle() const; void setStrokeStyle(const StrokeStyle& style); Color strokeColor() const; - void setStrokeColor(const Color&); - ColorSpace strokeColorSpace() const; + void setStrokeColor(const Color&, ColorSpace); void setStrokePattern(PassRefPtr<Pattern>); Pattern* strokePattern() const; @@ -183,7 +171,8 @@ namespace WebCore { WindRule fillRule() const; void setFillRule(WindRule); Color fillColor() const; - void setFillColor(const Color&); + ColorSpace fillColorSpace() const; + void setFillColor(const Color&, ColorSpace); void setFillPattern(PassRefPtr<Pattern>); Pattern* fillPattern() const; @@ -191,8 +180,6 @@ namespace WebCore { void setFillGradient(PassRefPtr<Gradient>); Gradient* fillGradient() const; - ColorSpace fillColorSpace() const; - void setShadowsIgnoreTransforms(bool); void setShouldAntialias(bool); @@ -250,24 +237,24 @@ namespace WebCore { void strokeArc(const IntRect&, int startAngle, int angleSpan); void fillRect(const FloatRect&); - void fillRect(const FloatRect&, const Color&); + void fillRect(const FloatRect&, const Color&, ColorSpace); void fillRect(const FloatRect&, Generator&); - void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&); + void fillRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color&, ColorSpace); void clearRect(const FloatRect&); void strokeRect(const FloatRect&); void strokeRect(const FloatRect&, float lineWidth); - void drawImage(Image*, const IntPoint&, CompositeOperator = CompositeSourceOver); - void drawImage(Image*, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawImage(Image*, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver); - void drawImage(Image*, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), + void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint&, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, ColorSpace styleColorSpace, const IntRect&, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, ColorSpace styleColorSpace, const IntPoint& destPoint, const IntRect& srcRect, CompositeOperator = CompositeSourceOver); + void drawImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); + void drawImage(Image*, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); - void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, + void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator = CompositeSourceOver); - void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, + void drawTiledImage(Image*, ColorSpace styleColorSpace, const IntRect& destRect, const IntRect& srcRect, Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile, CompositeOperator = CompositeSourceOver); @@ -288,7 +275,7 @@ namespace WebCore { void drawText(const Font&, const TextRun&, const IntPoint&, int from = 0, int to = -1); void drawBidiText(const Font&, const TextRun&, const FloatPoint&); - void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1); + void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, ColorSpace, int from = 0, int to = -1); FloatRect roundToDevicePixels(const FloatRect&); @@ -304,7 +291,7 @@ namespace WebCore { void beginTransparencyLayer(float opacity); void endTransparencyLayer(); - void setShadow(const IntSize&, int blur, const Color&); + void setShadow(const IntSize&, int blur, const Color&, ColorSpace); bool getShadow(IntSize&, int&, Color&) const; void clearShadow(); @@ -322,6 +309,8 @@ namespace WebCore { void setAlpha(float); #if PLATFORM(CAIRO) float getAlpha(); + void createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize); + static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur); #endif void setCompositeOperation(CompositeOperator); @@ -405,12 +394,16 @@ namespace WebCore { void drawWindowsBitmap(WindowsBitmap*, const IntPoint&); #endif -#if PLATFORM(QT) && defined(Q_WS_WIN) +#if (PLATFORM(QT) && defined(Q_WS_WIN)) || (PLATFORM(WX) && PLATFORM(WIN_OS)) HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); bool shouldIncludeChildWindows() const { return false; } #endif +#if PLATFORM(WX) + bool inTransparencyLayer() const { return false; } +#endif + #if PLATFORM(QT) bool inTransparencyLayer() const; PlatformPath* currentPath(); @@ -434,19 +427,19 @@ namespace WebCore { void setPlatformTextDrawingMode(int); void setPlatformFont(const Font& font); - void setPlatformStrokeColor(const Color&); + void setPlatformStrokeColor(const Color&, ColorSpace); void setPlatformStrokeStyle(const StrokeStyle&); void setPlatformStrokeThickness(float); void setPlatformStrokeGradient(Gradient*); void setPlatformStrokePattern(Pattern*); - void setPlatformFillColor(const Color&); + void setPlatformFillColor(const Color&, ColorSpace); void setPlatformFillGradient(Gradient*); void setPlatformFillPattern(Pattern*); void setPlatformShouldAntialias(bool b); - void setPlatformShadow(const IntSize&, int blur, const Color&); + void setPlatformShadow(const IntSize&, int blur, const Color&, ColorSpace); void clearPlatformShadow(); static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle&); diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index 07ec04d..aad8dd4 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -28,9 +28,15 @@ #include "PlatformString.h" +#include <wtf/ListHashSet.h> #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> +// FIXME: Find a better way to avoid the name confliction for NO_ERROR. +#if PLATFORM(CHROMIUM) && PLATFORM(WIN_OS) +#undef NO_ERROR +#endif + #if PLATFORM(MAC) #include <OpenGL/OpenGL.h> @@ -46,20 +52,19 @@ const Platform3DObject NullPlatform3DObject = 0; #endif namespace WebCore { - class CanvasActiveInfo; - class CanvasArray; - class CanvasBuffer; - class CanvasUnsignedByteArray; - class CanvasFloatArray; - class CanvasFramebuffer; - class CanvasIntArray; - class CanvasProgram; - class CanvasRenderbuffer; - class CanvasRenderingContext3D; - class CanvasShader; - class CanvasTexture; - class HTMLCanvasElement; - class HTMLImageElement; + class WebGLActiveInfo; + class WebGLArray; + class WebGLBuffer; + class WebGLUnsignedByteArray; + class WebGLFloatArray; + class WebGLFramebuffer; + class WebGLIntArray; + class WebGLProgram; + class WebGLRenderbuffer; + class WebGLRenderingContext; + class WebGLShader; + class WebGLTexture; + class Image; class HTMLVideoElement; class ImageData; class WebKitCSSMatrix; @@ -77,8 +82,309 @@ namespace WebCore { class GraphicsContext3D : public Noncopyable { public: - enum ShaderType { FRAGMENT_SHADER, VERTEX_SHADER }; - + enum WebGLEnumType { + DEPTH_BUFFER_BIT = 0x00000100, + STENCIL_BUFFER_BIT = 0x00000400, + COLOR_BUFFER_BIT = 0x00004000, + POINTS = 0x0000, + LINES = 0x0001, + LINE_LOOP = 0x0002, + LINE_STRIP = 0x0003, + TRIANGLES = 0x0004, + TRIANGLE_STRIP = 0x0005, + TRIANGLE_FAN = 0x0006, + ZERO = 0, + ONE = 1, + SRC_COLOR = 0x0300, + ONE_MINUS_SRC_COLOR = 0x0301, + SRC_ALPHA = 0x0302, + ONE_MINUS_SRC_ALPHA = 0x0303, + DST_ALPHA = 0x0304, + ONE_MINUS_DST_ALPHA = 0x0305, + DST_COLOR = 0x0306, + ONE_MINUS_DST_COLOR = 0x0307, + SRC_ALPHA_SATURATE = 0x0308, + FUNC_ADD = 0x8006, + BLEND_EQUATION = 0x8009, + BLEND_EQUATION_RGB = 0x8009, + BLEND_EQUATION_ALPHA = 0x883D, + FUNC_SUBTRACT = 0x800A, + FUNC_REVERSE_SUBTRACT = 0x800B, + BLEND_DST_RGB = 0x80C8, + BLEND_SRC_RGB = 0x80C9, + BLEND_DST_ALPHA = 0x80CA, + BLEND_SRC_ALPHA = 0x80CB, + CONSTANT_COLOR = 0x8001, + ONE_MINUS_CONSTANT_COLOR = 0x8002, + CONSTANT_ALPHA = 0x8003, + ONE_MINUS_CONSTANT_ALPHA = 0x8004, + BLEND_COLOR = 0x8005, + ARRAY_BUFFER = 0x8892, + ELEMENT_ARRAY_BUFFER = 0x8893, + ARRAY_BUFFER_BINDING = 0x8894, + ELEMENT_ARRAY_BUFFER_BINDING = 0x8895, + STREAM_DRAW = 0x88E0, + STATIC_DRAW = 0x88E4, + DYNAMIC_DRAW = 0x88E8, + BUFFER_SIZE = 0x8764, + BUFFER_USAGE = 0x8765, + CURRENT_VERTEX_ATTRIB = 0x8626, + FRONT = 0x0404, + BACK = 0x0405, + FRONT_AND_BACK = 0x0408, + TEXTURE_2D = 0x0DE1, + CULL_FACE = 0x0B44, + BLEND = 0x0BE2, + DITHER = 0x0BD0, + STENCIL_TEST = 0x0B90, + DEPTH_TEST = 0x0B71, + SCISSOR_TEST = 0x0C11, + POLYGON_OFFSET_FILL = 0x8037, + SAMPLE_ALPHA_TO_COVERAGE = 0x809E, + SAMPLE_COVERAGE = 0x80A0, + NO_ERROR = 0, + INVALID_ENUM = 0x0500, + INVALID_VALUE = 0x0501, + INVALID_OPERATION = 0x0502, + OUT_OF_MEMORY = 0x0505, + CW = 0x0900, + CCW = 0x0901, + LINE_WIDTH = 0x0B21, + ALIASED_POINT_SIZE_RANGE = 0x846D, + ALIASED_LINE_WIDTH_RANGE = 0x846E, + CULL_FACE_MODE = 0x0B45, + FRONT_FACE = 0x0B46, + DEPTH_RANGE = 0x0B70, + DEPTH_WRITEMASK = 0x0B72, + DEPTH_CLEAR_VALUE = 0x0B73, + DEPTH_FUNC = 0x0B74, + STENCIL_CLEAR_VALUE = 0x0B91, + STENCIL_FUNC = 0x0B92, + STENCIL_FAIL = 0x0B94, + STENCIL_PASS_DEPTH_FAIL = 0x0B95, + STENCIL_PASS_DEPTH_PASS = 0x0B96, + STENCIL_REF = 0x0B97, + STENCIL_VALUE_MASK = 0x0B93, + STENCIL_WRITEMASK = 0x0B98, + STENCIL_BACK_FUNC = 0x8800, + STENCIL_BACK_FAIL = 0x8801, + STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802, + STENCIL_BACK_PASS_DEPTH_PASS = 0x8803, + STENCIL_BACK_REF = 0x8CA3, + STENCIL_BACK_VALUE_MASK = 0x8CA4, + STENCIL_BACK_WRITEMASK = 0x8CA5, + VIEWPORT = 0x0BA2, + SCISSOR_BOX = 0x0C10, + COLOR_CLEAR_VALUE = 0x0C22, + COLOR_WRITEMASK = 0x0C23, + UNPACK_ALIGNMENT = 0x0CF5, + PACK_ALIGNMENT = 0x0D05, + MAX_TEXTURE_SIZE = 0x0D33, + MAX_VIEWPORT_DIMS = 0x0D3A, + SUBPIXEL_BITS = 0x0D50, + RED_BITS = 0x0D52, + GREEN_BITS = 0x0D53, + BLUE_BITS = 0x0D54, + ALPHA_BITS = 0x0D55, + DEPTH_BITS = 0x0D56, + STENCIL_BITS = 0x0D57, + POLYGON_OFFSET_UNITS = 0x2A00, + POLYGON_OFFSET_FACTOR = 0x8038, + TEXTURE_BINDING_2D = 0x8069, + SAMPLE_BUFFERS = 0x80A8, + SAMPLES = 0x80A9, + SAMPLE_COVERAGE_VALUE = 0x80AA, + SAMPLE_COVERAGE_INVERT = 0x80AB, + NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2, + COMPRESSED_TEXTURE_FORMATS = 0x86A3, + DONT_CARE = 0x1100, + FASTEST = 0x1101, + NICEST = 0x1102, + GENERATE_MIPMAP_HINT = 0x8192, + BYTE = 0x1400, + UNSIGNED_BYTE = 0x1401, + SHORT = 0x1402, + UNSIGNED_SHORT = 0x1403, + INT = 0x1404, + UNSIGNED_INT = 0x1405, + FLOAT = 0x1406, + FIXED = 0x140C, + DEPTH_COMPONENT = 0x1902, + ALPHA = 0x1906, + RGB = 0x1907, + RGBA = 0x1908, + LUMINANCE = 0x1909, + LUMINANCE_ALPHA = 0x190A, + UNSIGNED_SHORT_4_4_4_4 = 0x8033, + UNSIGNED_SHORT_5_5_5_1 = 0x8034, + UNSIGNED_SHORT_5_6_5 = 0x8363, + FRAGMENT_SHADER = 0x8B30, + VERTEX_SHADER = 0x8B31, + MAX_VERTEX_ATTRIBS = 0x8869, + MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB, + MAX_VARYING_VECTORS = 0x8DFC, + MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D, + MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C, + MAX_TEXTURE_IMAGE_UNITS = 0x8872, + MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD, + SHADER_TYPE = 0x8B4F, + DELETE_STATUS = 0x8B80, + LINK_STATUS = 0x8B82, + VALIDATE_STATUS = 0x8B83, + ATTACHED_SHADERS = 0x8B85, + ACTIVE_UNIFORMS = 0x8B86, + ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87, + ACTIVE_ATTRIBUTES = 0x8B89, + ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A, + SHADING_LANGUAGE_VERSION = 0x8B8C, + CURRENT_PROGRAM = 0x8B8D, + NEVER = 0x0200, + LESS = 0x0201, + EQUAL = 0x0202, + LEQUAL = 0x0203, + GREATER = 0x0204, + NOTEQUAL = 0x0205, + GEQUAL = 0x0206, + ALWAYS = 0x0207, + KEEP = 0x1E00, + REPLACE = 0x1E01, + INCR = 0x1E02, + DECR = 0x1E03, + INVERT = 0x150A, + INCR_WRAP = 0x8507, + DECR_WRAP = 0x8508, + VENDOR = 0x1F00, + RENDERER = 0x1F01, + VERSION = 0x1F02, + EXTENSIONS = 0x1F03, + NEAREST = 0x2600, + LINEAR = 0x2601, + NEAREST_MIPMAP_NEAREST = 0x2700, + LINEAR_MIPMAP_NEAREST = 0x2701, + NEAREST_MIPMAP_LINEAR = 0x2702, + LINEAR_MIPMAP_LINEAR = 0x2703, + TEXTURE_MAG_FILTER = 0x2800, + TEXTURE_MIN_FILTER = 0x2801, + TEXTURE_WRAP_S = 0x2802, + TEXTURE_WRAP_T = 0x2803, + TEXTURE = 0x1702, + TEXTURE_CUBE_MAP = 0x8513, + TEXTURE_BINDING_CUBE_MAP = 0x8514, + TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515, + TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516, + TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517, + TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518, + TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519, + TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A, + MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C, + TEXTURE0 = 0x84C0, + TEXTURE1 = 0x84C1, + TEXTURE2 = 0x84C2, + TEXTURE3 = 0x84C3, + TEXTURE4 = 0x84C4, + TEXTURE5 = 0x84C5, + TEXTURE6 = 0x84C6, + TEXTURE7 = 0x84C7, + TEXTURE8 = 0x84C8, + TEXTURE9 = 0x84C9, + TEXTURE10 = 0x84CA, + TEXTURE11 = 0x84CB, + TEXTURE12 = 0x84CC, + TEXTURE13 = 0x84CD, + TEXTURE14 = 0x84CE, + TEXTURE15 = 0x84CF, + TEXTURE16 = 0x84D0, + TEXTURE17 = 0x84D1, + TEXTURE18 = 0x84D2, + TEXTURE19 = 0x84D3, + TEXTURE20 = 0x84D4, + TEXTURE21 = 0x84D5, + TEXTURE22 = 0x84D6, + TEXTURE23 = 0x84D7, + TEXTURE24 = 0x84D8, + TEXTURE25 = 0x84D9, + TEXTURE26 = 0x84DA, + TEXTURE27 = 0x84DB, + TEXTURE28 = 0x84DC, + TEXTURE29 = 0x84DD, + TEXTURE30 = 0x84DE, + TEXTURE31 = 0x84DF, + ACTIVE_TEXTURE = 0x84E0, + REPEAT = 0x2901, + CLAMP_TO_EDGE = 0x812F, + MIRRORED_REPEAT = 0x8370, + FLOAT_VEC2 = 0x8B50, + FLOAT_VEC3 = 0x8B51, + FLOAT_VEC4 = 0x8B52, + INT_VEC2 = 0x8B53, + INT_VEC3 = 0x8B54, + INT_VEC4 = 0x8B55, + BOOL = 0x8B56, + BOOL_VEC2 = 0x8B57, + BOOL_VEC3 = 0x8B58, + BOOL_VEC4 = 0x8B59, + FLOAT_MAT2 = 0x8B5A, + FLOAT_MAT3 = 0x8B5B, + FLOAT_MAT4 = 0x8B5C, + SAMPLER_2D = 0x8B5E, + SAMPLER_CUBE = 0x8B60, + VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622, + VERTEX_ATTRIB_ARRAY_SIZE = 0x8623, + VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624, + VERTEX_ATTRIB_ARRAY_TYPE = 0x8625, + VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A, + VERTEX_ATTRIB_ARRAY_POINTER = 0x8645, + VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F, + IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A, + IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B, + COMPILE_STATUS = 0x8B81, + INFO_LOG_LENGTH = 0x8B84, + SHADER_SOURCE_LENGTH = 0x8B88, + SHADER_COMPILER = 0x8DFA, + SHADER_BINARY_FORMATS = 0x8DF8, + NUM_SHADER_BINARY_FORMATS = 0x8DF9, + LOW_FLOAT = 0x8DF0, + MEDIUM_FLOAT = 0x8DF1, + HIGH_FLOAT = 0x8DF2, + LOW_INT = 0x8DF3, + MEDIUM_INT = 0x8DF4, + HIGH_INT = 0x8DF5, + FRAMEBUFFER = 0x8D40, + RENDERBUFFER = 0x8D41, + RGBA4 = 0x8056, + RGB5_A1 = 0x8057, + RGB565 = 0x8D62, + DEPTH_COMPONENT16 = 0x81A5, + STENCIL_INDEX = 0x1901, + STENCIL_INDEX8 = 0x8D48, + RENDERBUFFER_WIDTH = 0x8D42, + RENDERBUFFER_HEIGHT = 0x8D43, + RENDERBUFFER_INTERNAL_FORMAT = 0x8D44, + RENDERBUFFER_RED_SIZE = 0x8D50, + RENDERBUFFER_GREEN_SIZE = 0x8D51, + RENDERBUFFER_BLUE_SIZE = 0x8D52, + RENDERBUFFER_ALPHA_SIZE = 0x8D53, + RENDERBUFFER_DEPTH_SIZE = 0x8D54, + RENDERBUFFER_STENCIL_SIZE = 0x8D55, + FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0, + FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1, + FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2, + FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3, + COLOR_ATTACHMENT0 = 0x8CE0, + DEPTH_ATTACHMENT = 0x8D00, + STENCIL_ATTACHMENT = 0x8D20, + NONE = 0, + FRAMEBUFFER_COMPLETE = 0x8CD5, + FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6, + FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7, + FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9, + FRAMEBUFFER_UNSUPPORTED = 0x8CDD, + FRAMEBUFFER_BINDING = 0x8CA6, + RENDERBUFFER_BINDING = 0x8CA7, + MAX_RENDERBUFFER_SIZE = 0x84E8, + INVALID_FRAMEBUFFER_OPERATION = 0x0506 + }; + static PassOwnPtr<GraphicsContext3D> create(); virtual ~GraphicsContext3D(); @@ -92,7 +398,6 @@ namespace WebCore { PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } Platform3DObject platformTexture() const { return NullPlatform3DObject; } #endif - void checkError() const; void makeContextCurrent(); // Helper to return the size in bytes of OpenGL data types @@ -100,12 +405,12 @@ namespace WebCore { int sizeInBytes(int type); void activeTexture(unsigned long texture); - void attachShader(CanvasProgram* program, CanvasShader* shader); - void bindAttribLocation(CanvasProgram*, unsigned long index, const String& name); - void bindBuffer(unsigned long target, CanvasBuffer*); - void bindFramebuffer(unsigned long target, CanvasFramebuffer*); - void bindRenderbuffer(unsigned long target, CanvasRenderbuffer*); - void bindTexture(unsigned long target, CanvasTexture* texture); + void attachShader(WebGLProgram* program, WebGLShader* shader); + void bindAttribLocation(WebGLProgram*, unsigned long index, const String& name); + void bindBuffer(unsigned long target, WebGLBuffer*); + void bindFramebuffer(unsigned long target, WebGLFramebuffer*); + void bindRenderbuffer(unsigned long target, WebGLRenderbuffer*); + void bindTexture(unsigned long target, WebGLTexture* texture); void blendColor(double red, double green, double blue, double alpha); void blendEquation(unsigned long mode); void blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha); @@ -113,8 +418,8 @@ namespace WebCore { void blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha); void bufferData(unsigned long target, int size, unsigned long usage); - void bufferData(unsigned long target, CanvasArray* data, unsigned long usage); - void bufferSubData(unsigned long target, long offset, CanvasArray* data); + void bufferData(unsigned long target, WebGLArray* data, unsigned long usage); + void bufferSubData(unsigned long target, long offset, WebGLArray* data); unsigned long checkFramebufferStatus(unsigned long target); void clear(unsigned long mask); @@ -122,7 +427,7 @@ namespace WebCore { void clearDepth(double depth); void clearStencil(long s); void colorMask(bool red, bool green, bool blue, bool alpha); - void compileShader(CanvasShader*); + void compileShader(WebGLShader*); //void compressedTexImage2D(unsigned long target, long level, unsigned long internalformat, unsigned long width, unsigned long height, long border, unsigned long imageSize, const void* data); //void compressedTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, unsigned long width, unsigned long height, unsigned long format, unsigned long imageSize, const void* data); @@ -133,7 +438,7 @@ namespace WebCore { void depthFunc(unsigned long func); void depthMask(bool flag); void depthRange(double zNear, double zFar); - void detachShader(CanvasProgram*, CanvasShader*); + void detachShader(WebGLProgram*, WebGLShader*); void disable(unsigned long cap); void disableVertexAttribArray(unsigned long index); void drawArrays(unsigned long mode, long first, long count); @@ -143,84 +448,77 @@ namespace WebCore { void enableVertexAttribArray(unsigned long index); void finish(); void flush(); - void framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, CanvasRenderbuffer*); - void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture*, long level); + void framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer*); + void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture*, long level); void frontFace(unsigned long mode); void generateMipmap(unsigned long target); - bool getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo&); - bool getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo&); + bool getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo&); + bool getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo&); - int getAttribLocation(CanvasProgram*, const String& name); + int getAttribLocation(WebGLProgram*, const String& name); - bool getBoolean(unsigned long pname); - PassRefPtr<CanvasUnsignedByteArray> getBooleanv(unsigned long pname); - int getBufferParameteri(unsigned long target, unsigned long pname); - PassRefPtr<CanvasIntArray> getBufferParameteriv(unsigned long target, unsigned long pname); + void getBooleanv(unsigned long pname, unsigned char* value); + + void getBufferParameteriv(unsigned long target, unsigned long pname, int* value); unsigned long getError(); - float getFloat(unsigned long pname); - PassRefPtr<CanvasFloatArray> getFloatv(unsigned long pname); - int getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname); - PassRefPtr<CanvasIntArray> getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname); - int getInteger(unsigned long pname); - PassRefPtr<CanvasIntArray> getIntegerv(unsigned long pname); - int getProgrami(CanvasProgram*, unsigned long pname); - PassRefPtr<CanvasIntArray> getProgramiv(CanvasProgram*, unsigned long pname); - String getProgramInfoLog(CanvasProgram*); - int getRenderbufferParameteri(unsigned long target, unsigned long pname); - PassRefPtr<CanvasIntArray> getRenderbufferParameteriv(unsigned long target, unsigned long pname); - int getShaderi(CanvasShader*, unsigned long pname); - PassRefPtr<CanvasIntArray> getShaderiv(CanvasShader*, unsigned long pname); - - String getShaderInfoLog(CanvasShader*); + void getFloatv(unsigned long pname, float* value); + + void getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value); + + void getIntegerv(unsigned long pname, int* value); + + void getProgramiv(WebGLProgram* program, unsigned long pname, int* value); + + String getProgramInfoLog(WebGLProgram*); + + void getRenderbufferParameteriv(unsigned long target, unsigned long pname, int* value); + + void getShaderiv(WebGLShader*, unsigned long pname, int* value); + + String getShaderInfoLog(WebGLShader*); // TBD // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); - String getShaderSource(CanvasShader*); + String getShaderSource(WebGLShader*); String getString(unsigned long name); - - float getTexParameterf(unsigned long target, unsigned long pname); - PassRefPtr<CanvasFloatArray> getTexParameterfv(unsigned long target, unsigned long pname); - int getTexParameteri(unsigned long target, unsigned long pname); - PassRefPtr<CanvasIntArray> getTexParameteriv(unsigned long target, unsigned long pname); - - float getUniformf(CanvasProgram* program, long location); - PassRefPtr<CanvasFloatArray> getUniformfv(CanvasProgram* program, long location); - int getUniformi(CanvasProgram* program, long location); - PassRefPtr<CanvasIntArray> getUniformiv(CanvasProgram* program, long location); - - long getUniformLocation(CanvasProgram*, const String& name); - - float getVertexAttribf(unsigned long index, unsigned long pname); - PassRefPtr<CanvasFloatArray> getVertexAttribfv(unsigned long index, unsigned long pname); - int getVertexAttribi(unsigned long index, unsigned long pname); - PassRefPtr<CanvasIntArray> getVertexAttribiv(unsigned long index, unsigned long pname); - + + void getTexParameterfv(unsigned long target, unsigned long pname, float* value); + void getTexParameteriv(unsigned long target, unsigned long pname, int* value); + + void getUniformfv(WebGLProgram* program, long location, float* value); + void getUniformiv(WebGLProgram* program, long location, int* value); + + long getUniformLocation(WebGLProgram*, const String& name); + + void getVertexAttribfv(unsigned long index, unsigned long pname, float* value); + void getVertexAttribiv(unsigned long index, unsigned long pname, int* value); + long getVertexAttribOffset(unsigned long index, unsigned long pname); void hint(unsigned long target, unsigned long mode); - bool isBuffer(CanvasBuffer*); + bool isBuffer(WebGLBuffer*); bool isEnabled(unsigned long cap); - bool isFramebuffer(CanvasFramebuffer*); - bool isProgram(CanvasProgram*); - bool isRenderbuffer(CanvasRenderbuffer*); - bool isShader(CanvasShader*); - bool isTexture(CanvasTexture*); + bool isFramebuffer(WebGLFramebuffer*); + bool isProgram(WebGLProgram*); + bool isRenderbuffer(WebGLRenderbuffer*); + bool isShader(WebGLShader*); + bool isTexture(WebGLTexture*); void lineWidth(double); - void linkProgram(CanvasProgram*); + void linkProgram(WebGLProgram*); void pixelStorei(unsigned long pname, long param); void polygonOffset(double factor, double units); - PassRefPtr<CanvasArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type); + PassRefPtr<WebGLArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type); void releaseShaderCompiler(); void renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height); void sampleCoverage(double value, bool invert); void scissor(long x, long y, unsigned long width, unsigned long height); - void shaderSource(CanvasShader*, const String& string); + void shaderSource(WebGLShader*, const String& string); void stencilFunc(unsigned long func, long ref, unsigned long mask); void stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask); void stencilMask(unsigned long mask); @@ -232,13 +530,11 @@ namespace WebCore { // Currently they return -1 on any error. int texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, - unsigned format, unsigned type, CanvasArray* pixels); + unsigned format, unsigned type, WebGLArray* pixels); int texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, ImageData* pixels); - int texImage2D(unsigned target, unsigned level, HTMLImageElement* image, - bool flipY, bool premultiplyAlpha); - int texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, + int texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha); int texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha); @@ -248,15 +544,12 @@ namespace WebCore { int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, - unsigned format, unsigned type, CanvasArray* pixels); + unsigned format, unsigned type, WebGLArray* pixels); int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, unsigned format, unsigned type, ImageData* pixels); int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, - unsigned width, unsigned height, HTMLImageElement* image, - bool flipY, bool premultiplyAlpha); - int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, - unsigned width, unsigned height, HTMLCanvasElement* canvas, + unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha); int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, unsigned width, unsigned height, HTMLVideoElement* video, @@ -282,8 +575,8 @@ namespace WebCore { void uniformMatrix3fv(long location, bool transpose, float* value, int size); void uniformMatrix4fv(long location, bool transpose, float* value, int size); - void useProgram(CanvasProgram*); - void validateProgram(CanvasProgram*); + void useProgram(WebGLProgram*); + void validateProgram(WebGLProgram*); void vertexAttrib1f(unsigned long indx, float x); void vertexAttrib1fv(unsigned long indx, float* values); @@ -301,7 +594,7 @@ namespace WebCore { void reshape(int width, int height); // Helpers for notification about paint events - void beginPaint(CanvasRenderingContext3D* context); + void beginPaint(WebGLRenderingContext* context); void endPaint(); // Support for buffer creation and deletion @@ -309,7 +602,7 @@ namespace WebCore { unsigned createFramebuffer(); unsigned createProgram(); unsigned createRenderbuffer(); - unsigned createShader(ShaderType); + unsigned createShader(unsigned long); unsigned createTexture(); void deleteBuffer(unsigned); @@ -319,6 +612,16 @@ namespace WebCore { void deleteShader(unsigned); void deleteTexture(unsigned); + // Synthesizes an OpenGL error which will be returned from a + // later call to getError. This is used to emulate OpenGL ES + // 2.0 behavior on the desktop and to enforce additional error + // checking mandated by WebGL. + // + // Per the behavior of glGetError, this stores at most one + // instance of any given error, and returns them from calls to + // getError in the order they were added. + void synthesizeGLError(unsigned long error); + private: GraphicsContext3D(); @@ -331,6 +634,8 @@ namespace WebCore { GLuint m_texture; GLuint m_fbo; GLuint m_depthBuffer; + // Errors raised by synthesizeGLError(). + ListHashSet<unsigned long> m_syntheticErrors; #endif // FIXME: ideally this would be used on all platforms. @@ -343,4 +648,3 @@ namespace WebCore { } // namespace WebCore #endif // GraphicsContext3D_h - diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h index 98baab1..c532162 100644 --- a/WebCore/platform/graphics/GraphicsContextPrivate.h +++ b/WebCore/platform/graphics/GraphicsContextPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,10 +26,10 @@ #ifndef GraphicsContextPrivate_h #define GraphicsContextPrivate_h -#include "TransformationMatrix.h" #include "Gradient.h" #include "GraphicsContext.h" #include "Pattern.h" +#include "TransformationMatrix.h" namespace WebCore { @@ -38,18 +38,18 @@ namespace WebCore { : textDrawingMode(cTextFill) , strokeStyle(SolidStroke) , strokeThickness(0) -#if PLATFORM(CAIRO) - , globalAlpha(1.0f) -#endif - , strokeColorSpace(SolidColorSpace) , strokeColor(Color::black) + , strokeColorSpace(DeviceColorSpace) , fillRule(RULE_NONZERO) - , fillColorSpace(SolidColorSpace) , fillColor(Color::black) + , fillColorSpace(DeviceColorSpace) , shouldAntialias(true) , paintingDisabled(false) , shadowBlur(0) , shadowsIgnoreTransforms(false) +#if PLATFORM(CAIRO) + , globalAlpha(1.0f) +#endif { } @@ -57,19 +57,14 @@ namespace WebCore { StrokeStyle strokeStyle; float strokeThickness; -#if PLATFORM(CAIRO) - float globalAlpha; -#elif PLATFORM(QT) - TransformationMatrix pathTransform; -#endif - ColorSpace strokeColorSpace; Color strokeColor; + ColorSpace strokeColorSpace; RefPtr<Gradient> strokeGradient; RefPtr<Pattern> strokePattern; WindRule fillRule; - ColorSpace fillColorSpace; Color fillColor; + ColorSpace fillColorSpace; RefPtr<Gradient> fillGradient; RefPtr<Pattern> fillPattern; @@ -82,9 +77,14 @@ namespace WebCore { Color shadowColor; bool shadowsIgnoreTransforms; +#if PLATFORM(CAIRO) + float globalAlpha; +#elif PLATFORM(QT) + TransformationMatrix pathTransform; +#endif }; - class GraphicsContextPrivate { + class GraphicsContextPrivate : public Noncopyable { public: GraphicsContextPrivate() : m_focusRingWidth(0) diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index c8582bb..e215097 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -92,6 +92,21 @@ bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const return false; } +bool GraphicsLayer::setChildren(const Vector<GraphicsLayer*>& newChildren) +{ + // If the contents of the arrays are the same, nothing to do. + if (newChildren == m_children) + return false; + + removeAllChildren(); + + size_t listSize = newChildren.size(); + for (size_t i = 0; i < listSize; ++i) + addChild(newChildren[i]); + + return true; +} + void GraphicsLayer::addChild(GraphicsLayer* childLayer) { ASSERT(childLayer != this); diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 85eace0..0456bad 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -53,6 +53,12 @@ typedef CALayer* NativeLayer; typedef void* PlatformLayer; typedef void* NativeLayer; #endif +#elif PLATFORM(WIN) +namespace WebCore { +class WKCACFLayer; +typedef WKCACFLayer PlatformLayer; +typedef void* NativeLayer; +} #else typedef void* PlatformLayer; typedef void* NativeLayer; @@ -176,6 +182,8 @@ public: bool hasAncestor(GraphicsLayer*) const; const Vector<GraphicsLayer*>& children() const { return m_children; } + // Returns true if the child list changed. + virtual bool setChildren(const Vector<GraphicsLayer*>&); // Add child layers. If the child is already parented, it will be removed from its old parent. virtual void addChild(GraphicsLayer*); @@ -292,8 +300,8 @@ public: virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; } CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; } - static bool showDebugBorders(); - static bool showRepaintCounter(); + bool showDebugBorders() { return m_client ? m_client->showDebugBorders() : false; } + bool showRepaintCounter() { return m_client ? m_client->showRepaintCounter() : false; } void updateDebugIndicators(); diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h index 5facc94..afb297d 100644 --- a/WebCore/platform/graphics/GraphicsLayerClient.h +++ b/WebCore/platform/graphics/GraphicsLayerClient.h @@ -62,6 +62,9 @@ public: virtual void notifySyncRequired(const GraphicsLayer*) = 0; virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0; + + virtual bool showDebugBorders() const = 0; + virtual bool showRepaintCounter() const = 0; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h index 444c67c..d7d694a 100644 --- a/WebCore/platform/graphics/Icon.h +++ b/WebCore/platform/graphics/Icon.h @@ -51,7 +51,6 @@ class String; class Icon : public RefCounted<Icon> { public: - static PassRefPtr<Icon> createIconForFile(const String& filename); static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames); ~Icon(); diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp index 80b5457..611216a 100644 --- a/WebCore/platform/graphics/Image.cpp +++ b/WebCore/platform/graphics/Image.cpp @@ -75,14 +75,14 @@ bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived) return dataChanged(allDataReceived); } -void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op) +void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, ColorSpace styleColorSpace, CompositeOperator op) { if (color.alpha() <= 0) return; ctxt->save(); ctxt->setCompositeOperation(!color.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op); - ctxt->fillRect(dstRect, color); + ctxt->fillRect(dstRect, color, styleColorSpace); ctxt->restore(); } @@ -104,10 +104,10 @@ static inline FloatSize calculatePatternScale(const FloatRect& dstRect, const Fl } -void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, CompositeOperator op) +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint, const FloatSize& scaledTileSize, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, destRect, solidColor(), op); + fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, op); return; } @@ -132,22 +132,22 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl 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); + draw(ctxt, destRect, visibleSrcRect, styleColorSpace, op); return; } TransformationMatrix patternTransform = TransformationMatrix().scaleNonUniform(scale.width(), scale.height()); FloatRect tileRect(FloatPoint(), intrinsicTileSize); - drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), op, destRect); + drawPattern(ctxt, tileRect, patternTransform, oneTileRect.location(), styleColorSpace, 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) +void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator op) { if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dstRect, solidColor(), op); + fillWithSolidColor(ctxt, dstRect, solidColor(), styleColorSpace, op); return; } @@ -170,7 +170,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const Flo 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); + drawPattern(ctxt, srcRect, patternTransform, patternPhase, styleColorSpace, op, dstRect); startAnimation(); } diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h index 294ddf6..aef6577 100644 --- a/WebCore/platform/graphics/Image.h +++ b/WebCore/platform/graphics/Image.h @@ -28,6 +28,7 @@ #define Image_h #include "Color.h" +#include "ColorSpace.h" #include "GraphicsTypes.h" #include "ImageSource.h" #include "IntRect.h" @@ -158,21 +159,22 @@ public: protected: Image(ImageObserver* = 0); - static void fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op); + static void fillWithSolidColor(GraphicsContext*, const FloatRect& dstRect, const Color&, ColorSpace styleColorSpace, CompositeOperator); + // The ColorSpace parameter will only be used for untagged images. #if PLATFORM(WIN) - virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator) { } + virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, 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); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator) = 0; + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, ColorSpace styleColorSpace, CompositeOperator); + void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule, ColorSpace styleColorSpace, CompositeOperator); // Supporting tiled drawing virtual bool mayFillWithSolidColor() { return false; } virtual Color solidColor() const { return Color(); } virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator, const FloatRect& destRect); private: RefPtr<SharedBuffer> m_data; // The encoded raw data for the image. diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index b64f82b..4c66c50 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -91,6 +91,9 @@ public: virtual void setVolume(float) { } + virtual bool hasClosedCaptions() const { return false; } + virtual void setClosedCaptionsVisible(bool) { }; + virtual MediaPlayer::NetworkState networkState() const { return MediaPlayer::Empty; } virtual MediaPlayer::ReadyState readyState() const { return MediaPlayer::HaveNothing; } @@ -126,7 +129,7 @@ static MediaPlayerPrivateInterface* createNullMediaPlayer(MediaPlayer* player) // engine support -struct MediaPlayerFactory { +struct MediaPlayerFactory : Noncopyable { MediaPlayerFactory(CreateMediaEnginePlayer constructor, MediaEngineSupportedTypes getSupportedTypes, MediaEngineSupportsType supportsTypeAndCodecs) : constructor(constructor) , getSupportedTypes(getSupportedTypes) @@ -377,6 +380,16 @@ void MediaPlayer::setVolume(float volume) m_private->setVolume(volume); } +bool MediaPlayer::hasClosedCaptions() const +{ + return m_private->hasClosedCaptions(); +} + +void MediaPlayer::setClosedCaptionsVisible(bool closedCaptionsVisible) +{ + m_private->setClosedCaptionsVisible(closedCaptionsVisible); +} + float MediaPlayer::rate() const { return m_rate; diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 4cc6476..ec8ac33 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -37,6 +37,7 @@ #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> #include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> #ifdef __OBJC__ @class QTMovie; @@ -115,7 +116,11 @@ public: class MediaPlayer : public Noncopyable { public: - MediaPlayer(MediaPlayerClient*); + + static PassOwnPtr<MediaPlayer> create(MediaPlayerClient* client) + { + return new MediaPlayer(client); + } virtual ~MediaPlayer(); // media engine support @@ -175,7 +180,10 @@ public: float volume() const; void setVolume(float); - + + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool closedCaptionsVisible); + int dataRate() const; bool autobuffer() const; @@ -223,6 +231,8 @@ public: bool hasSingleSecurityOrigin() const; private: + MediaPlayer(MediaPlayerClient*); + static void initializeMediaEngines(); MediaPlayerClient* m_mediaPlayerClient; diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index f5687b3..03906bd 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -36,7 +36,7 @@ class IntRect; class IntSize; class String; -class MediaPlayerPrivateInterface { +class MediaPlayerPrivateInterface : public Noncopyable { public: virtual ~MediaPlayerPrivateInterface() { } @@ -76,6 +76,9 @@ public: virtual void setVolume(float) = 0; + virtual bool hasClosedCaptions() const { return false; } + virtual void setClosedCaptionsVisible(bool) { } + virtual MediaPlayer::NetworkState networkState() const = 0; virtual MediaPlayer::ReadyState readyState() const = 0; diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index 6b617a0..fef5ad2 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -29,6 +29,7 @@ #define Path_h #include <algorithm> +#include <wtf/FastAllocBase.h> #if PLATFORM(CG) typedef struct CGPath PlatformPath; @@ -93,7 +94,7 @@ namespace WebCore { typedef void (*PathApplierFunction)(void* info, const PathElement*); - class Path { + class Path : public FastAllocBase { public: Path(); ~Path(); diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 1a951c2..3bfa8f3 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -32,6 +32,7 @@ #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContext.h" +#include "ImageBuffer.h" #include "Pattern.h" #include "SimpleFontData.h" #include "TransformationMatrix.h" @@ -85,6 +86,34 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons shadowFillColor.getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha); +#if ENABLE(FILTERS) + cairo_text_extents_t extents; + cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); + + FloatRect rect(FloatPoint(), FloatSize(extents.width, extents.height)); + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0.f; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + GraphicsContext* shadowContext = shadowBuffer->context(); + cairo_t* shadowCr = shadowContext->platformContext(); + + cairo_translate(shadowCr, kernelSize, extents.height + kernelSize); + + cairo_set_scaled_font(shadowCr, font->platformData().scaledFont()); + cairo_show_glyphs(shadowCr, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + cairo_save(shadowCr); + cairo_translate(shadowCr, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(shadowCr, glyphs, numGlyphs); + cairo_restore(shadowCr); + } + cairo_translate(cr, 0.0, -extents.height); + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#else cairo_translate(cr, shadowSize.width(), shadowSize.height()); cairo_show_glyphs(cr, glyphs, numGlyphs); if (font->syntheticBoldOffset()) { @@ -93,6 +122,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_show_glyphs(cr, glyphs, numGlyphs); cairo_restore(cr); } +#endif cairo_restore(cr); } @@ -156,7 +186,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons // Re-enable the platform shadow we disabled earlier if (hasShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 8741c5e..14034fd 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -1,8 +1,9 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> - * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de> + * Copyright (C) 2008, 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,14 +33,17 @@ #if PLATFORM(CAIRO) #include "CairoPath.h" +#include "FEGaussianBlur.h" #include "FloatRect.h" #include "Font.h" #include "ImageBuffer.h" +#include "ImageBufferFilter.h" #include "IntRect.h" #include "NotImplemented.h" #include "Path.h" #include "Pattern.h" #include "SimpleFontData.h" +#include "SourceGraphic.h" #include "TransformationMatrix.h" #include <cairo.h> @@ -69,6 +73,42 @@ static inline void setColor(cairo_t* cr, const Color& col) cairo_set_source_rgba(cr, red, green, blue, alpha); } +static inline void setPlatformFill(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +{ + cairo_save(cr); + if (gcp->state.fillPattern) { + TransformationMatrix affine; + cairo_set_source(cr, gcp->state.fillPattern->createPlatformPattern(affine)); + } else if (gcp->state.fillGradient) + cairo_set_source(cr, gcp->state.fillGradient->platformGradient()); + else + setColor(cr, context->fillColor()); + cairo_clip_preserve(cr); + cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_restore(cr); +} + +static inline void setPlatformStroke(GraphicsContext* context, cairo_t* cr, GraphicsContextPrivate* gcp) +{ + cairo_save(cr); + if (gcp->state.strokePattern) { + TransformationMatrix affine; + cairo_set_source(cr, gcp->state.strokePattern->createPlatformPattern(affine)); + } else if (gcp->state.strokeGradient) + cairo_set_source(cr, gcp->state.strokeGradient->platformGradient()); + else { + Color strokeColor = colorWithOverrideAlpha(context->strokeColor().rgb(), context->strokeColor().alpha() / 255.f * gcp->state.globalAlpha); + setColor(cr, strokeColor); + } + if (gcp->state.globalAlpha < 1.0f && (gcp->state.strokePattern || gcp->state.strokeGradient)) { + cairo_push_group(cr); + cairo_paint_with_alpha(cr, gcp->state.globalAlpha); + cairo_pop_group_to_source(cr); + } + cairo_stroke_preserve(cr); + cairo_restore(cr); +} + // A fillRect helper static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const Color& col) { @@ -78,6 +118,81 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const cairo_fill(cr); } +static inline void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr) +{ + cairo_set_antialias(dstCr, cairo_get_antialias(srcCr)); + + size_t dashCount = cairo_get_dash_count(srcCr); + Vector<double> dashes(dashCount); + + double offset; + cairo_get_dash(srcCr, dashes.data(), &offset); + cairo_set_dash(dstCr, dashes.data(), dashCount, offset); + cairo_set_line_cap(dstCr, cairo_get_line_cap(srcCr)); + cairo_set_line_join(dstCr, cairo_get_line_join(srcCr)); + cairo_set_line_width(dstCr, cairo_get_line_width(srcCr)); + cairo_set_miter_limit(dstCr, cairo_get_miter_limit(srcCr)); + cairo_set_fill_rule(dstCr, cairo_get_fill_rule(srcCr)); +} + +void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& kernelSize, const FloatRect& sourceRect, const IntSize& shadowSize, int shadowBlur) +{ +#if ENABLE(FILTERS) + // calculate the kernel size according to the HTML5 canvas shadow specification + kernelSize = (shadowBlur < 8 ? shadowBlur / 2.f : sqrt(shadowBlur * 2.f)); + int blurRadius = ceil(kernelSize); + + shadowBufferSize = IntSize(sourceRect.width() + blurRadius * 2, sourceRect.height() + blurRadius * 2); + + // determine dimensions of shadow rect + shadowRect = FloatRect(sourceRect.location(), shadowBufferSize); + shadowRect.move(shadowSize.width() - kernelSize, shadowSize.height() - kernelSize); +#endif +} + +static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* gcp, bool fillShadow, bool strokeShadow) +{ +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (!context->getShadow(shadowSize, shadowBlur, shadowColor)) + return; + + // Calculate filter values to create appropriate shadow. + cairo_t* cr = context->platformContext(); + cairo_path_t* path = cairo_copy_path(cr); + double x0, x1, y0, y1; + if (strokeShadow) + cairo_stroke_extents(cr, &x0, &y0, &x1, &y1); + else + cairo_fill_extents(cr, &x0, &y0, &x1, &y1); + FloatRect rect(x0, y0, x1 - x0, y1 - y0); + + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Create suitably-sized ImageBuffer to hold the shadow. + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + + // Draw shadow into a new ImageBuffer. + cairo_t* shadowContext = shadowBuffer->context()->platformContext(); + copyContextProperties(cr, shadowContext); + cairo_translate(shadowContext, -rect.x() + kernelSize, -rect.y() + kernelSize); + cairo_new_path(shadowContext); + cairo_append_path(shadowContext, path); + + if (fillShadow) + setPlatformFill(context, shadowContext, gcp); + if (strokeShadow) + setPlatformStroke(context, shadowContext, gcp); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#endif +} + GraphicsContext::GraphicsContext(PlatformGraphicsContext* cr) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate) @@ -387,30 +502,12 @@ void GraphicsContext::fillPath() return; cairo_t* cr = m_data->cr; - cairo_save(cr); cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - setColor(cr, fillColor()); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - case PatternColorSpace: { - TransformationMatrix affine; - cairo_set_source(cr, m_common->state.fillPattern->createPlatformPattern(affine)); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - } - case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient(); - cairo_set_source(cr, pattern); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - break; - } - cairo_restore(cr); + drawPathShadow(this, m_common, true, false); + + setPlatformFill(this, cr, m_common); + cairo_new_path(cr); } void GraphicsContext::strokePath() @@ -419,45 +516,26 @@ void GraphicsContext::strokePath() return; cairo_t* cr = m_data->cr; - cairo_save(cr); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - float red, green, blue, alpha; - strokeColor().getRGBA(red, green, blue, alpha); - if (m_common->state.globalAlpha < 1.0f) - alpha *= m_common->state.globalAlpha; - cairo_set_source_rgba(cr, red, green, blue, alpha); - cairo_stroke(cr); - break; - case PatternColorSpace: { - TransformationMatrix affine; - cairo_set_source(cr, m_common->state.strokePattern->createPlatformPattern(affine)); - if (m_common->state.globalAlpha < 1.0f) { - cairo_push_group(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - cairo_pop_group_to_source(cr); - } - cairo_stroke(cr); - break; - } - case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient(); - cairo_set_source(cr, pattern); - if (m_common->state.globalAlpha < 1.0f) { - cairo_push_group(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - cairo_pop_group_to_source(cr); - } - cairo_stroke(cr); - break; - } - cairo_restore(cr); + drawPathShadow(this, m_common, false, true); + + setPlatformStroke(this, cr, m_common); + cairo_new_path(cr); + } void GraphicsContext::drawPath() { - fillPath(); - strokePath(); + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + + cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); + drawPathShadow(this, m_common, true, true); + + setPlatformFill(this, cr, m_common); + setPlatformStroke(this, cr, m_common); + cairo_new_path(cr); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -470,11 +548,36 @@ void GraphicsContext::fillRect(const FloatRect& rect) fillPath(); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +static void drawBorderlessRectShadow(GraphicsContext* context, const FloatRect& rect, const Color& rectColor) +{ +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + + if (!context->getShadow(shadowSize, shadowBlur, shadowColor)) + return; + + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize = 0; + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, rect, shadowSize, shadowBlur); + + // Draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + GraphicsContext* shadowContext = shadowBuffer->context(); + shadowContext->fillRect(FloatRect(FloatPoint(kernelSize, kernelSize), rect.size()), rectColor, DeviceColorSpace); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); +#endif +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; + drawBorderlessRectShadow(this, rect, color); if (color.alpha()) fillRectSourceOver(m_data->cr, rect, color); } @@ -634,13 +737,13 @@ IntPoint GraphicsContext::origin() return IntPoint(static_cast<int>(matrix.x0), static_cast<int>(matrix.y0)); } -void GraphicsContext::setPlatformFillColor(const Color& col) +void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) { // Cairo contexts can't hold separate fill and stroke colors // so we set them just before we actually fill or stroke } -void GraphicsContext::setPlatformStrokeColor(const Color& col) +void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) { // Cairo contexts can't hold separate fill and stroke colors // so we set them just before we actually fill or stroke @@ -726,9 +829,48 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer notImplemented(); } -void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&) +void GraphicsContext::setPlatformShadow(IntSize const& size, int, Color const&, ColorSpace) { - notImplemented(); + // Cairo doesn't support shadows natively, they are drawn manually in the draw* + // functions + + if (m_common->state.shadowsIgnoreTransforms) { + // Meaning that this graphics context is associated with a CanvasRenderingContext + // We flip the height since CG and HTML5 Canvas have opposite Y axis + m_common->state.shadowSize = IntSize(size.width(), -size.height()); + } +} + +void GraphicsContext::createPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float kernelSize) +{ +#if ENABLE(FILTERS) + cairo_t* cr = m_data->cr; + + // draw the shadow without blurring, if kernelSize is zero + if (!kernelSize) { + setColor(cr, shadowColor); + cairo_mask_surface(cr, buffer->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y()); + return; + } + + // limit kernel size to 1000, this is what CG is doing. + kernelSize = std::min(1000.f, kernelSize); + + // create filter + RefPtr<Filter> filter = ImageBufferFilter::create(); + filter->setSourceImage(buffer.release()); + RefPtr<FilterEffect> source = SourceGraphic::create(); + source->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); + source->setIsAlphaImage(true); + RefPtr<FilterEffect> blur = FEGaussianBlur::create(source.get(), kernelSize, kernelSize); + blur->setScaledSubRegion(FloatRect(FloatPoint(), shadowRect.size())); + blur->apply(filter.get()); + + // Mask the filter with the shadow color and draw it to the context. + // Masking makes it possible to just blur the alpha channel. + setColor(cr, shadowColor); + cairo_mask_surface(cr, blur->resultImage()->image()->nativeImageForCurrentFrame(), shadowRect.x(), shadowRect.y()); +#endif } void GraphicsContext::clearPlatformShadow() @@ -941,7 +1083,6 @@ void GraphicsContext::clipOut(const Path& path) if (paintingDisabled()) return; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); @@ -952,9 +1093,6 @@ void GraphicsContext::clipOut(const Path& path) cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); -#else - notImplemented(); -#endif } void GraphicsContext::rotate(float radians) @@ -980,19 +1118,15 @@ void GraphicsContext::clipOut(const IntRect& r) if (paintingDisabled()) return; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,4,0) cairo_t* cr = m_data->cr; double x1, y1, x2, y2; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - cairo_rectangle(cr, x1, x2, x2 - x1, y2 - y1); + cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); cairo_rectangle(cr, r.x(), r.y(), r.width(), r.height()); cairo_fill_rule_t savedFillRule = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_clip(cr); cairo_set_fill_rule(cr, savedFillRule); -#else - notImplemented(); -#endif } void GraphicsContext::clipOutEllipseInRect(const IntRect& r) @@ -1005,7 +1139,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& r) clipOut(p); } -void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1015,6 +1149,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& r, const IntSize& topLeft, beginPath(); addPath(Path::createRoundedRectangle(r, topLeft, topRight, bottomLeft, bottomRight)); setColor(cr, color); + drawPathShadow(this, m_common, true, false); cairo_fill(cr); cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 0213944..d991c80 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -136,6 +136,7 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) *pixel = premultipliedARGBFromColor(pixelColor); } } + cairo_surface_mark_dirty_rectangle (m_data.m_surface, 0, 0, m_size.width(), m_size.height()); } template <Multiply multiplied> @@ -260,6 +261,9 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& } srcRows += srcBytesPerRow; } + cairo_surface_mark_dirty_rectangle (data.m_surface, + destx, desty, + numColumns, numRows); } void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index c8c992e..92e36fc 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -89,7 +89,7 @@ BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer) checkForSolidColor(); } -void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { FloatRect srcRect(src); FloatRect dstRect(dst); @@ -105,7 +105,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo return; if (mayFillWithSolidColor()) { - fillWithSolidColor(context, dstRect, solidColor(), op); + fillWithSolidColor(context, dstRect, solidColor(), styleColorSpace, op); return; } @@ -125,17 +125,37 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo // 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); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_PAD); 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 shadow +#if ENABLE(FILTERS) + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { + IntSize shadowBufferSize; + FloatRect shadowRect; + float kernelSize (0.0); + GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, kernelSize, dstRect, shadowSize, shadowBlur); + shadowColor = colorWithOverrideAlpha(shadowColor.rgb(), (shadowColor.alpha() * context->getAlpha()) / 255.f); + + //draw shadow into a new ImageBuffer + OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + cairo_t* shadowContext = shadowBuffer->context()->platformContext(); + cairo_set_source(shadowContext, pattern); + cairo_translate(shadowContext, -dstRect.x(), -dstRect.y()); + cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height()); + cairo_fill(shadowContext); + + context->createPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, kernelSize); + } +#endif + // Draw the image. cairo_translate(cr, dstRect.x(), dstRect.y()); cairo_set_source(cr, pattern); @@ -151,7 +171,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo } void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) { cairo_surface_t* image = nativeImageForCurrentFrame(); if (!image) // If it's too early we won't have an image yet. @@ -180,9 +200,6 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, con 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() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()}; cairo_matrix_t combined; diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 75681bd..8bde57e 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -78,15 +78,7 @@ void Path::clear() 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 + return !cairo_has_current_point(platformPath()->m_cr); } bool Path::hasCurrentPoint() const @@ -256,11 +248,7 @@ FloatRect Path::boundingRect() const { cairo_t* cr = platformPath()->m_cr; double x0, x1, y0, y1; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0) cairo_path_extents(cr, &x0, &y0, &x1, &y1); -#else - cairo_stroke_extents(cr, &x0, &y0, &x1, &y1); -#endif return FloatRect(x0, y0, x1 - x0, y1 - y0); } diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 1350bd3..39f06a6 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -43,26 +43,78 @@ #include <wtf/OwnArrayPtr.h> #include <wtf/RetainPtr.h> -#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) +// Building on 10.6 or later: kCGInterpolationMedium is defined in the CGInterpolationQuality enum. #define HAVE_CG_INTERPOLATION_MEDIUM 1 #endif +#if !defined(TARGETING_TIGER) && !defined(TARGETING_LEOPARD) +// Targeting 10.6 or later: use kCGInterpolationMedium. +#define WTF_USE_CG_INTERPOLATION_MEDIUM 1 +#endif + +#endif + using namespace std; namespace WebCore { -static void setCGFillColor(CGContextRef context, const Color& color) +static CGColorRef createCGColorWithColorSpace(const Color& color, ColorSpace colorSpace) { - CGFloat red, green, blue, alpha; - color.getRGBA(red, green, blue, alpha); - CGContextSetRGBFillColor(context, red, green, blue, alpha); + CGFloat components[4]; + color.getRGBA(components[0], components[1], components[2], components[3]); + + CGColorRef cgColor = 0; + if (colorSpace == sRGBColorSpace) + cgColor = CGColorCreate(sRGBColorSpaceRef(), components); + else + cgColor = CGColorCreate(deviceRGBColorSpaceRef(), components); + + return cgColor; } -static void setCGStrokeColor(CGContextRef context, const Color& color) +static void setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace) { - CGFloat red, green, blue, alpha; - color.getRGBA(red, green, blue, alpha); - CGContextSetRGBStrokeColor(context, red, green, blue, alpha); + CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace); + CGContextSetFillColorWithColor(context, cgColor); + CFRelease(cgColor); +} + +static void setCGStrokeColor(CGContextRef context, const Color& color, ColorSpace colorSpace) +{ + CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace); + CGContextSetStrokeColorWithColor(context, cgColor); + CFRelease(cgColor); +} + +static void setCGFillColorSpace(CGContextRef context, ColorSpace colorSpace) +{ + switch (colorSpace) { + case DeviceColorSpace: + break; + case sRGBColorSpace: + CGContextSetFillColorSpace(context, sRGBColorSpaceRef()); + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +static void setCGStrokeColorSpace(CGContextRef context, ColorSpace colorSpace) +{ + switch (colorSpace) { + case DeviceColorSpace: + break; + case sRGBColorSpace: + CGContextSetStrokeColorSpace(context, sRGBColorSpaceRef()); + break; + default: + ASSERT_NOT_REACHED(); + break; + } } GraphicsContext::GraphicsContext(CGContextRef cgContext) @@ -72,8 +124,8 @@ GraphicsContext::GraphicsContext(CGContextRef cgContext) setPaintingDisabled(!cgContext); if (cgContext) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), fillColorSpace()); + setPlatformStrokeColor(strokeColor(), strokeColorSpace()); } } @@ -123,7 +175,7 @@ void GraphicsContext::drawRect(const IntRect& rect) // We do a fill of four rects to simulate the stroke of a border. Color oldFillColor = fillColor(); if (oldFillColor != strokeColor()) - setCGFillColor(context, strokeColor()); + setCGFillColor(context, strokeColor(), strokeColorSpace()); CGRect rects[4] = { FloatRect(rect.x(), rect.y(), rect.width(), 1), FloatRect(rect.x(), rect.bottom() - 1, rect.width(), 1), @@ -132,7 +184,7 @@ void GraphicsContext::drawRect(const IntRect& rect) }; CGContextFillRects(context, rects, 4); if (oldFillColor != strokeColor()) - setCGFillColor(context, oldFillColor); + setCGFillColor(context, oldFillColor, fillColorSpace()); } } @@ -200,7 +252,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) // 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. + setCGFillColor(context, strokeColor(), strokeColorSpace()); // 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)); @@ -392,7 +444,7 @@ void GraphicsContext::applyStrokePattern() { CGContextRef cgContext = platformContext(); - RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.strokePattern.get()->createPlatformPattern(getCTM())); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.strokePattern->createPlatformPattern(getCTM())); if (!platformPattern) return; @@ -407,7 +459,7 @@ void GraphicsContext::applyFillPattern() { CGContextRef cgContext = platformContext(); - RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.fillPattern.get()->createPlatformPattern(getCTM())); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.fillPattern->createPlatformPattern(getCTM())); if (!platformPattern) return; @@ -420,8 +472,8 @@ void GraphicsContext::applyFillPattern() static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode) { - bool shouldFill = state.fillColorSpace == PatternColorSpace || state.fillColor.alpha(); - bool shouldStroke = state.strokeColorSpace == PatternColorSpace || (state.strokeStyle != NoStroke && state.strokeColor.alpha()); + bool shouldFill = state.fillPattern || state.fillColor.alpha(); + bool shouldStroke = state.strokePattern || (state.strokeStyle != NoStroke && state.strokeColor.alpha()); bool useEOFill = state.fillRule == RULE_EVENODD; if (shouldFill) { @@ -453,16 +505,16 @@ void GraphicsContext::drawPath() CGContextRef context = platformContext(); const GraphicsContextState& state = m_common->state; - if (state.fillColorSpace == GradientColorSpace || state.strokeColorSpace == GradientColorSpace) { + if (state.fillGradient || state.strokeGradient) { // We don't have any optimized way to fill & stroke a path using gradients fillPath(); strokePath(); return; } - if (state.fillColorSpace == PatternColorSpace) + if (state.fillPattern) applyFillPattern(); - if (state.strokeColorSpace == PatternColorSpace) + if (state.strokePattern) applyStrokePattern(); CGPathDrawingMode drawingMode; @@ -484,15 +536,11 @@ void GraphicsContext::fillPath() return; CGContextRef context = platformContext(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - fillPathWithFillRule(context, fillRule()); - break; - case PatternColorSpace: - applyFillPattern(); - fillPathWithFillRule(context, fillRule()); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases? + setCGFillColorSpace(context, m_common->state.fillColorSpace); + + if (m_common->state.fillGradient) { CGContextSaveGState(context); if (fillRule() == RULE_EVENODD) CGContextEOClip(context); @@ -501,8 +549,12 @@ void GraphicsContext::fillPath() CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.fillGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.fillPattern) + applyFillPattern(); + fillPathWithFillRule(context, fillRule()); } void GraphicsContext::strokePath() @@ -511,76 +563,83 @@ void GraphicsContext::strokePath() return; CGContextRef context = platformContext(); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - CGContextStrokePath(context); - break; - case PatternColorSpace: - applyStrokePattern(); - CGContextStrokePath(context); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases? + setCGStrokeColorSpace(context, m_common->state.strokeColorSpace); + + if (m_common->state.strokeGradient) { CGContextSaveGState(context); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); CGContextConcatCTM(context, m_common->state.strokeGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.strokePattern) + applyStrokePattern(); + CGContextStrokePath(context); } void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) return; + CGContextRef context = platformContext(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - CGContextFillRect(context, rect); - break; - case PatternColorSpace: - applyFillPattern(); - CGContextFillRect(context, rect); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the fillPattern and fillGradient cases? + setCGFillColorSpace(context, m_common->state.fillColorSpace); + + if (m_common->state.fillGradient) { CGContextSaveGState(context); CGContextClipToRect(context, rect); CGContextConcatCTM(context, m_common->state.fillGradient->gradientSpaceTransform()); CGContextDrawShading(context, m_common->state.fillGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.fillPattern) + applyFillPattern(); + CGContextFillRect(context, rect); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; CGContextRef context = platformContext(); Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); + ColorSpace oldColorSpace = fillColorSpace(); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, color, colorSpace); + CGContextFillRect(context, rect); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, oldFillColor, oldColorSpace); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; CGContextRef context = platformContext(); Color oldFillColor = fillColor(); - if (oldFillColor != color) - setCGFillColor(context, color); + ColorSpace oldColorSpace = fillColorSpace(); + + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, color, colorSpace); addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); fillPath(); - if (oldFillColor != color) - setCGFillColor(context, oldFillColor); + if (oldFillColor != color || oldColorSpace != colorSpace) + setCGFillColor(context, oldFillColor, oldColorSpace); } void GraphicsContext::clip(const FloatRect& rect) @@ -680,7 +739,7 @@ void GraphicsContext::endTransparencyLayer() m_data->m_userToDeviceTransformKnownToBeIdentity = false; } -void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color) +void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -727,7 +786,7 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col if (!color.isValid()) CGContextSetShadow(context, CGSizeMake(width, height), blurRadius); else { - RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColor(color)); + RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColorWithColorSpace(color, colorSpace)); CGContextSetShadowWithColor(context, CGSizeMake(width, height), blurRadius, @@ -769,15 +828,11 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) return; CGContextRef context = platformContext(); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - CGContextStrokeRectWithWidth(context, r, lineWidth); - break; - case PatternColorSpace: - applyStrokePattern(); - CGContextStrokeRectWithWidth(context, r, lineWidth); - break; - case GradientColorSpace: + + // FIXME: Is this helpful and correct in the strokePattern and strokeGradient cases? + setCGStrokeColorSpace(context, m_common->state.strokeColorSpace); + + if (m_common->state.strokeGradient) { CGContextSaveGState(context); setStrokeThickness(lineWidth); CGContextAddRect(context, r); @@ -785,8 +840,12 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextClip(context); CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient()); CGContextRestoreGState(context); - break; + return; } + + if (m_common->state.strokePattern) + applyStrokePattern(); + CGContextStrokeRectWithWidth(context, r, lineWidth); } void GraphicsContext::setLineCap(LineCap cap) @@ -986,10 +1045,10 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri } if (fillColor() != strokeColor()) - setCGFillColor(platformContext(), strokeColor()); + setCGFillColor(platformContext(), strokeColor(), strokeColorSpace()); CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness)); if (fillColor() != strokeColor()) - setCGFillColor(platformContext(), fillColor()); + setCGFillColor(platformContext(), fillColor(), fillColorSpace()); if (restoreAntialiasMode) CGContextSetShouldAntialias(platformContext(), true); @@ -1034,9 +1093,9 @@ void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode) quality = kCGInterpolationLow; break; - // Fall through to InterpolationHigh if kCGInterpolationMedium is not available + // Fall through to InterpolationHigh if kCGInterpolationMedium is not usable. case InterpolationMedium: -#if HAVE(CG_INTERPOLATION_MEDIUM) +#if USE(CG_INTERPOLATION_MEDIUM) quality = kCGInterpolationMedium; break; #endif @@ -1061,9 +1120,15 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const case kCGInterpolationLow: return InterpolationLow; #if HAVE(CG_INTERPOLATION_MEDIUM) + // kCGInterpolationMedium is known to be present in the CGInterpolationQuality enum. case kCGInterpolationMedium: +#if USE(CG_INTERPOLATION_MEDIUM) + // Only map to InterpolationMedium if targeting a system that understands it. return InterpolationMedium; -#endif +#else + return InterpolationDefault; +#endif // USE(CG_INTERPOLATION_MEDIUM) +#endif // HAVE(CG_INTERPOLATION_MEDIUM) case kCGInterpolationHigh: return InterpolationHigh; } @@ -1107,11 +1172,11 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) } } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; - setCGStrokeColor(platformContext(), color); + setCGStrokeColor(platformContext(), color, colorSpace); } void GraphicsContext::setPlatformStrokeThickness(float thickness) @@ -1121,11 +1186,11 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) CGContextSetLineWidth(platformContext(), thickness); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; - setCGFillColor(platformContext(), color); + setCGFillColor(platformContext(), color, colorSpace); } void GraphicsContext::setPlatformShouldAntialias(bool enable) diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index 38c5506..ff1816f 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -27,6 +27,25 @@ namespace WebCore { +// FIXME: This would be in GraphicsContextCG.h if that existed. +inline CGColorSpaceRef deviceRGBColorSpaceRef() +{ + static CGColorSpaceRef deviceSpace = CGColorSpaceCreateDeviceRGB(); + return deviceSpace; +} + +// FIXME: This would be in GraphicsContextCG.h if that existed. +inline CGColorSpaceRef sRGBColorSpaceRef() +{ + // FIXME: Windows should be able to use kCGColorSpaceSRGB, this is tracked by http://webkit.org/b/31363. +#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER) + return deviceRGBColorSpaceRef(); +#else + static CGColorSpaceRef sRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + return sRGBSpace; +#endif +} + class GraphicsContextPlatformPrivate { public: GraphicsContextPlatformPrivate(CGContextRef cgContext) diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp index 4da7018..2e372e2 100644 --- a/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -32,6 +32,7 @@ #include "FloatConversion.h" #include "FloatRect.h" #include "GraphicsContext.h" +#include "GraphicsContextPlatformPrivateCG.h" #include "ImageObserver.h" #include "PDFDocumentImage.h" #include "PlatformString.h" @@ -127,25 +128,46 @@ void BitmapImage::checkForSolidColor() } } +static RetainPtr<CGImageRef> imageWithColorSpace(CGImageRef originalImage, ColorSpace colorSpace) +{ + CGColorSpaceRef originalColorSpace = CGImageGetColorSpace(originalImage); + + // If the image already has a (non-device) color space, we don't want to + // override it, so return. + if (!originalColorSpace || !CFEqual(originalColorSpace, deviceRGBColorSpaceRef())) + return originalImage; + + switch (colorSpace) { + case DeviceColorSpace: + return originalImage; + case sRGBColorSpace: + return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, + sRGBColorSpaceRef())); + } + + ASSERT_NOT_REACHED(); + return originalImage; +} + CGImageRef BitmapImage::getCGImageRef() { return frameAtIndex(0); } -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp) { startAnimation(); - CGImageRef image = frameAtIndex(m_currentFrame); + RetainPtr<CGImageRef> image = frameAtIndex(m_currentFrame); if (!image) // If it's too early we won't have an image yet. return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, destRect, solidColor(), compositeOp); + fillWithSolidColor(ctxt, destRect, solidColor(), styleColorSpace, compositeOp); return; } - float currHeight = CGImageGetHeight(image); + float currHeight = CGImageGetHeight(image.get()); if (currHeight <= srcRect.y()) return; @@ -181,10 +203,10 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F subimageRect.setHeight(ceilf(subimageRect.height() + topPadding)); adjustedDestRect.setHeight(subimageRect.height() / yScale); - image = CGImageCreateWithImageInRect(image, subimageRect); + image.adoptCF(CGImageCreateWithImageInRect(image.get(), subimageRect)); if (currHeight < srcRect.bottom()) { - ASSERT(CGImageGetHeight(image) == currHeight - CGRectIntegral(srcRect).origin.y); - adjustedDestRect.setHeight(CGImageGetHeight(image) / yScale); + ASSERT(CGImageGetHeight(image.get()) == currHeight - CGRectIntegral(srcRect).origin.y); + adjustedDestRect.setHeight(CGImageGetHeight(image.get()) / yScale); } } else { adjustedDestRect.setLocation(FloatPoint(destRect.x() - srcRect.x() / xScale, destRect.y() - srcRect.y() / yScale)); @@ -204,11 +226,11 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F CGContextScaleCTM(context, 1, -1); adjustedDestRect.setY(-adjustedDestRect.bottom()); - // Draw the image. - CGContextDrawImage(context, adjustedDestRect, image); + // Adjust the color space. + image = imageWithColorSpace(image.get(), styleColorSpace); - if (shouldUseSubimage) - CGImageRelease(image); + // Draw the image. + CGContextDrawImage(context, adjustedDestRect, image.get()); ctxt->restore(); @@ -223,7 +245,7 @@ static void drawPatternCallback(void* info, CGContextRef context) } void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect) { if (!nativeImageForCurrentFrame()) return; @@ -260,6 +282,9 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const ASSERT(h == height()); subImage.adoptCF(CGImageCreateWithImageInRect(tileImage, tileRect)); } + + // Adjust the color space. + subImage = imageWithColorSpace(subImage.get(), styleColorSpace); #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 diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 66246fe..2b2c6b0 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -35,12 +35,27 @@ #include <ApplicationServices/ApplicationServices.h> #include <wtf/UnusedParam.h> +using namespace std; + namespace WebCore { static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); #if !PLATFORM(MAC) -static void sharedBufferDerefCallback(void*, void* info) +size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count) +{ + SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); + size_t sourceSize = sharedBuffer->size(); + if (position >= sourceSize) + return 0; + + const char* source = sharedBuffer->data() + position; + size_t amount = min<size_t>(count, sourceSize - position); + memcpy(buffer, source, amount); + return amount; +} + +void sharedBufferRelease(void* info) { SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); sharedBuffer->deref(); @@ -110,15 +125,17 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) // 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. RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData()); + CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); #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. Ensure that the SharedBuffer lives as long as the CFDataRef. + // Create a CGDataProvider to wrap the SharedBuffer. data->ref(); - CFAllocatorContext context = {0, data, 0, 0, 0, 0, 0, &sharedBufferDerefCallback, 0}; - RetainPtr<CFAllocatorRef> derefAllocator(AdoptCF, CFAllocatorCreate(kCFAllocatorDefault, &context)); - RetainPtr<CFDataRef> cfData(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), derefAllocator.get())); + // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer + // does not provide a way to lock down the byte pointer and guarantee that it won't move, which + // is a requirement for using the GetBytePointer callback. + CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease }; + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(data, data->size(), &providerCallbacks)); + CGImageSourceUpdateDataProvider(m_decoder, dataProvider.get(), allDataReceived); #endif - CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); } String ImageSource::filenameExtension() const diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.h b/WebCore/platform/graphics/cg/ImageSourceCG.h index d5b4b5a..76b4160 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.h +++ b/WebCore/platform/graphics/cg/ImageSourceCG.h @@ -36,6 +36,10 @@ String preferredExtensionForImageSourceType(const String& type); String MIMETypeForImageSourceType(const String& type); +#if !PLATFORM(MAC) +size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count); +#endif + } #endif // ImageSourceCG_h diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 2f5c15e..67333ae 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -33,6 +33,10 @@ #include "ImageObserver.h" #include <wtf/MathExtras.h> +#if !PLATFORM(MAC) +#include "ImageSourceCG.h" +#endif + using namespace std; namespace WebCore { @@ -69,12 +73,15 @@ bool PDFDocumentImage::dataChanged(bool allDataReceived) // 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. RetainPtr<CFDataRef> data(AdoptCF, this->data()->createCFData()); + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); #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. - RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(this->data()->data()), this->data()->size(), kCFAllocatorNull)); + // Create a CGDataProvider to wrap the SharedBuffer. + // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer + // does not provide a way to lock down the byte pointer and guarantee that it won't move, which + // is a requirement for using the GetBytePointer callback. + CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, 0 }; + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateDirect(this->data(), this->data()->size(), &providerCallbacks)); #endif - RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); m_document = CGPDFDocumentCreateWithProvider(dataProvider.get()); setCurrentPage(0); } @@ -139,7 +146,7 @@ int PDFDocumentImage::pageCount() const return m_document ? CGPDFDocumentGetNumberOfPages(m_document) : 0; } -void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op) +void PDFDocumentImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator op) { if (!m_document || m_currentPage == -1) return; diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h index 130c12c..12ab46c 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.h +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -58,7 +58,7 @@ namespace WebCore { virtual IntSize size() const; PDFDocumentImage(); - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); void setCurrentPage(int); int pageCount() const; diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 229188e..9f8f354 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -112,12 +112,16 @@ void TransparencyAwareFontPainter::init() void TransparencyAwareFontPainter::initializeForGDI() { + m_graphicsContext->save(); SkColor color = m_platformContext->effectiveFillColor(); + // Used only when m_createdTransparencyLayer is true. + float layerAlpha = 0.0f; if (SkColorGetA(color) != 0xFF) { // When the font has some transparency, apply it by creating a new - // transparency layer with that opacity applied. + // transparency layer with that opacity applied. We'll actually create + // a new transparency layer after we calculate the bounding box. m_createdTransparencyLayer = true; - m_graphicsContext->beginTransparencyLayer(SkColorGetA(color) / 255.0f); + layerAlpha = SkColorGetA(color) / 255.0f; // The color should be opaque now. color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); } @@ -131,16 +135,22 @@ void TransparencyAwareFontPainter::initializeForGDI() // and we could do ClearType in that case. layerMode = TransparencyWin::TextComposite; layerRect = estimateTextBounds(); + m_graphicsContext->clip(layerRect); + if (m_createdTransparencyLayer) + m_graphicsContext->beginTransparencyLayer(layerAlpha); // The transparency helper requires that we draw text in black in // this mode and it will apply the color. m_transparency.setTextCompositeColor(color); color = SkColorSetRGB(0, 0, 0); - } else if (canvasHasMultipleLayers(m_platformContext->canvas())) { + } else if (m_createdTransparencyLayer || canvasHasMultipleLayers(m_platformContext->canvas())) { // When we're drawing a web page, we know the background is opaque, // but if we're drawing to a layer, we still need extra work. layerMode = TransparencyWin::OpaqueCompositeLayer; layerRect = estimateTextBounds(); + m_graphicsContext->clip(layerRect); + if (m_createdTransparencyLayer) + m_graphicsContext->beginTransparencyLayer(layerAlpha); } else { // Common case of drawing onto the bottom layer of a web page: we // know everything is opaque so don't need to do anything special. @@ -167,6 +177,7 @@ TransparencyAwareFontPainter::~TransparencyAwareFontPainter() m_transparency.composite(); if (m_createdTransparencyLayer) m_graphicsContext->endTransparencyLayer(); + m_graphicsContext->restore(); m_platformContext->canvas()->endPlatformPaint(); } diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp index 88035d5..6bd7d7c 100644 --- a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -42,12 +42,11 @@ #include "FontPlatformData.h" #include "NotImplemented.h" +#include "OpenTypeSanitizer.h" #include "SharedBuffer.h" #if PLATFORM(WIN_OS) #include <objbase.h> -#include <t2embapi.h> -#pragma comment(lib, "t2embed") #elif PLATFORM(LINUX) #include <cstring> #endif @@ -57,13 +56,8 @@ namespace WebCore { FontCustomPlatformData::~FontCustomPlatformData() { #if PLATFORM(WIN_OS) - if (m_fontReference) { - if (m_name.isNull()) { - ULONG status; - TTDeleteEmbeddedFont(m_fontReference, 0, &status); - } else - RemoveFontMemResourceEx(m_fontReference); - } + if (m_fontReference) + RemoveFontMemResourceEx(m_fontReference); #elif PLATFORM(LINUX) if (m_fontReference) m_fontReference->unref(); @@ -76,19 +70,15 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b ASSERT(m_fontReference); LOGFONT logFont; - if (m_name.isNull()) - TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0); - else { - // m_name comes from createUniqueFontName, which, in turn, gets - // it from base64-encoded uuid (128-bit). So, m_name - // can never be longer than LF_FACESIZE (32). - if (m_name.length() + 1 >= LF_FACESIZE) { - ASSERT_NOT_REACHED(); - return FontPlatformData(); - } - memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), - sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); + // m_name comes from createUniqueFontName, which, in turn, gets + // it from base64-encoded uuid (128-bit). So, m_name + // can never be longer than LF_FACESIZE (32). + if (m_name.length() + 1 >= LF_FACESIZE) { + ASSERT_NOT_REACHED(); + return FontPlatformData(); } + memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), + sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); // FIXME: almost identical to FillLogFont in FontCacheWin.cpp. // Need to refactor. @@ -119,69 +109,6 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b } #if PLATFORM(WIN_OS) -// FIXME: EOTStream class and static functions in this #if block are -// duplicated from platform/graphics/win/FontCustomPlatformData.cpp -// and need to be shared. - -// Streams the concatenation of a header and font data. -class EOTStream { -public: - EOTStream(const EOTHeader& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) - : m_eotHeader(eotHeader) - , m_fontData(fontData) - , m_overlayDst(overlayDst) - , m_overlaySrc(overlaySrc) - , m_overlayLength(overlayLength) - , m_offset(0) - , m_inHeader(true) - { - } - - size_t read(void* buffer, size_t count); - -private: - const EOTHeader& m_eotHeader; - const SharedBuffer* m_fontData; - size_t m_overlayDst; - size_t m_overlaySrc; - size_t m_overlayLength; - size_t m_offset; - bool m_inHeader; -}; - -size_t EOTStream::read(void* buffer, size_t count) -{ - size_t bytesToRead = count; - if (m_inHeader) { - size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count); - memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); - m_offset += bytesFromHeader; - bytesToRead -= bytesFromHeader; - if (m_offset == m_eotHeader.size()) { - m_inHeader = false; - m_offset = 0; - } - } - if (bytesToRead && !m_inHeader) { - size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead); - memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); - if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) { - size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0); - size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst); - size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset); - memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy); - } - m_offset += bytesFromData; - bytesToRead -= bytesFromData; - } - return count - bytesToRead; -} - -static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length) -{ - return static_cast<EOTStream*>(stream)->read(buffer, length); -} - // Creates a unique and unpredictable font name, in order to avoid collisions and to // not allow access from CSS. static String createUniqueFontName() @@ -245,38 +172,22 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); +#if ENABLE(OPENTYPE_SANITIZER) + OpenTypeSanitizer sanitizer(buffer); + RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize(); + if (!transcodeBuffer) + return 0; // validation failed. + buffer = transcodeBuffer.get(); +#endif + #if PLATFORM(WIN_OS) - // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's + // Introduce the font to GDI. AddFontMemResourceEx should be used with care, because it will pollute the process's // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the - // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name - // we avoid namespace collisions. - + // entire process first). String fontName = createUniqueFontName(); - - // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, - // so we need to create an EOT header and prepend it to the font data. - EOTHeader eotHeader; - size_t overlayDst; - size_t overlaySrc; - size_t overlayLength; - - if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) + HANDLE fontReference = renameAndActivateFont(buffer, fontName); + if (!fontReference) return 0; - - HANDLE fontReference; - ULONG privStatus; - ULONG status; - EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength); - - LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0); - if (loadEmbeddedFontResult == E_NONE) - fontName = String(); - else { - fontReference = renameAndActivateFont(buffer, fontName); - if (!fontReference) - return 0; - } - return new FontCustomPlatformData(fontReference, fontName); #elif PLATFORM(LINUX) RemoteFontStream stream(buffer); diff --git a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp index a5a6e1f..1386163 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp @@ -46,12 +46,6 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String&) -{ - notImplemented(); - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { notImplemented(); diff --git a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp index 93e36ba..23ca698 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp @@ -39,11 +39,6 @@ namespace WebCore { -PassRefPtr<Icon> Icon::createIconForFile(const String&) -{ - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { return 0; diff --git a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp index b419e6f..b0145f8 100644 --- a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp @@ -52,26 +52,11 @@ Icon::~Icon() DestroyIcon(m_icon); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - SHFILEINFO sfi; - memset(&sfi, 0, sizeof(sfi)); - - String tmpFilename = filename; - if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) - return 0; - - return adoptRef(new Icon(sfi.hIcon)); -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - // FIXME: support multiple files. + // FIXME: We can't access icons directly from renderer processes. // http://code.google.com/p/chromium/issues/detail?id=4092 - if (!filenames.size()) - return 0; - - return createIconForFile(filenames[0]); + return 0; } void Icon::paint(GraphicsContext* context, const IntRect& rect) diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 7957d5a..6dcd595 100644 --- a/WebCore/platform/graphics/chromium/TransparencyWin.cpp +++ b/WebCore/platform/graphics/chromium/TransparencyWin.cpp @@ -275,7 +275,7 @@ void TransparencyWin::setupLayerForWhiteLayer() if (!m_validLayer) return; - m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white); + m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white, DeviceColorSpace); // Layer rect represents the part of the original layer. } diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 2364cc4..f362148 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -111,10 +111,10 @@ void FEBlend::apply(Filter* filter) if (!getEffectContext()) return; - IntRect effectADrawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->scaledSubRegion()); RefPtr<CanvasPixelArray> srcPixelArrayB(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)->data()); IntRect imageRect(IntPoint(), resultImage()->size()); diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index a2ed9bd..f422157 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -164,7 +164,7 @@ void FEColorMatrix::apply(Filter* filter) if (!filterContext) return; - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); IntRect imageRect(IntPoint(), resultImage()->size()); PassRefPtr<ImageData> imageData(resultImage()->getUnmultipliedImageData(imageRect)); diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 0d76d8d..1d9cfff 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -165,7 +165,7 @@ void FEComponentTransfer::apply(Filter* filter) for (unsigned channel = 0; channel < 4; channel++) (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); - IntRect drawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect drawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<ImageData> imageData(m_in->resultImage()->getUnmultipliedImageData(drawingRect)); CanvasPixelArray* srcPixelArray(imageData->data()); diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 1b41165..c540cb7 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -133,32 +133,32 @@ void FEComposite::apply(Filter* filter) FloatRect srcRect = FloatRect(0.f, 0.f, -1.f, -1.f); switch (m_type) { case FECOMPOSITE_OPERATOR_OVER: - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); break; case FECOMPOSITE_OPERATOR_IN: filterContext->save(); - filterContext->clipToImageBuffer(calculateDrawingRect(m_in2->subRegion()), m_in2->resultImage()); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->clipToImageBuffer(calculateDrawingRect(m_in2->scaledSubRegion()), m_in2->resultImage()); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); filterContext->restore(); break; case FECOMPOSITE_OPERATOR_OUT: - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion()), srcRect, CompositeDestinationOut); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion())); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion()), srcRect, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeSourceAtop); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion()), srcRect, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: - filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); - filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeXOR); + filterContext->drawImage(m_in2->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in2->scaledSubRegion())); + filterContext->drawImage(m_in->resultImage()->image(), DeviceColorSpace, calculateDrawingRect(m_in->scaledSubRegion()), srcRect, CompositeXOR); break; case FECOMPOSITE_OPERATOR_ARITHMETIC: { - IntRect effectADrawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->scaledSubRegion()); RefPtr<ImageData> imageData(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)); CanvasPixelArray* srcPixelArrayB(imageData->data()); diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index f480f10..0b97e39 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -32,6 +32,8 @@ #include <math.h> #include <wtf/MathExtras.h> +using std::max; + namespace WebCore { FEGaussianBlur::FEGaussianBlur(FilterEffect* in, const float& x, const float& y) @@ -111,10 +113,12 @@ void FEGaussianBlur::apply(Filter* filter) if (m_x == 0 || m_y == 0) return; - unsigned sdx = static_cast<unsigned>(floor(m_x * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); - unsigned sdy = static_cast<unsigned>(floor(m_y * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + unsigned sdx = static_cast<unsigned>(floor(m_x * filter->filterResolution().width() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + unsigned sdy = static_cast<unsigned>(floor(m_y * filter->filterResolution().height() * 3 * sqrt(2 * piDouble) / 4.f + 0.5f)); + sdx = max(sdx, static_cast<unsigned>(1)); + sdy = max(sdy, static_cast<unsigned>(1)); - IntRect effectDrawingRect = calculateDrawingIntRect(m_in->subRegion()); + IntRect effectDrawingRect = calculateDrawingIntRect(m_in->scaledSubRegion()); RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect)); CanvasPixelArray* srcPixelArray(srcImageData->data()); diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h index ee97afc..8924b94 100644 --- a/WebCore/platform/graphics/filters/Filter.h +++ b/WebCore/platform/graphics/filters/Filter.h @@ -22,6 +22,7 @@ #if ENABLE(FILTERS) #include "FloatRect.h" +#include "FloatSize.h" #include "ImageBuffer.h" #include "StringHash.h" @@ -40,15 +41,21 @@ namespace WebCore { void setSourceImage(PassOwnPtr<ImageBuffer> sourceImage) { m_sourceImage = sourceImage; } ImageBuffer* sourceImage() { return m_sourceImage.get(); } - virtual FloatRect sourceImageRect() = 0; - virtual FloatRect filterRegion() = 0; + FloatSize filterResolution() const { return m_filterResolution; } + void setFilterResolution(const FloatSize& filterResolution) { m_filterResolution = filterResolution; } + + virtual FloatRect sourceImageRect() const = 0; + virtual FloatRect filterRegion() const = 0; // SVG specific - virtual void calculateEffectSubRegion(FilterEffect*) = 0; - virtual bool effectBoundingBoxMode() = 0; + virtual void calculateEffectSubRegion(FilterEffect*) { } + + virtual FloatSize maxImageSize() const = 0; + virtual bool effectBoundingBoxMode() const = 0; private: OwnPtr<ImageBuffer> m_sourceImage; + FloatSize m_filterResolution; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 68900b5..5583813 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -58,21 +58,21 @@ FloatRect FilterEffect::calculateEffectRect(Filter* filter) IntRect FilterEffect::calculateDrawingIntRect(const FloatRect& effectRect) { - IntPoint location = roundedIntPoint(FloatPoint(subRegion().x() - effectRect.x(), - subRegion().y() - effectRect.y())); + IntPoint location = roundedIntPoint(FloatPoint(scaledSubRegion().x() - effectRect.x(), + scaledSubRegion().y() - effectRect.y())); return IntRect(location, resultImage()->size()); } FloatRect FilterEffect::calculateDrawingRect(const FloatRect& srcRect) { - FloatPoint startPoint = FloatPoint(srcRect.x() - subRegion().x(), srcRect.y() - subRegion().y()); + FloatPoint startPoint = FloatPoint(srcRect.x() - scaledSubRegion().x(), srcRect.y() - scaledSubRegion().y()); FloatRect drawingRect = FloatRect(startPoint, srcRect.size()); return drawingRect; } GraphicsContext* FilterEffect::getEffectContext() { - IntRect bufferRect = enclosingIntRect(subRegion()); + IntRect bufferRect = enclosingIntRect(scaledSubRegion()); m_effectBuffer = ImageBuffer::create(bufferRect.size(), LinearRGB); return m_effectBuffer->context(); } diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index b30e513..a46d795 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -44,6 +44,12 @@ namespace WebCore { FloatRect subRegion() const { return m_subRegion; } void setSubRegion(const FloatRect& subRegion) { m_subRegion = subRegion; } + FloatRect scaledSubRegion() const { return m_scaledSubRegion; } + void setScaledSubRegion(const FloatRect& scaledSubRegion) { m_scaledSubRegion = scaledSubRegion; } + + FloatRect effectBoundaries() const { return m_effectBoundaries; } + void setEffectBoundaries(const FloatRect& effectBoundaries) { m_effectBoundaries = effectBoundaries; } + bool hasX() { return m_hasX; } void setHasX(bool value) { m_hasX = value; } @@ -96,7 +102,9 @@ namespace WebCore { bool m_alphaImage; + FloatRect m_effectBoundaries; FloatRect m_subRegion; + FloatRect m_scaledSubRegion; FloatRect m_unionOfChildEffectSubregions; mutable OwnPtr<ImageBuffer> m_effectBuffer; diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp new file mode 100644 index 0000000..33953d6 --- /dev/null +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@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(FILTERS) +#include "ImageBufferFilter.h" + +#include "FloatSize.h" + +namespace WebCore { + +ImageBufferFilter::ImageBufferFilter() + : Filter() +{ + setFilterResolution(FloatSize(1.f, 1.f)); +} + +PassRefPtr<ImageBufferFilter> ImageBufferFilter::create() +{ + return adoptRef(new ImageBufferFilter()); +} + +} // namespace WebCore + +#endif // ENABLE(FILTERS) diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.h b/WebCore/platform/graphics/filters/ImageBufferFilter.h new file mode 100644 index 0000000..a2775ea --- /dev/null +++ b/WebCore/platform/graphics/filters/ImageBufferFilter.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) 2009 Brent Fulgham <bfulgham@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 ImageBufferFilter_h +#define ImageBufferFilter_h + +#if ENABLE(FILTERS) +#include "Filter.h" +#include "FilterEffect.h" +#include "FloatRect.h" +#include "FloatSize.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class ImageBufferFilter : public Filter { +public: + static PassRefPtr<ImageBufferFilter> create(); + + virtual FloatRect filterRegion() const { return FloatRect(); } + virtual FloatRect sourceImageRect() const { return FloatRect(); } + + // SVG specific + virtual bool effectBoundingBoxMode() const { return false; } + + virtual FloatSize maxImageSize() const { return FloatSize(); } + virtual void calculateEffectSubRegion(FilterEffect*) { } + +private: + ImageBufferFilter(); +}; + +} // namespace WebCore + +#endif // ENABLE(FILTERS) + +#endif // ImageBufferFilter_h diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 1b6309b..539bb44 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -50,6 +50,8 @@ FloatRect SourceAlpha::calculateEffectRect(Filter* filter) if (filter->sourceImageRect().y() < filter->filterRegion().y()) clippedSourceRect.setY(filter->filterRegion().y()); setSubRegion(clippedSourceRect); + clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setScaledSubRegion(clippedSourceRect); return filter->filterRegion(); } @@ -64,7 +66,7 @@ void SourceAlpha::apply(Filter* filter) FloatRect imageRect(FloatPoint(), filter->sourceImage()->image()->size()); filterContext->save(); filterContext->clipToImageBuffer(imageRect, filter->sourceImage()); - filterContext->fillRect(imageRect, Color::black); + filterContext->fillRect(imageRect, Color::black, DeviceColorSpace); filterContext->restore(); } diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp index 023eeac..cc55618 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.cpp +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -49,6 +49,8 @@ FloatRect SourceGraphic::calculateEffectRect(Filter* filter) if (filter->sourceImageRect().y() < filter->filterRegion().y()) clippedSourceRect.setY(filter->filterRegion().y()); setSubRegion(clippedSourceRect); + clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setScaledSubRegion(clippedSourceRect); return filter->filterRegion(); } @@ -58,7 +60,7 @@ void SourceGraphic::apply(Filter* filter) if (!filterContext) return; - filterContext->drawImage(filter->sourceImage()->image(), IntPoint()); + filterContext->drawImage(filter->sourceImage()->image(), DeviceColorSpace, IntPoint()); } void SourceGraphic::dump() diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index ee86f96..5c320e0 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -259,7 +259,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F // Re-enable the platform shadow we disabled earlier if (hasShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); // Pango sometimes leaves behind paths we don't want cairo_new_path(cr); diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp index e08c1ab..3563a59 100644 --- a/WebCore/platform/graphics/gtk/IconGtk.cpp +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -87,23 +87,25 @@ static String lookupIconName(String MIMEType) return GTK_STOCK_FILE; } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - if (!g_path_skip_root(filename.utf8().data())) + if (filenames.isEmpty()) return 0; - String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename); - String iconName = lookupIconName(MIMEType); + if (filenames.size() == 1) { + if (!g_path_skip_root(filenames[0].utf8().data())) + return 0; - RefPtr<Icon> icon = adoptRef(new Icon); - icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); - if (!icon->m_icon) - return 0; - return icon.release(); -} + String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filenames[0]); + String iconName = lookupIconName(MIMEType); + + RefPtr<Icon> icon = adoptRef(new Icon); + icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, 0); + if (!icon->m_icon) + return 0; + return icon.release(); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) -{ //FIXME: Implement this return 0; } diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp index 8d1d261..a023dae 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -46,7 +46,7 @@ #include <gst/video/video.h> #include <limits> #include <math.h> -#include <wtf/GOwnPtr.h> +#include <wtf/gtk/GOwnPtr.h> using namespace std; @@ -66,11 +66,15 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); error = MediaPlayer::Empty; - if (err->domain == GST_CORE_ERROR || err->domain == GST_LIBRARY_ERROR) - error = MediaPlayer::DecodeError; - else if (err->domain == GST_RESOURCE_ERROR) + if (err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND + || err->code == GST_STREAM_ERROR_WRONG_TYPE + || err->code == GST_STREAM_ERROR_FAILED + || err->code == GST_CORE_ERROR_MISSING_PLUGIN + || err->code == GST_RESOURCE_ERROR_NOT_FOUND) error = MediaPlayer::FormatError; else if (err->domain == GST_STREAM_ERROR) + error = MediaPlayer::DecodeError; + else if (err->domain == GST_RESOURCE_ERROR) error = MediaPlayer::NetworkError; if (mp) @@ -95,6 +99,33 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo return true; } +static float playbackPosition(GstElement* playbin) +{ + + float ret = 0.0; + + GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); + if (!gst_element_query(playbin, query)) { + LOG_VERBOSE(Media, "Position query failed..."); + gst_query_unref(query); + return ret; + } + + gint64 position; + gst_query_parse_position(query, 0, &position); + + // Position is available only if the pipeline is not in NULL or + // READY state. + if (position != static_cast<gint64>(GST_CLOCK_TIME_NONE)) + ret = static_cast<float>(position) / static_cast<float>(GST_SECOND); + + LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + + gst_query_unref(query); + + return ret; +} + void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate) { g_return_if_fail(GST_IS_BUFFER(buffer)); @@ -115,16 +146,34 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) static bool gstInitialized = false; -static void do_gst_init() +static bool do_gst_init() { // FIXME: We should pass the arguments from the command line if (!gstInitialized) { - gst_init(0, 0); - gstInitialized = true; - gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, - WEBKIT_TYPE_DATA_SRC); + GOwnPtr<GError> error; + gstInitialized = gst_init_check(0, 0, &error.outPtr()); + if (!gstInitialized) + LOG_VERBOSE(Media, "Could not initialize GStreamer: %s", + error ? error->message : "unknown error occurred"); + else + gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, + WEBKIT_TYPE_DATA_SRC); } + return gstInitialized; +} + +bool MediaPlayerPrivate::isAvailable() +{ + if (!do_gst_init()) + return false; + + GstElementFactory* factory = gst_element_factory_find("playbin2"); + if (factory) { + gst_object_unref(GST_OBJECT(factory)); + return true; + } + return false; } MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) @@ -132,6 +181,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_playBin(0) , m_videoSink(0) , m_source(0) + , m_seekTime(0) + , m_changingRate(false) , m_endTime(numeric_limits<float>::infinity()) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) @@ -181,14 +232,26 @@ void MediaPlayerPrivate::load(const String& url) void MediaPlayerPrivate::play() { - LOG_VERBOSE(Media, "Play"); - gst_element_set_state(m_playBin, GST_STATE_PLAYING); + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if (state != GST_STATE_PLAYING && pending != GST_STATE_PLAYING) { + LOG_VERBOSE(Media, "Play"); + gst_element_set_state(m_playBin, GST_STATE_PLAYING); + } } void MediaPlayerPrivate::pause() { - LOG_VERBOSE(Media, "Pause"); - gst_element_set_state(m_playBin, GST_STATE_PAUSED); + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if (state != GST_STATE_PAUSED && pending != GST_STATE_PAUSED) { + LOG_VERBOSE(Media, "Pause"); + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + } } float MediaPlayerPrivate::duration() const @@ -202,7 +265,7 @@ float MediaPlayerPrivate::duration() const GstFormat timeFormat = GST_FORMAT_TIME; gint64 timeLength = 0; - if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || timeLength == GST_CLOCK_TIME_NONE) { + if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || static_cast<guint64>(timeLength) == GST_CLOCK_TIME_NONE) { LOG_VERBOSE(Media, "Time duration query failed."); return numeric_limits<float>::infinity(); } @@ -221,23 +284,11 @@ float MediaPlayerPrivate::currentTime() const if (m_errorOccured) return 0; - float ret = 0.0; + if (m_seeking) + return m_seekTime; - GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); - if (!gst_element_query(m_playBin, query)) { - LOG_VERBOSE(Media, "Position query failed..."); - gst_query_unref(query); - return ret; - } + return playbackPosition(m_playBin); - gint64 position; - gst_query_parse_position(query, 0, &position); - ret = (float) (position / 1000000000.0); - LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); - - gst_query_unref(query); - - return ret; } void MediaPlayerPrivate::seek(float time) @@ -260,8 +311,10 @@ void MediaPlayerPrivate::seek(float time) GST_SEEK_TYPE_SET, sec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) LOG_VERBOSE(Media, "Seek to %f failed", time); - else + else { m_seeking = true; + m_seekTime = sec; + } } void MediaPlayerPrivate::setEndTime(float time) @@ -310,10 +363,10 @@ IntSize MediaPlayerPrivate::naturalSize() const gfloat pixelAspectRatio; gint pixelAspectRatioNumerator, pixelAspectRatioDenominator; - if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) || - !gst_video_format_parse_caps(caps, NULL, &width, &height) || - !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, - &pixelAspectRatioDenominator)) { + if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) + || !gst_video_format_parse_caps(caps, 0, &width, &height) + || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, + &pixelAspectRatioDenominator)) { gst_object_unref(GST_OBJECT(pad)); return IntSize(); } @@ -353,16 +406,50 @@ void MediaPlayerPrivate::setVolume(float volume) void MediaPlayerPrivate::setRate(float rate) { - if (rate == 0.0) { - gst_element_set_state(m_playBin, GST_STATE_PAUSED); + GstState state; + GstState pending; + + gst_element_get_state(m_playBin, &state, &pending, 0); + if ((state != GST_STATE_PLAYING && state != GST_STATE_PAUSED) + || (pending == GST_STATE_PAUSED)) return; - } if (m_isStreaming) return; + m_changingRate = true; + float currentPosition = playbackPosition(m_playBin) * GST_SECOND; + GstSeekFlags flags = (GstSeekFlags)(GST_SEEK_FLAG_FLUSH); + gint64 start, end; + bool mute = false; + LOG_VERBOSE(Media, "Set Rate to %f", rate); - seek(currentTime()); + if (rate >= 0) { + // Mute the sound if the playback rate is too extreme. + // TODO: in other cases we should perform pitch adjustments. + mute = (bool) (rate < 0.8 || rate > 2); + start = currentPosition; + end = GST_CLOCK_TIME_NONE; + } else { + start = 0; + mute = true; + + // If we are at beginning of media, start from the end to + // avoid immediate EOS. + if (currentPosition <= 0) + end = duration() * GST_SECOND; + else + end = currentPosition; + } + + LOG_VERBOSE(Media, "Need to mute audio: %d", (int) mute); + + if (!gst_element_seek(m_playBin, rate, GST_FORMAT_TIME, flags, + GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_SET, end)) + LOG_VERBOSE(Media, "Set rate to %f failed", rate); + else + g_object_set(m_playBin, "mute", mute, NULL); } int MediaPlayerPrivate::dataRate() const @@ -497,6 +584,11 @@ void MediaPlayerPrivate::updateStates() } else m_paused = true; + if (m_changingRate) { + m_player->rateChanged(); + m_changingRate = false; + } + if (m_seeking) { shouldUpdateAfterSeek = true; m_seeking = false; @@ -560,11 +652,6 @@ void MediaPlayerPrivate::loadStateChanged() updateStates(); } -void MediaPlayerPrivate::rateChanged() -{ - updateStates(); -} - void MediaPlayerPrivate::sizeChanged() { notImplemented(); @@ -624,54 +711,36 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) return; int width = 0, height = 0; - int pixelAspectRatioNumerator = 0; - int pixelAspectRatioDenominator = 0; - double doublePixelAspectRatioNumerator = 0; - double doublePixelAspectRatioDenominator = 0; - double displayWidth; - double displayHeight; - double scale, gapHeight, gapWidth; - GstCaps *caps = gst_buffer_get_caps(m_buffer); + GstVideoFormat format; - if (!gst_video_format_parse_caps(caps, NULL, &width, &height) || - !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) { + if (!gst_video_format_parse_caps(caps, &format, &width, &height)) { gst_caps_unref(caps); return; } - displayWidth = width; - displayHeight = height; - doublePixelAspectRatioNumerator = pixelAspectRatioNumerator; - doublePixelAspectRatioDenominator = pixelAspectRatioDenominator; + cairo_format_t cairoFormat; + if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) + cairoFormat = CAIRO_FORMAT_ARGB32; + else + cairoFormat = CAIRO_FORMAT_RGB24; cairo_t* cr = context->platformContext(); cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer), - CAIRO_FORMAT_RGB24, + cairoFormat, width, height, 4 * width); cairo_save(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - - displayWidth *= doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator; - displayHeight *= doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator; - scale = MIN (rect.width () / displayWidth, rect.height () / displayHeight); - displayWidth *= scale; - displayHeight *= scale; + // translate and scale the context to correct size + cairo_translate(cr, rect.x(), rect.y()); + cairo_scale(cr, static_cast<double>(rect.width()) / width, static_cast<double>(rect.height()) / height); - // Calculate gap between border an picture - gapWidth = (rect.width() - displayWidth) / 2.0; - gapHeight = (rect.height() - displayHeight) / 2.0; - - // paint the rectangle on the context and draw the surface inside. - cairo_translate(cr, rect.x() + gapWidth, rect.y() + gapHeight); - cairo_rectangle(cr, 0, 0, rect.width(), rect.height()); - cairo_scale(cr, doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator, - doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator); - cairo_scale(cr, scale, scale); + // And paint it. cairo_set_source_surface(cr, src, 0, 0); + cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); + cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); cairo_restore(cr); @@ -688,76 +757,91 @@ static HashSet<String> mimeTypeCache() static bool typeListInitialized = false; if (!typeListInitialized) { - // These subtypes are already beeing supported by WebKit itself - HashSet<String> ignoredApplicationSubtypes; - ignoredApplicationSubtypes.add(String("javascript")); - ignoredApplicationSubtypes.add(String("ecmascript")); - ignoredApplicationSubtypes.add(String("x-javascript")); - ignoredApplicationSubtypes.add(String("xml")); - ignoredApplicationSubtypes.add(String("xhtml+xml")); - ignoredApplicationSubtypes.add(String("rss+xml")); - ignoredApplicationSubtypes.add(String("atom+xml")); - ignoredApplicationSubtypes.add(String("x-ftp-directory")); - ignoredApplicationSubtypes.add(String("x-java-applet")); - ignoredApplicationSubtypes.add(String("x-java-bean")); - ignoredApplicationSubtypes.add(String("x-java-vm")); - ignoredApplicationSubtypes.add(String("x-shockwave-flash")); + // Build a whitelist of mime-types known to be supported by + // GStreamer. + HashSet<String> handledApplicationSubtypes; + handledApplicationSubtypes.add(String("ogg")); + handledApplicationSubtypes.add(String("x-3gp")); + handledApplicationSubtypes.add(String("vnd.rn-realmedia")); + handledApplicationSubtypes.add(String("x-pn-realaudio")); GList* factories = gst_type_find_factory_get_list(); for (GList* iterator = factories; iterator; iterator = iterator->next) { GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data); GstCaps* caps = gst_type_find_factory_get_caps(factory); - // Splitting the capability by comma and taking the first part - // as capability can be something like "audio/x-wavpack, framed=(boolean)false" - GOwnPtr<gchar> capabilityString(gst_caps_to_string(caps)); - gchar** capability = g_strsplit(capabilityString.get(), ",", 2); - gchar** mimetype = g_strsplit(capability[0], "/", 2); - - // GStreamer plugins can be capable of supporting types which WebKit supports - // by default. In that case, we should not consider these types supportable by GStreamer. - // Examples of what GStreamer can support but should not be added: - // text/plain, text/html, image/jpeg, application/xml - if (g_str_equal(mimetype[0], "audio") || - g_str_equal(mimetype[0], "video") || - (g_str_equal(mimetype[0], "application") && - !ignoredApplicationSubtypes.contains(String(mimetype[1])))) { - cache.add(String(capability[0])); - - // These formats are supported by GStreamer, but not correctly advertised - if (g_str_equal(capability[0], "video/x-h264") || - g_str_equal(capability[0], "audio/x-m4a")) { + if (!caps) + continue; + + for (guint structureIndex = 0; structureIndex < gst_caps_get_size(caps); structureIndex++) { + GstStructure* structure = gst_caps_get_structure(caps, structureIndex); + const gchar* name = gst_structure_get_name(structure); + bool cached = false; + + // These formats are supported by GStreamer, but not + // correctly advertised. + if (g_str_equal(name, "video/x-h264") + || g_str_equal(name, "audio/x-m4a")) { cache.add(String("video/mp4")); cache.add(String("audio/aac")); + cached = true; } - if (g_str_equal(capability[0], "video/x-theora")) + if (g_str_equal(name, "video/x-theora")) { cache.add(String("video/ogg")); + cached = true; + } - if (g_str_equal(capability[0], "audio/x-wav")) - cache.add(String("audio/wav")); + if (g_str_equal(name, "audio/x-vorbis")) { + cache.add(String("audio/ogg")); + cached = true; + } - if (g_str_equal(capability[0], "audio/mpeg")) { - // This is what we are handling: mpegversion=(int)1, layer=(int)[ 1, 3 ] - gchar** versionAndLayer = g_strsplit(capability[1], ",", 2); + if (g_str_equal(name, "audio/x-wav")) { + cache.add(String("audio/wav")); + cached = true; + } - if (g_str_has_suffix (versionAndLayer[0], "(int)1")) { - for (int i = 0; versionAndLayer[1][i] != '\0'; i++) { - if (versionAndLayer[1][i] == '1') + if (g_str_equal(name, "audio/mpeg")) { + cache.add(String(name)); + cached = true; + + // This is what we are handling: + // mpegversion=(int)1, layer=(int)[ 1, 3 ] + gint mpegVersion = 0; + if (gst_structure_get_int(structure, "mpegversion", &mpegVersion) && (mpegVersion == 1)) { + const GValue* layer = gst_structure_get_value(structure, "layer"); + if (G_VALUE_TYPE(layer) == GST_TYPE_INT_RANGE) { + gint minLayer = gst_value_get_int_range_min(layer); + gint maxLayer = gst_value_get_int_range_max(layer); + if (minLayer <= 1 <= maxLayer) cache.add(String("audio/mp1")); - else if (versionAndLayer[1][i] == '2') + if (minLayer <= 2 <= maxLayer) cache.add(String("audio/mp2")); - else if (versionAndLayer[1][i] == '3') + if (minLayer <= 3 <= maxLayer) cache.add(String("audio/mp3")); } } + } - g_strfreev(versionAndLayer); + if (!cached) { + // GStreamer plugins can be capable of supporting + // types which WebKit supports by default. In that + // case, we should not consider these types + // supportable by GStreamer. Examples of what + // GStreamer can support but should not be added: + // text/plain, text/html, image/jpeg, + // application/xml + gchar** mimetype = g_strsplit(name, "/", 2); + if (g_str_equal(mimetype[0], "audio") + || g_str_equal(mimetype[0], "video") + || (g_str_equal(mimetype[0], "application") + && handledApplicationSubtypes.contains(String(mimetype[1])))) + cache.add(String(name)); + + g_strfreev(mimetype); } } - - g_strfreev(capability); - g_strfreev(mimetype); } gst_plugin_feature_list_free(factories); diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h index 54da420..6ab8edb 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -29,6 +29,7 @@ #include <cairo.h> #include <glib.h> +#include <gst/gst.h> typedef struct _WebKitVideoSink WebKitVideoSink; typedef struct _GstBuffer GstBuffer; @@ -89,7 +90,6 @@ namespace WebCore { void setSize(const IntSize&); void loadStateChanged(); - void rateChanged(); void sizeChanged(); void timeChanged(); void volumeChanged(); @@ -109,7 +109,7 @@ namespace WebCore { static void getSupportedTypes(HashSet<String>&); static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); - static bool isAvailable() { return true; } + static bool isAvailable(); void updateStates(); void cancelSeek(); @@ -124,6 +124,8 @@ namespace WebCore { GstElement* m_playBin; GstElement* m_videoSink; GstElement* m_source; + GstClockTime m_seekTime; + bool m_changingRate; float m_endTime; bool m_isEndReached; MediaPlayer::NetworkState m_networkState; diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp index 9a616f4..df25393 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -39,8 +39,6 @@ #include "FontDescription.h" #include "GlyphBuffer.h" #include <cairo.h> -#include <unicode/uchar.h> -#include <unicode/unorm.h> #include <wtf/MathExtras.h> namespace WebCore { diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp index b5e1a8b..5e0f8e2 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -37,21 +37,15 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, // CAIRO_FORMAT_RGB24 used to render the video buffers is little/big endian dependant. #if G_BYTE_ORDER == G_LITTLE_ENDIAN - GST_STATIC_CAPS(GST_VIDEO_CAPS_BGRx) + GST_STATIC_CAPS(GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_BGRA) #else - GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB) + GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_ARGB) #endif ); GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug); #define GST_CAT_DEFAULT webkit_video_sink_debug -static GstElementDetails webkit_video_sink_details = - GST_ELEMENT_DETAILS((gchar*) "WebKit video sink", - (gchar*) "Sink/Video", - (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface", - (gchar*) "Alp Toker <alp@atoker.com>"); - enum { REPAINT_REQUESTED, LAST_SIGNAL @@ -98,7 +92,9 @@ 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); + gst_element_class_set_details_simple(element_class, "WebKit video sink", + "Sink/Video", "Sends video data from a GStreamer pipeline to a Cairo surface", + "Alp Toker <alp@atoker.com>"); } static void @@ -129,11 +125,6 @@ webkit_video_sink_timeout_func(gpointer data) return FALSE; } - if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) { - buffer = gst_buffer_make_metadata_writable(buffer); - gst_buffer_set_caps(buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(sink))); - } - g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0, buffer); gst_buffer_unref(buffer); g_cond_signal(priv->data_cond); @@ -157,6 +148,71 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) priv->buffer = gst_buffer_ref(buffer); + // For the unlikely case where the buffer has no caps, the caps + // are implicitely the caps of the pad. This shouldn't happen. + if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) { + buffer = priv->buffer = gst_buffer_make_metadata_writable(priv->buffer); + gst_buffer_set_caps(priv->buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(bsink))); + } + + GstCaps *caps = GST_BUFFER_CAPS(buffer); + GstVideoFormat format; + int width, height; + if (G_UNLIKELY(!gst_video_format_parse_caps(caps, &format, &width, &height))) { + gst_buffer_unref(buffer); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_ERROR; + } + + // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't. + // Here we convert to Cairo's ARGB. + if (format == GST_VIDEO_FORMAT_ARGB || format == GST_VIDEO_FORMAT_BGRA) { + // Because GstBaseSink::render() only owns the buffer reference in the + // method scope we can't use gst_buffer_make_writable() here. Also + // The buffer content should not be changed here because the same buffer + // could be passed multiple times to this method (in theory) + GstBuffer *newBuffer = gst_buffer_try_new_and_alloc(GST_BUFFER_SIZE(buffer)); + + // Check if allocation failed + if (G_UNLIKELY(!newBuffer)) { + gst_buffer_unref(buffer); + g_mutex_unlock(priv->buffer_mutex); + return GST_FLOW_ERROR; + } + + gst_buffer_copy_metadata(newBuffer, buffer, (GstBufferCopyFlags) GST_BUFFER_COPY_ALL); + + // We don't use Color::premultipliedARGBFromColor() here because + // one function call per video pixel is just too expensive: + // For 720p/PAL for example this means 1280*720*25=23040000 + // function calls per second! + unsigned short alpha; + const guint8 *source = GST_BUFFER_DATA(buffer); + guint8 *destination = GST_BUFFER_DATA(newBuffer); + + for (int x = 0; x < height; x++) { + for (int y = 0; y < width; y++) { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + alpha = source[3]; + destination[0] = (source[0] * alpha + 128) / 255; + destination[1] = (source[1] * alpha + 128) / 255; + destination[2] = (source[2] * alpha + 128) / 255; + destination[3] = alpha; +#else + alpha = source[0]; + destination[0] = alpha; + destination[1] = (source[1] * alpha + 128) / 255; + destination[2] = (source[2] * alpha + 128) / 255; + destination[3] = (source[3] * alpha + 128) / 255; +#endif + source += 4; + destination += 4; + } + } + gst_buffer_unref(buffer); + buffer = priv->buffer = newBuffer; + } + // Use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations. priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0, webkit_video_sink_timeout_func, diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp index c23b8a9..4728d56 100644 --- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -152,7 +152,7 @@ void GraphicsContext::drawConvexPolygon(size_t pointsLength, const FloatPoint* p m_data->m_view->StrokePolygon(bPoints, pointsLength, true, getHaikuStrokeStyle()); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -169,7 +169,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !color.alpha()) return; @@ -477,7 +477,7 @@ void GraphicsContext::setPlatformFont(const Font& font) m_data->m_view->SetFont(font.primaryFont()->platformData().font()); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -519,7 +519,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) m_data->m_view->SetPenSize(thickness); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -532,7 +532,7 @@ void GraphicsContext::clearPlatformShadow() notImplemented(); } -void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&) +void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&, ColorSpace) { notImplemented(); } diff --git a/WebCore/platform/graphics/haiku/IconHaiku.cpp b/WebCore/platform/graphics/haiku/IconHaiku.cpp index dccac4a..3663ee2 100644 --- a/WebCore/platform/graphics/haiku/IconHaiku.cpp +++ b/WebCore/platform/graphics/haiku/IconHaiku.cpp @@ -36,12 +36,6 @@ Icon::~Icon() notImplemented(); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - notImplemented(); - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { notImplemented(); diff --git a/WebCore/platform/graphics/haiku/ImageHaiku.cpp b/WebCore/platform/graphics/haiku/ImageHaiku.cpp index 323d6ab..df08822 100644 --- a/WebCore/platform/graphics/haiku/ImageHaiku.cpp +++ b/WebCore/platform/graphics/haiku/ImageHaiku.cpp @@ -83,7 +83,7 @@ void BitmapImage::invalidatePlatformData() } // Drawing Routines -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { startAnimation(); @@ -92,7 +92,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -109,7 +109,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR ctxt->restore(); } -void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& srcPoint, CompositeOperator op, const FloatRect& dstRect) +void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& srcPoint, ColorSpace, CompositeOperator op, const FloatRect& dstRect) { // FIXME: finish this to support also phased position (srcPoint) startAnimation(); diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp index b2682e4..265b2c3 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,30 +10,24 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "CoreTextController.h" - -#if USE(CORE_TEXT) +#include "ComplexTextController.h" #include "CharacterNames.h" #include "Font.h" -#include "FontCache.h" -#include "SimpleFontData.h" #include "TextBreakIterator.h" -#include <wtf/MathExtras.h> using namespace std; @@ -53,54 +47,7 @@ static inline CGFloat ceilCGFloat(CGFloat f) return static_cast<CGFloat>(ceil(f)); } -CoreTextController::CoreTextRun::CoreTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) - : m_CTRun(ctRun) - , m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) -{ - m_glyphCount = CTRunGetGlyphCount(ctRun); - m_indices = CTRunGetStringIndicesPtr(ctRun); - if (!m_indices) { - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get())); - CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices)); - } -} - -// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on -// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path. -CoreTextController::CoreTextRun::CoreTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) - : m_fontData(fontData) - , m_characters(characters) - , m_stringLocation(stringLocation) - , m_stringLength(stringLength) -{ - Vector<CFIndex, 16> indices; - unsigned r = 0; - while (r < stringLength) { - indices.append(r); - if (U_IS_SURROGATE(characters[r])) { - ASSERT(r + 1 < stringLength); - ASSERT(U_IS_SURROGATE_LEAD(characters[r])); - ASSERT(U_IS_TRAIL(characters[r + 1])); - r += 2; - } else - r++; - } - m_glyphCount = indices.size(); - if (!ltr) { - for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) - std::swap(indices[r], indices[end]); - } - m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); - CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); - m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); -} - -CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) +ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts) : m_font(*font) , m_run(run) , m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection) @@ -111,6 +58,7 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo , m_numGlyphsSoFar(0) , m_currentRun(0) , m_glyphInCurrentRun(0) + , m_characterInCurrentGlyph(0) , m_finalRoundingWidth(0) , m_fallbackFonts(fallbackFonts) , m_lastRoundingGlyph(0) @@ -130,16 +78,12 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo m_padPerSpace = ceilf(m_run.padding() / numSpaces); } - collectCoreTextRuns(); + collectComplexTextRuns(); adjustGlyphsAndAdvances(); } -int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) +int ComplexTextController::offsetForPosition(int h, bool includePartialGlyphs) { - // FIXME: For positions occurring within a ligature, we should return the closest "ligature caret" or - // approximate it by dividing the width of the ligature by the number of characters it encompasses. - // However, Core Text does not expose a low-level API for directly finding - // out how many characters a ligature encompasses (the "attachment count"). if (h >= m_totalWidth) return m_run.ltr() ? m_end : 0; if (h < 0) @@ -147,17 +91,27 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) CGFloat x = h; - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); size_t offsetIntoAdjustedGlyphs = 0; for (size_t r = 0; r < runCount; ++r) { - const CoreTextRun& coreTextRun = m_coreTextRuns[r]; - for (unsigned j = 0; j < coreTextRun.glyphCount(); ++j) { + const ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; + for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) { CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width; - if (x <= adjustedAdvance) { - CFIndex hitIndex = coreTextRun.indexAt(j); - int stringLength = coreTextRun.stringLength(); - TextBreakIterator* cursorPositionIterator = cursorMovementIterator(coreTextRun.characters(), stringLength); + if (x < adjustedAdvance) { + CFIndex hitGlyphStart = complexTextRun.indexAt(j); + CFIndex hitGlyphEnd; + if (m_run.ltr()) + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : complexTextRun.stringLength()); + else + hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.stringLength()); + + // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // could use the glyph's "ligature carets". However, there is no Core Text API to get the + // ligature carets. + CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance); + int stringLength = complexTextRun.stringLength(); + TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength); int clusterStart; if (isTextBreak(cursorPositionIterator, hitIndex)) clusterStart = hitIndex; @@ -168,45 +122,49 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) } if (!includePartialGlyphs) - return coreTextRun.stringLocation() + clusterStart; + return complexTextRun.stringLocation() + clusterStart; int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex); if (clusterEnd == TextBreakDone) clusterEnd = stringLength; - CGFloat clusterWidth = adjustedAdvance; - // FIXME: The search stops at the boundaries of coreTextRun. In theory, it should go on into neighboring CoreTextRuns + CGFloat clusterWidth; + // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no // reordering and on font fallback should occur within a CTLine. if (clusterEnd - clusterStart > 1) { + clusterWidth = adjustedAdvance; int firstGlyphBeforeCluster = j - 1; - while (firstGlyphBeforeCluster >= 0 && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { + while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width; clusterWidth += width; x += width; firstGlyphBeforeCluster--; } unsigned firstGlyphAfterCluster = j + 1; - while (firstGlyphAfterCluster < coreTextRun.glyphCount() && coreTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) { + while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) { clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width; firstGlyphAfterCluster++; } + } else { + clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart); + x -= clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1); } if (x <= clusterWidth / 2) - return coreTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd); + return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd); else - return coreTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart); + return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart); } x -= adjustedAdvance; } - offsetIntoAdjustedGlyphs += coreTextRun.glyphCount(); + offsetIntoAdjustedGlyphs += complexTextRun.glyphCount(); } ASSERT_NOT_REACHED(); return 0; } -void CoreTextController::collectCoreTextRuns() +void ComplexTextController::collectComplexTextRuns() { if (!m_end) return; @@ -227,7 +185,7 @@ void CoreTextController::collectCoreTextRuns() static const UChar hyphen = '-'; if (hasTrailingSoftHyphen && m_run.rtl()) { - collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); + collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); indexOfFontTransition--; curr--; } @@ -290,7 +248,7 @@ void CoreTextController::collectCoreTextRuns() if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) { int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition; int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition; - collectCoreTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0); + collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0); indexOfFontTransition = index; } } @@ -298,19 +256,15 @@ void CoreTextController::collectCoreTextRuns() int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition - (hasTrailingSoftHyphen ? 1 : 0); if (itemLength) { int itemStart = m_run.rtl() ? 0 : indexOfFontTransition; - collectCoreTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); + collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0); } if (hasTrailingSoftHyphen && m_run.ltr()) - collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); + collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData); } -void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) +void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) { - // FIXME: For offsets falling inside a ligature, we should advance only as far as the appropriate "ligature caret" - // or divide the width of the ligature by the number of offsets it encompasses and make an advance proportional - // to the offsets into the ligature. However, Core Text does not expose a low-level API for - // directly finding out how many characters a ligature encompasses (the "attachment count"). if (static_cast<int>(offset) > m_end) offset = m_end; @@ -319,24 +273,44 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) m_currentCharacter = offset; - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); bool ltr = m_run.ltr(); unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar; while (m_currentRun < runCount) { - const CoreTextRun& coreTextRun = m_coreTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun]; - size_t glyphCount = coreTextRun.glyphCount(); + const ComplexTextRun& complexTextRun = *m_complexTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun]; + size_t glyphCount = complexTextRun.glyphCount(); unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun; while (m_glyphInCurrentRun < glyphCount) { - if (coreTextRun.indexAt(g) + coreTextRun.stringLocation() >= m_currentCharacter) - return; + unsigned glyphStartOffset = complexTextRun.indexAt(g); + unsigned glyphEndOffset; + if (ltr) + glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.stringLength()); + else + glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.stringLength()); + CGSize adjustedAdvance = m_adjustedAdvances[k]; - if (glyphBuffer) - glyphBuffer->add(m_adjustedGlyphs[k], coreTextRun.fontData(), adjustedAdvance); - m_runWidthSoFar += adjustedAdvance.width; + + if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter) + return; + + if (glyphBuffer && !m_characterInCurrentGlyph) + glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance); + + unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph; + m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset; + // FIXME: Instead of dividing the glyph's advance equially between the characters, this + // could use the glyph's "ligature carets". However, there is no Core Text API to get the + // ligature carets. + m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset); + + if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter) + return; + m_numGlyphsSoFar++; m_glyphInCurrentRun++; + m_characterInCurrentGlyph = 0; if (ltr) { g++; k++; @@ -352,100 +326,35 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer) m_runWidthSoFar += m_finalRoundingWidth; } -void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) -{ - if (!fontData) { - // Create a run of missing glyphs from the primary font. - m_coreTextRuns.append(CoreTextRun(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); - return; - } - - if (m_fallbackFonts && fontData != m_font.primaryFont()) - m_fallbackFonts->add(fontData); - - RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); - - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); - - RetainPtr<CTTypesetterRef> typesetter; - - if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) { - static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; - static const void* ltrOptionValues[] = { kCFBooleanFalse }; - static const void* rtlOptionValues[] = { kCFBooleanTrue }; - static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); - } else - typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); - - RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); - - CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); - - CFIndex runCount = CFArrayGetCount(runArray); - - for (CFIndex r = 0; r < runCount; r++) { - CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); - ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); - m_coreTextRuns.append(CoreTextRun(ctRun, fontData, cp, stringLocation, length)); - } -} - -void CoreTextController::adjustGlyphsAndAdvances() +void ComplexTextController::adjustGlyphsAndAdvances() { - size_t runCount = m_coreTextRuns.size(); + size_t runCount = m_complexTextRuns.size(); for (size_t r = 0; r < runCount; ++r) { - const CoreTextRun& coreTextRun = m_coreTextRuns[r]; - unsigned glyphCount = coreTextRun.glyphCount(); - const SimpleFontData* fontData = coreTextRun.fontData(); - - Vector<CGGlyph, 256> glyphsVector; - const CGGlyph* glyphs; - - Vector<CGSize, 256> advancesVector; - const CGSize* advances; - - if (coreTextRun.ctRun()) { - glyphs = CTRunGetGlyphsPtr(coreTextRun.ctRun()); - if (!glyphs) { - glyphsVector.grow(glyphCount); - CTRunGetGlyphs(coreTextRun.ctRun(), CFRangeMake(0, 0), glyphsVector.data()); - glyphs = glyphsVector.data(); - } + const ComplexTextRun& complexTextRun = *m_complexTextRuns[r]; + unsigned glyphCount = complexTextRun.glyphCount(); + const SimpleFontData* fontData = complexTextRun.fontData(); - advances = CTRunGetAdvancesPtr(coreTextRun.ctRun()); - if (!advances) { - advancesVector.grow(glyphCount); - CTRunGetAdvances(coreTextRun.ctRun(), CFRangeMake(0, 0), advancesVector.data()); - advances = advancesVector.data(); - } - } else { - // Synthesize a run of missing glyphs. - glyphsVector.fill(0, glyphCount); - glyphs = glyphsVector.data(); - advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), glyphCount); - advances = advancesVector.data(); - } + const CGGlyph* glyphs = complexTextRun.glyphs(); + const CGSize* advances = complexTextRun.advances(); bool lastRun = r + 1 == runCount; - const UChar* cp = coreTextRun.characters(); + const UChar* cp = complexTextRun.characters(); CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth()); bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances(); bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled(); for (unsigned i = 0; i < glyphCount; i++) { - CFIndex characterIndex = coreTextRun.indexAt(i); + CFIndex characterIndex = complexTextRun.indexAt(i); UChar ch = *(cp + characterIndex); bool lastGlyph = lastRun && i + 1 == glyphCount; UChar nextCh; if (lastGlyph) nextCh = ' '; else if (i + 1 < glyphCount) - nextCh = *(cp + coreTextRun.indexAt(i + 1)); + nextCh = *(cp + complexTextRun.indexAt(i + 1)); else - nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0)); + nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0)); bool treatAsSpace = Font::treatAsSpace(ch); CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i]; @@ -533,5 +442,3 @@ void CoreTextController::adjustGlyphsAndAdvances() } } // namespace WebCore - -#endif // USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h new file mode 100644 index 0000000..7a915e2 --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextController.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 ComplexTextController_h +#define ComplexTextController_h + +#include "GlyphBuffer.h" +#include <wtf/HashSet.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +class Font; +class SimpleFontData; +class TextRun; + +class ComplexTextController { +public: + ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); + + // Advance and emit glyphs up to the specified character. + void advance(unsigned to, GlyphBuffer* = 0); + + // Compute the character offset for a given x coordinate. + int offsetForPosition(int x, bool includePartialGlyphs); + + // Returns the width of everything we've consumed so far. + float runWidthSoFar() const { return m_runWidthSoFar; } + + float totalWidth() const { return m_totalWidth; } + + // Extra width to the left of the leftmost glyph. + float finalRoundingWidth() const { return m_finalRoundingWidth; } + +private: + class ComplexTextRun : public RefCounted<ComplexTextRun> { + public: +#if USE(CORE_TEXT) + static PassRefPtr<ComplexTextRun> create(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) + { + return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength)); + } +#elif USE(ATSUI) + static PassRefPtr<ComplexTextRun> create(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride) + { + return adoptRef(new ComplexTextRun(atsuTextLayout, fontData, characters, stringLocation, stringLength, ltr, directionalOverride)); + } +#endif + static PassRefPtr<ComplexTextRun> create(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + { + return adoptRef(new ComplexTextRun(fontData, characters, stringLocation, stringLength, ltr)); + } + + unsigned glyphCount() const { return m_glyphCount; } + const SimpleFontData* fontData() const { return m_fontData; } + const UChar* characters() const { return m_characters; } + unsigned stringLocation() const { return m_stringLocation; } + size_t stringLength() const { return m_stringLength; } + CFIndex indexAt(size_t i) const { return m_indices[i]; } + const CGGlyph* glyphs() const { return m_glyphs; } + const CGSize* advances() const { return m_advances; } + + private: +#if USE(CORE_TEXT) + ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); +#elif USE(ATSUI) + ComplexTextRun(ATSUTextLayout, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride); +#endif + ComplexTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr); + +#if USE(ATSUI) +#ifdef BUILDING_ON_TIGER + typedef UInt32 URefCon; +#endif + static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef, URefCon, void*, ATSULayoutOperationCallbackStatus*); +#endif + +#if USE(CORE_TEXT) + RetainPtr<CTRunRef> m_CTRun; +#endif + unsigned m_glyphCount; + const SimpleFontData* m_fontData; + const UChar* m_characters; + unsigned m_stringLocation; + size_t m_stringLength; +#if USE(CORE_TEXT) + RetainPtr<CFMutableDataRef> m_indicesData; + const CFIndex* m_indices; +#elif USE(ATSUI) + Vector<CFIndex, 64> m_indices; +#endif + Vector<CGGlyph, 64> m_glyphsVector; + const CGGlyph* m_glyphs; + Vector<CGSize, 64> m_advancesVector; + const CGSize* m_advances; +#if USE(ATSUI) + bool m_ltr; + bool m_directionalOverride; +#endif + }; + + void collectComplexTextRuns(); + void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); + void adjustGlyphsAndAdvances(); + + const Font& m_font; + const TextRun& m_run; + bool m_mayUseNaturalWritingDirection; + + Vector<UChar, 256> m_smallCapsBuffer; + + Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns; + Vector<CGSize, 256> m_adjustedAdvances; + Vector<CGGlyph, 256> m_adjustedGlyphs; + + unsigned m_currentCharacter; + int m_end; + + CGFloat m_totalWidth; + + float m_runWidthSoFar; + unsigned m_numGlyphsSoFar; + size_t m_currentRun; + unsigned m_glyphInCurrentRun; + unsigned m_characterInCurrentGlyph; + float m_finalRoundingWidth; + float m_padding; + float m_padPerSpace; + + HashSet<const SimpleFontData*>* m_fallbackFonts; + + unsigned m_lastRoundingGlyph; +}; + +} // namespace WebCore + +#endif // ComplexTextController_h diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp new file mode 100644 index 0000000..78c588f --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp @@ -0,0 +1,341 @@ +/* + * 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, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * 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 "ComplexTextController.h" + +#if USE(ATSUI) + +#include "CharacterNames.h" +#include "Font.h" +#include "ShapeArabic.h" + +#ifdef __LP64__ +// ATSUTextInserted() is SPI in 64-bit. +extern "C" { +OSStatus ATSUTextInserted(ATSUTextLayout iTextLayout, UniCharArrayOffset iInsertionLocation, UniCharCount iInsertionLength); +} +#endif + +using namespace WTF::Unicode; + +namespace WebCore { + +OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef atsuLineRef, URefCon refCon, void*, ATSULayoutOperationCallbackStatus* callbackStatus) +{ + ComplexTextRun* complexTextRun = reinterpret_cast<ComplexTextRun*>(refCon); + OSStatus status; + ItemCount count; + ATSLayoutRecord *layoutRecords; + + status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, reinterpret_cast<void**>(&layoutRecords), &count); + if (status != noErr) { + *callbackStatus = kATSULayoutOperationCallbackStatusContinue; + return status; + } + + count--; + ItemCount j = 0; + CFIndex indexOffset = 0; + + if (complexTextRun->m_directionalOverride) { + j++; + count -= 2; + indexOffset = -1; + } + + complexTextRun->m_glyphCount = count; + complexTextRun->m_glyphsVector.reserveCapacity(count); + complexTextRun->m_advancesVector.reserveCapacity(count); + complexTextRun->m_indices.reserveCapacity(count); + + bool atBeginning = true; + CGFloat lastX = 0; + + for (ItemCount i = 0; i < count; ++i, ++j) { + if (layoutRecords[j].glyphID == kATSDeletedGlyphcode) { + complexTextRun->m_glyphCount--; + continue; + } + complexTextRun->m_glyphsVector.uncheckedAppend(layoutRecords[j].glyphID); + complexTextRun->m_indices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset); + CGFloat x = FixedToFloat(layoutRecords[j].realPos); + if (!atBeginning) + complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(x - lastX, 0)); + lastX = x; + atBeginning = false; + } + + complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(FixedToFloat(layoutRecords[j].realPos) - lastX, 0)); + + complexTextRun->m_glyphs = complexTextRun->m_glyphsVector.data(); + complexTextRun->m_advances = complexTextRun->m_advancesVector.data(); + + status = ATSUDirectReleaseLayoutDataArrayPtr(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, reinterpret_cast<void**>(&layoutRecords)); + *callbackStatus = kATSULayoutOperationCallbackStatusContinue; + 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 = 0; + 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; + } +} + +ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) + , m_ltr(ltr) + , m_directionalOverride(directionalOverride) +{ + OSStatus status; + + status = ATSUSetTextLayoutRefCon(atsuTextLayout, reinterpret_cast<URefCon>(this)); + + ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers; + + Boolean rtl = !ltr; + + Vector<UChar, 256> substituteCharacters; + bool shouldCheckForMirroring = !ltr && !fontData->m_ATSUMirrors; + bool shouldCheckForArabic = !fontData->shapesArabic(); + bool shouldShapeArabic = false; + + bool mirrored = false; + for (size_t i = 0; i < stringLength; ++i) { + if (shouldCheckForMirroring) { + UChar mirroredChar = u_charMirror(characters[i]); + if (mirroredChar != characters[i]) { + if (!mirrored) { + mirrored = true; + substituteCharacters.grow(stringLength); + memcpy(substituteCharacters.data(), characters, stringLength * sizeof(UChar)); + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } + substituteCharacters[i] = mirroredChar; + } + } + if (shouldCheckForArabic && isArabicChar(characters[i])) { + shouldCheckForArabic = false; + shouldShapeArabic = true; + } + } + + if (shouldShapeArabic) { + Vector<UChar, 256> shapedArabic(stringLength); + shapeArabic(substituteCharacters.isEmpty() ? characters : substituteCharacters.data(), shapedArabic.data(), stringLength); + substituteCharacters.swap(shapedArabic); + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } + + if (directionalOverride) { + UChar override = ltr ? leftToRightOverride : rightToLeftOverride; + if (substituteCharacters.isEmpty()) { + substituteCharacters.grow(stringLength + 2); + substituteCharacters[0] = override; + memcpy(substituteCharacters.data() + 1, characters, stringLength * sizeof(UChar)); + substituteCharacters[stringLength + 1] = popDirectionalFormatting; + ATSUTextMoved(atsuTextLayout, substituteCharacters.data()); + } else { + substituteCharacters.prepend(override); + substituteCharacters.append(popDirectionalFormatting); + } + ATSUTextInserted(atsuTextLayout, 0, 2); + } + + ATSULayoutOperationOverrideSpecifier overrideSpecifier; + overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment; + overrideSpecifier.overrideUPP = overrideLayoutOperation; + + ATSUAttributeTag tags[] = { kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag }; + ByteCount sizes[] = { sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) }; + ATSUAttributeValuePtr values[] = { &lineLayoutOptions, &rtl, &overrideSpecifier }; + + status = ATSUSetLayoutControls(atsuTextLayout, 3, tags, sizes, values); + + ItemCount boundsCount; + status = ATSUGetGlyphBounds(atsuTextLayout, 0, 0, 0, m_stringLength, kATSUseFractionalOrigins, 0, 0, &boundsCount); + + status = ATSUDisposeTextLayout(atsuTextLayout); +} + +ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + m_indices.reserveCapacity(stringLength); + unsigned r = 0; + while (r < stringLength) { + m_indices.uncheckedAppend(r); + if (U_IS_SURROGATE(characters[r])) { + ASSERT(r + 1 < stringLength); + ASSERT(U_IS_SURROGATE_LEAD(characters[r])); + ASSERT(U_IS_TRAIL(characters[r + 1])); + r += 2; + } else + r++; + } + m_glyphCount = m_indices.size(); + if (!ltr) { + for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) + std::swap(m_indices[r], m_indices[end]); + } + + m_glyphsVector.fill(0, m_glyphCount); + m_glyphs = m_glyphsVector.data(); + m_advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), m_glyphCount); + m_advances = m_advancesVector.data(); +} + +static bool fontHasMirroringInfo(ATSUFontID fontID) +{ + ByteCount propTableSize; + OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize); + if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info + return true; + else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error + LOG_ERROR("ATSFontGetTable failed (%d)", static_cast<int>(status)); + + return false; +} + +static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode) +{ + // 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 (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) + return; + + ATSUFontFeatureType featureTypes[] = { kLigaturesType }; + ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector }; + OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors); + if (status != noErr) + LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", static_cast<int>(status)); +} + +static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) +{ + if (fontData->m_ATSUStyleInitialized) + return; + + ATSUFontID fontID = fontData->platformData().m_atsuFontID; + if (!fontID) { + LOG_ERROR("unable to get ATSUFontID for %p", fontData->platformData().font()); + return; + } + + OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle); + if (status != noErr) + LOG_ERROR("ATSUCreateStyle failed (%d)", static_cast<int>(status)); + + Fixed fontSize = FloatToFixed(fontData->platformData().m_size); + Fract kerningInhibitFactor = FloatToFract(1); + static CGAffineTransform verticalFlip = CGAffineTransformMakeScale(1, -1); + + ByteCount styleSizes[4] = { sizeof(fontSize), sizeof(fontID), sizeof(verticalFlip), sizeof(kerningInhibitFactor) }; + ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; + ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &verticalFlip, &kerningInhibitFactor }; + + bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; + status = ATSUSetAttributes(fontData->m_ATSUStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues); + if (status != noErr) + LOG_ERROR("ATSUSetAttributes failed (%d)", static_cast<int>(status)); + + fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); + + disableLigatures(fontData, textMode); + + fontData->m_ATSUStyleInitialized = true; +} + +void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +{ + if (!fontData) { + // Create a run of missing glyphs from the primary font. + m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); + return; + } + + if (m_fallbackFonts && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + + initializeATSUStyle(fontData, m_font.fontDescription().textRenderingMode()); + + OSStatus status; + ATSUTextLayout atsuTextLayout; + UniCharCount runLength = length; + + status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &fontData->m_ATSUStyle, &atsuTextLayout); + if (status != noErr) { + LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed with error %d", static_cast<int>(status)); + return; + } + m_complexTextRuns.append(ComplexTextRun::create(atsuTextLayout, fontData, cp, stringLocation, length, m_run.ltr(), m_run.directionalOverride())); +} + +} // namespace WebCore + +#endif // USE(ATSUI) diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp new file mode 100644 index 0000000..c9daf84 --- /dev/null +++ b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "ComplexTextController.h" + +#if USE(CORE_TEXT) + +#include "Font.h" + +namespace WebCore { + +ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength) + : m_CTRun(ctRun) + , m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + m_glyphCount = CTRunGetGlyphCount(m_CTRun.get()); + m_indices = CTRunGetStringIndicesPtr(m_CTRun.get()); + if (!m_indices) { + m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex)); + m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get())); + CTRunGetStringIndices(m_CTRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices)); + } + + m_glyphs = CTRunGetGlyphsPtr(m_CTRun.get()); + if (!m_glyphs) { + m_glyphsVector.grow(m_glyphCount); + CTRunGetGlyphs(m_CTRun.get(), CFRangeMake(0, 0), m_glyphsVector.data()); + m_glyphs = m_glyphsVector.data(); + } + + m_advances = CTRunGetAdvancesPtr(m_CTRun.get()); + if (!m_advances) { + m_advancesVector.grow(m_glyphCount); + CTRunGetAdvances(m_CTRun.get(), CFRangeMake(0, 0), m_advancesVector.data()); + m_advances = m_advancesVector.data(); + } + +} + +// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on +// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path. +ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr) + : m_fontData(fontData) + , m_characters(characters) + , m_stringLocation(stringLocation) + , m_stringLength(stringLength) +{ + Vector<CFIndex, 16> indices; + unsigned r = 0; + while (r < stringLength) { + indices.append(r); + if (U_IS_SURROGATE(characters[r])) { + ASSERT(r + 1 < stringLength); + ASSERT(U_IS_SURROGATE_LEAD(characters[r])); + ASSERT(U_IS_TRAIL(characters[r + 1])); + r += 2; + } else + r++; + } + m_glyphCount = indices.size(); + if (!ltr) { + for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end) + std::swap(indices[r], indices[end]); + } + m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex))); + CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex)); + m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get())); + + // Synthesize a run of missing glyphs. + m_glyphsVector.fill(0, m_glyphCount); + m_glyphs = m_glyphsVector.data(); + m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount); + m_advances = m_advancesVector.data(); +} + +void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData) +{ + if (!fontData) { + // Create a run of missing glyphs from the primary font. + m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr())); + return; + } + + if (m_fallbackFonts && fontData != m_font.primaryFont()) + m_fallbackFonts->add(fontData); + + RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); + + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); + + RetainPtr<CTTypesetterRef> typesetter; + + if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) { + static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; + static const void* ltrOptionValues[] = { kCFBooleanFalse }; + static const void* rtlOptionValues[] = { kCFBooleanTrue }; + static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); + } else + typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); + + RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0))); + + CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); + + CFIndex runCount = CFArrayGetCount(runArray); + + for (CFIndex r = 0; r < runCount; r++) { + CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r)); + ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); + m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length)); + } +} + +} // namespace WebCore + +#endif // USE(CORE_TEXT) diff --git a/WebCore/platform/graphics/mac/CoreTextController.h b/WebCore/platform/graphics/mac/CoreTextController.h deleted file mode 100644 index 4dd6f93..0000000 --- a/WebCore/platform/graphics/mac/CoreTextController.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CoreTextController_h -#define CoreTextController_h - -#if USE(CORE_TEXT) - -#include "Font.h" -#include "GlyphBuffer.h" -#include <wtf/RetainPtr.h> -#include <wtf/Vector.h> - -namespace WebCore { - -class CoreTextController { -public: - CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0); - - // Advance and emit glyphs up to the specified character. - void advance(unsigned to, GlyphBuffer* = 0); - - // Compute the character offset for a given x coordinate. - int offsetForPosition(int x, bool includePartialGlyphs); - - // Returns the width of everything we've consumed so far. - float runWidthSoFar() const { return m_runWidthSoFar; } - - float totalWidth() const { return m_totalWidth; } - - // Extra width to the left of the leftmost glyph. - float finalRoundingWidth() const { return m_finalRoundingWidth; } - -private: - class CoreTextRun { - public: - CoreTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength); - CoreTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr); - - CTRunRef ctRun() const { return m_CTRun.get(); } - unsigned glyphCount() const { return m_glyphCount; } - const SimpleFontData* fontData() const { return m_fontData; } - const UChar* characters() const { return m_characters; } - unsigned stringLocation() const { return m_stringLocation; } - size_t stringLength() const { return m_stringLength; } - CFIndex indexAt(size_t i) const { return m_indices[i]; } - - private: - RetainPtr<CTRunRef> m_CTRun; - unsigned m_glyphCount; - const SimpleFontData* m_fontData; - const UChar* m_characters; - unsigned m_stringLocation; - size_t m_stringLength; - const CFIndex* m_indices; - // Used only if CTRunGet*Ptr fails or if this is a missing glyphs run. - RetainPtr<CFMutableDataRef> m_indicesData; - }; - - void collectCoreTextRuns(); - void collectCoreTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*); - void adjustGlyphsAndAdvances(); - - const Font& m_font; - const TextRun& m_run; - bool m_mayUseNaturalWritingDirection; - - Vector<UChar, 256> m_smallCapsBuffer; - - Vector<CoreTextRun, 16> m_coreTextRuns; - Vector<CGSize, 256> m_adjustedAdvances; - Vector<CGGlyph, 256> m_adjustedGlyphs; - - unsigned m_currentCharacter; - int m_end; - - CGFloat m_totalWidth; - - float m_runWidthSoFar; - unsigned m_numGlyphsSoFar; - size_t m_currentRun; - unsigned m_glyphInCurrentRun; - float m_finalRoundingWidth; - float m_padding; - float m_padPerSpace; - - HashSet<const SimpleFontData*>* m_fallbackFonts; - - unsigned m_lastRoundingGlyph; -}; - -} // namespace WebCore -#endif // USE(CORE_TEXT) -#endif // CoreTextController_h diff --git a/WebCore/platform/graphics/mac/FontMacCoreText.cpp b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp index 9dffc7a..0db2601 100644 --- a/WebCore/platform/graphics/mac/FontMacCoreText.cpp +++ b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,25 +10,22 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "Font.h" -#if USE(CORE_TEXT) - -#include "CoreTextController.h" +#include "ComplexTextController.h" #include "FontFallbackList.h" #include "GlyphBuffer.h" #include "GraphicsContext.h" @@ -41,7 +38,7 @@ namespace WebCore { FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const { - CoreTextController controller(this, run); + ComplexTextController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to); @@ -63,7 +60,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F GlyphBuffer glyphBuffer; float startX = point.x(); - CoreTextController controller(this, run); + ComplexTextController controller(this, run); controller.advance(from); float beforeWidth = controller.runWidthSoFar(); controller.advance(to, &glyphBuffer); @@ -88,15 +85,14 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const { - CoreTextController controller(this, run, true, fallbackFonts); + ComplexTextController controller(this, run, true, fallbackFonts); return controller.totalWidth(); } int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const { - CoreTextController controller(this, run); + ComplexTextController controller(this, run); return controller.offsetForPosition(x, includePartialGlyphs); } -} -#endif // USE(CORE_TEXT) +} // namespace WebCore diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index 5e72101..256b5a4 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -24,6 +24,7 @@ #include <ApplicationServices/ApplicationServices.h> #include "SharedBuffer.h" #include "FontPlatformData.h" +#include "OpenTypeSanitizer.h" namespace WebCore { @@ -43,6 +44,14 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); +#if ENABLE(OPENTYPE_SANITIZER) + OpenTypeSanitizer sanitizer(buffer); + RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize(); + if (!transcodeBuffer) + return 0; // validation failed. + buffer = transcodeBuffer.get(); +#endif + ATSFontContainerRef containerRef = 0; ATSFontRef fontRef = 0; diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index b2b9a5c..bb9561e 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -115,6 +115,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons IntSize shadowSize; int shadowBlur; Color shadowColor; + ColorSpace fillColorSpace = context->fillColorSpace(); context->getShadow(shadowSize, shadowBlur, shadowColor); bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; @@ -123,14 +124,14 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons context->clearShadow(); Color fillColor = context->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - context->setFillColor(shadowFillColor); + context->setFillColor(shadowFillColor, fillColorSpace); CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } - context->setFillColor(fillColor); + context->setFillColor(fillColor, fillColorSpace); } CGContextSetTextPosition(cgContext, point.x(), point.y()); @@ -141,7 +142,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } if (hasSimpleShadow) - context->setShadow(shadowSize, shadowBlur, shadowColor); + context->setShadow(shadowSize, shadowBlur, shadowColor, fillColorSpace); if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing); diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm deleted file mode 100644 index 409bda4..0000000 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006 Apple Computer, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#import "config.h" -#import "Font.h" - -#if USE(ATSUI) - -#import "CharacterNames.h" -#import "GraphicsContext.h" -#import "Logging.h" -#import "ShapeArabic.h" -#import "SimpleFontData.h" -#import <AppKit/NSGraphicsContext.h> -#import <wtf/OwnArrayPtr.h> - -#define SYNTHETIC_OBLIQUE_ANGLE 14 - -#ifdef __LP64__ -#define URefCon void* -#else -#define URefCon UInt32 -#endif - -using namespace std; - -namespace WebCore { - -struct ATSULayoutParameters : Noncopyable -{ - ATSULayoutParameters(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0) - : m_run(run) - , m_font(0) - , m_hasSyntheticBold(false) - , m_syntheticBoldPass(false) - , m_padPerSpace(0) - , m_fallbackFonts(fallbackFonts) - { - } - - ~ATSULayoutParameters() - { - ATSUDisposeTextLayout(m_layout); - } - - void initialize(const Font*, const GraphicsContext* = 0); - - const TextRun& m_run; - - const Font* m_font; - - ATSUTextLayout m_layout; - OwnArrayPtr<const SimpleFontData*> m_fonts; - - OwnArrayPtr<UChar> m_charBuffer; - bool m_hasSyntheticBold; - bool m_syntheticBoldPass; - float m_padPerSpace; - HashSet<const SimpleFontData*>* m_fallbackFonts; -}; - -static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride) -{ - if (!run.directionalOverride()) - return run; - - charactersWithOverride.set(new UChar[run.length() + 2]); - charactersWithOverride[0] = run.rtl() ? rightToLeftOverride : leftToRightOverride; - memcpy(&charactersWithOverride[1], run.data(0), sizeof(UChar) * run.length()); - charactersWithOverride[run.length() + 1] = popDirectionalFormatting; - - TextRun result = run; - result.setText(charactersWithOverride.get(), run.length() + 2); - return result; -} - -static bool fontHasMirroringInfo(ATSUFontID fontID) -{ - ByteCount propTableSize; - OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize); - if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info - return true; - else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error - LOG_ERROR("ATSFontGetTable failed (%d)", status); - - return false; -} - -static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode) -{ - // 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 (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) - return; - - ATSUFontFeatureType featureTypes[] = { kLigaturesType }; - ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector }; - OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors); - if (status != noErr) - LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status); -} - -static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) -{ - if (fontData->m_ATSUStyleInitialized) - return; - - ATSUFontID fontID = fontData->platformData().m_atsuFontID; - if (!fontID) { - LOG_ERROR("unable to get ATSUFontID for %@", fontData->platformData().font()); - return; - } - - OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle); - if (status != noErr) - // Who knows how many ATSU functions will crash when passed a NULL style... - LOG_ERROR("ATSUCreateStyle failed (%d)", status); - - CGAffineTransform transform = CGAffineTransformMakeScale(1, -1); - if (fontData->platformData().m_syntheticOblique) - transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); - Fixed fontSize = FloatToFixed(fontData->platformData().m_size); - ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) }; - - bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; - if (!allowKerning) { - // Turn off automatic kerning until it is supported in the CG code path (bug 6136) - Fract kerningInhibitFactor = FloatToFract(1.0); - ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; - ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor }; - status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues); - if (status != noErr) - LOG_ERROR("ATSUSetAttributes failed (%d)", status); - } else { - ATSUAttributeTag styleTags[3] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag }; - ATSUAttributeValuePtr styleValues[3] = { &fontSize, &fontID, &transform, }; - status = ATSUSetAttributes(fontData->m_ATSUStyle, 3, styleTags, styleSizes, styleValues); - if (status != noErr) - LOG_ERROR("ATSUSetAttributes failed (%d)", status); - } - - fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); - - // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bug 6135 is fixed. - disableLigatures(fontData, textMode); - - fontData->m_ATSUStyleInitialized = true; -} - -static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef iLineRef, URefCon iRefCon, void*, ATSULayoutOperationCallbackStatus* oCallbackStatus) -{ - ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon); - OSStatus status; - ItemCount count; - ATSLayoutRecord *layoutRecords; - - if (params->m_run.applyWordRounding()) { - status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, (void **)&layoutRecords, &count); - if (status != noErr) { - *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue; - return status; - } - - Fixed lastNativePos = 0; - float lastAdjustedPos = 0; - const UChar* characters = params->m_charBuffer ? params->m_charBuffer.get() : params->m_run.characters(); - const SimpleFontData** renderers = params->m_fonts.get(); - const SimpleFontData* renderer; - const SimpleFontData* lastRenderer = 0; - ByteCount offset = layoutRecords[0].originalOffset; - UChar nextCh = *(UChar *)(((char *)characters)+offset); - bool shouldRound = false; - bool syntheticBoldPass = params->m_syntheticBoldPass; - Fixed syntheticBoldOffset = 0; - bool hasExtraSpacing = (params->m_font->letterSpacing() || params->m_font->wordSpacing() || params->m_run.padding()) && !params->m_run.spacingDisabled(); - float padding = params->m_run.padding(); - // In the CoreGraphics code path, the rounding hack is applied in logical order. - // Here it is applied in visual left-to-right order, which may be better. - ItemCount lastRoundingChar = 0; - ItemCount i; - for (i = 1; i < count; i++) { - bool isLastChar = i == count - 1; - renderer = renderers[offset / 2]; - float width; - if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) { - width = 0; - layoutRecords[i-1].glyphID = renderer->spaceGlyph(); - } else { - width = FixedToFloat(layoutRecords[i].realPos - lastNativePos); - if (renderer != lastRenderer && width) { - lastRenderer = renderer; - // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems - // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI - // does in any of its device-metrics modes. - shouldRound = renderer->platformData().roundsGlyphAdvances(); - if (syntheticBoldPass) - syntheticBoldOffset = FloatToFixed(renderer->syntheticBoldOffset()); - if (params->m_fallbackFonts && renderer != params->m_font->primaryFont()) - params->m_fallbackFonts->add(renderer); - } - if (shouldRound) - width = roundf(width); - width += renderer->syntheticBoldOffset(); - if (renderer->pitch() == FixedPitch ? width == renderer->spaceWidth() : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace)) - width = renderer->adjustedSpaceWidth(); - } - lastNativePos = layoutRecords[i].realPos; - - if (hasExtraSpacing) { - if (width && params->m_font->letterSpacing()) - width +=params->m_font->letterSpacing(); - if (Font::treatAsSpace(nextCh)) { - if (params->m_run.padding()) { - if (padding < params->m_padPerSpace) { - width += padding; - padding = 0; - } else { - width += params->m_padPerSpace; - padding -= params->m_padPerSpace; - } - } - if (offset != 0 && !Font::treatAsSpace(*((UChar *)(((char *)characters)+offset) - 1)) && params->m_font->wordSpacing()) - width += params->m_font->wordSpacing(); - } - } - - UChar ch = nextCh; - offset = layoutRecords[i].originalOffset; - // Use space for nextCh at the end of the loop so that we get inside the rounding hack code. - // We won't actually round unless the other conditions are satisfied. - nextCh = isLastChar ? ' ' : *(UChar *)(((char *)characters)+offset); - - if (Font::isRoundingHackCharacter(ch)) - width = ceilf(width); - lastAdjustedPos = lastAdjustedPos + width; - if (Font::isRoundingHackCharacter(nextCh) && (!isLastChar || params->m_run.applyRunRounding())){ - if (params->m_run.ltr()) - lastAdjustedPos = ceilf(lastAdjustedPos); - else { - float roundingWidth = ceilf(lastAdjustedPos) - lastAdjustedPos; - Fixed rw = FloatToFixed(roundingWidth); - ItemCount j; - for (j = lastRoundingChar; j < i; j++) - layoutRecords[j].realPos += rw; - lastRoundingChar = i; - lastAdjustedPos += roundingWidth; - } - } - if (syntheticBoldPass) { - if (syntheticBoldOffset) - layoutRecords[i-1].realPos += syntheticBoldOffset; - else - layoutRecords[i-1].glyphID = renderer->spaceGlyph(); - } - layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos); - } - - status = ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords); - } - *oCallbackStatus = kATSULayoutOperationCallbackStatusHandled; - return noErr; -} - -static inline bool isArabicLamWithAlefLigature(UChar c) -{ - return c >= 0xfef5 && c <= 0xfefc; -} - -static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength, unsigned shapingStart) -{ - while (shapingStart < totalLength) { - unsigned shapingEnd; - // We do not want to pass a Lam with Alef ligature followed by a space to the shaper, - // since we want to be able to identify this sequence as the result of shaping a Lam - // followed by an Alef and padding with a space. - bool foundLigatureSpace = false; - for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd) - foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' '; - shapingEnd++; - - UErrorCode shapingError = U_ZERO_ERROR; - unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError); - - if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) { - for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) { - if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ') - dest[++j] = zeroWidthSpace; - } - if (foundLigatureSpace) { - dest[shapingEnd] = ' '; - shapingEnd++; - } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) { - // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef, - // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR. - ASSERT(dest[shapingStart] == ' '); - dest[shapingStart] = zeroWidthSpace; - } - } else { - // Something went wrong. Abandon shaping and just copy the rest of the buffer. - LOG_ERROR("u_shapeArabic failed(%d)", shapingError); - shapingEnd = totalLength; - memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar)); - } - shapingStart = shapingEnd; - } -} - -void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* graphicsContext) -{ - m_font = font; - - const SimpleFontData* fontData = font->primaryFont(); - m_fonts.set(new const SimpleFontData*[m_run.length()]); - if (font->isSmallCaps()) - m_charBuffer.set(new UChar[m_run.length()]); - - ATSUTextLayout layout; - OSStatus status; - ATSULayoutOperationOverrideSpecifier overrideSpecifier; - - initializeATSUStyle(fontData, m_font->fontDescription().textRenderingMode()); - - // FIXME: This is currently missing the following required features that the CoreGraphics code path has: - // - \n, \t, and nonbreaking space render as a space. - - UniCharCount runLength = m_run.length(); - - if (m_charBuffer) - memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar)); - - status = ATSUCreateTextLayoutWithTextPtr( - (m_charBuffer ? m_charBuffer.get() : m_run.characters()), - 0, // offset - runLength, // length - runLength, // total length - 1, // styleRunCount - &runLength, // length of style run - &fontData->m_ATSUStyle, - &layout); - if (status != noErr) - LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed(%d)", status); - m_layout = layout; - ATSUSetTextLayoutRefCon(m_layout, (URefCon)this); - - // FIXME: There are certain times when this method is called, when we don't have access to a GraphicsContext - // measuring text runs with floatWidthForComplexText is one example. - // ATSUI requires that we pass a valid CGContextRef to it when specifying kATSUCGContextTag (crashes when passed 0) - // ATSUI disables sub-pixel rendering if kATSUCGContextTag is not specified! So we're in a bind. - // Sometimes [[NSGraphicsContext currentContext] graphicsPort] may return the wrong (or no!) context. Nothing we can do about it (yet). - CGContextRef cgContext = graphicsContext ? graphicsContext->platformContext() : (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; - - ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers; - Boolean rtl = m_run.rtl(); - overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment; - overrideSpecifier.overrideUPP = overrideLayoutOperation; - ATSUAttributeTag tags[] = { kATSUCGContextTag, kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag }; - ByteCount sizes[] = { sizeof(CGContextRef), sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) }; - ATSUAttributeValuePtr values[] = { &cgContext, &lineLayoutOptions, &rtl, &overrideSpecifier }; - - status = ATSUSetLayoutControls(layout, (m_run.applyWordRounding() ? 4 : 3), tags, sizes, values); - if (status != noErr) - LOG_ERROR("ATSUSetLayoutControls failed(%d)", status); - - status = ATSUSetTransientFontMatching(layout, YES); - if (status != noErr) - LOG_ERROR("ATSUSetTransientFontMatching failed(%d)", status); - - m_hasSyntheticBold = false; - ATSUFontID ATSUSubstituteFont; - UniCharArrayOffset substituteOffset = 0; - UniCharCount substituteLength; - UniCharArrayOffset lastOffset; - const SimpleFontData* substituteFontData = 0; - - while (substituteOffset < runLength) { - // FIXME: Using ATSUMatchFontsToText() here results in several problems: the CSS font family list is not necessarily followed for the 2nd - // and onwards unmatched characters; segmented fonts do not work correctly; behavior does not match the simple text and Uniscribe code - // paths. Change this function to use Font::glyphDataForCharacter() for each character instead. - lastOffset = substituteOffset; - status = ATSUMatchFontsToText(layout, substituteOffset, kATSUToTextEnd, &ATSUSubstituteFont, &substituteOffset, &substituteLength); - if (status == kATSUFontsMatched || status == kATSUFontsNotMatched) { - const FontData* fallbackFontData = m_font->fontDataForCharacters(m_run.characters() + substituteOffset, substituteLength); - substituteFontData = fallbackFontData ? fallbackFontData->fontDataForCharacter(m_run[0]) : 0; - if (substituteFontData) { - initializeATSUStyle(substituteFontData, m_font->fontDescription().textRenderingMode()); - 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()), m_font->fontDescription().textRenderingMode()); - ATSUSetRunStyle(layout, r->smallCapsFontData(m_font->fontDescription())->m_ATSUStyle, firstSmallCap, i - firstSmallCap); - } - if (i == substituteOffset && substituteLength > 0) - r = substituteFontData; - else - break; - } - if (!shapedArabic && WTF::Unicode::isArabicChar(m_run[i]) && !r->shapesArabic()) { - shapedArabic = true; - if (!m_charBuffer) { - m_charBuffer.set(new UChar[runLength]); - memcpy(m_charBuffer.get(), m_run.characters(), i * sizeof(UChar)); - ATSUTextMoved(layout, m_charBuffer.get()); - } - shapeArabic(m_run.characters(), m_charBuffer.get(), runLength, i); - } - if (m_run.rtl() && !r->m_ATSUMirrors) { - UChar mirroredChar = u_charMirror(m_run[i]); - if (mirroredChar != m_run[i]) { - if (!m_charBuffer) { - m_charBuffer.set(new UChar[runLength]); - memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar)); - ATSUTextMoved(layout, m_charBuffer.get()); - } - m_charBuffer[i] = mirroredChar; - } - } - if (m_font->isSmallCaps()) { - const SimpleFontData* smallCapsData = r->smallCapsFontData(m_font->fontDescription()); - UChar c = m_charBuffer[i]; - UChar newC; - if (U_GET_GC_MASK(c) & U_GC_M_MASK) - m_fonts[i] = isSmallCap ? smallCapsData : r; - else if (!u_isUUppercase(c) && (newC = u_toupper(c)) != c) { - m_charBuffer[i] = newC; - if (!isSmallCap) { - isSmallCap = true; - firstSmallCap = i; - } - m_fonts[i] = smallCapsData; - } else { - if (isSmallCap) { - isSmallCap = false; - initializeATSUStyle(smallCapsData, m_font->fontDescription().textRenderingMode()); - ATSUSetRunStyle(layout, smallCapsData->m_ATSUStyle, firstSmallCap, i - firstSmallCap); - } - m_fonts[i] = r; - } - } else - m_fonts[i] = r; - if (m_fonts[i]->syntheticBoldOffset()) - m_hasSyntheticBold = true; - } - substituteOffset += substituteLength; - } - if (m_run.padding()) { - float numSpaces = 0; - unsigned k; - for (k = 0; k < runLength; k++) - if (Font::treatAsSpace(m_run[k])) - numSpaces++; - - if (numSpaces == 0) - m_padPerSpace = 0; - else - m_padPerSpace = ceilf(m_run.padding() / numSpaces); - } else - m_padPerSpace = 0; -} - -FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const -{ - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - if (run.directionalOverride()) { - from++; - to++; - } - - ATSULayoutParameters params(adjustedRun); - params.initialize(this); - - ATSTrapezoid firstGlyphBounds; - ItemCount actualNumBounds; - - OSStatus status = ATSUGetGlyphBounds(params.m_layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds); - if (status != noErr || actualNumBounds != 1) { - static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; - firstGlyphBounds = zeroTrapezoid; - } - - float beforeWidth = min(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x)); - float afterWidth = max(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x)); - - FloatRect rect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); - - return rect; -} - -void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - OSStatus status; - - int drawPortionLength = to - from; - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - if (run.directionalOverride()) - from++; - - ATSULayoutParameters params(adjustedRun); - params.initialize(this, graphicsContext); - - // ATSUI can't draw beyond -32768 to +32767 so we translate the CTM and tell ATSUI to draw at (0, 0). - CGContextRef context = graphicsContext->platformContext(); - CGContextTranslateCTM(context, point.x(), point.y()); - - IntSize shadowSize; - int shadowBlur; - Color shadowColor; - graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor); - - bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; - if (hasSimpleShadow) { - // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. - graphicsContext->clearShadow(); - Color fillColor = graphicsContext->fillColor(); - Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - graphicsContext->setFillColor(shadowFillColor); - CGContextTranslateCTM(context, shadowSize.width(), shadowSize.height()); - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - if (status == noErr && params.m_hasSyntheticBold) { - // Force relayout for the bold pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = true; - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - // Force relayout for the next pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = false; - } - CGContextTranslateCTM(context, -shadowSize.width(), -shadowSize.height()); - graphicsContext->setFillColor(fillColor); - } - - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - if (status == noErr && params.m_hasSyntheticBold) { - // Force relayout for the bold pass - ATSUClearLayoutCache(params.m_layout, 0); - params.m_syntheticBoldPass = true; - status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0); - } - CGContextTranslateCTM(context, -point.x(), -point.y()); - - if (status != noErr) - // Nothing to do but report the error (dev build only). - LOG_ERROR("ATSUDrawText() failed(%d)", status); - - if (hasSimpleShadow) - graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); -} - -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const -{ - if (run.length() == 0) - return 0; - - ATSULayoutParameters params(run, fallbackFonts); - params.initialize(this); - - OSStatus status; - - ATSTrapezoid firstGlyphBounds; - ItemCount actualNumBounds; - status = ATSUGetGlyphBounds(params.m_layout, 0, 0, 0, run.length(), kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds); - if (status != noErr) - LOG_ERROR("ATSUGetGlyphBounds() failed(%d)", status); - if (actualNumBounds != 1) - LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds); - - return max(FixedToFloat(firstGlyphBounds.upperRight.x), FixedToFloat(firstGlyphBounds.lowerRight.x)) - - min(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x)); -} - -int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool /*includePartialGlyphs*/) const -{ - OwnArrayPtr<UChar> charactersWithOverride; - TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); - - ATSULayoutParameters params(adjustedRun); - params.initialize(this); - - UniCharArrayOffset primaryOffset = 0; - - // FIXME: No idea how to avoid including partial glyphs. - // Not even sure if that's the behavior this yields now. - Boolean isLeading; - UniCharArrayOffset secondaryOffset = 0; - OSStatus status = ATSUPositionToOffset(params.m_layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset); - unsigned offset; - if (status == noErr) { - offset = (unsigned)primaryOffset; - if (run.directionalOverride() && offset > 0) - offset--; - } else - // Failed to find offset! Return 0 offset. - offset = 0; - - return offset; -} - -} -#endif // USE(ATSUI) diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp index 47617d8..41f63a9 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -30,18 +30,18 @@ #include "GraphicsContext3D.h" #include "CachedImage.h" -#include "CanvasActiveInfo.h" -#include "CanvasArray.h" -#include "CanvasBuffer.h" -#include "CanvasFramebuffer.h" -#include "CanvasFloatArray.h" -#include "CanvasIntArray.h" +#include "WebGLActiveInfo.h" +#include "WebGLArray.h" +#include "WebGLBuffer.h" +#include "WebGLFramebuffer.h" +#include "WebGLFloatArray.h" +#include "WebGLIntArray.h" #include "CanvasObject.h" -#include "CanvasProgram.h" -#include "CanvasRenderbuffer.h" -#include "CanvasShader.h" -#include "CanvasTexture.h" -#include "CanvasUnsignedByteArray.h" +#include "WebGLProgram.h" +#include "WebGLRenderbuffer.h" +#include "WebGLShader.h" +#include "WebGLTexture.h" +#include "WebGLUnsignedByteArray.h" #include "CString.h" #include "HTMLCanvasElement.h" #include "HTMLImageElement.h" @@ -175,21 +175,12 @@ GraphicsContext3D::~GraphicsContext3D() } } -void GraphicsContext3D::checkError() const -{ - // FIXME: This needs to only be done in the debug context. It will probably throw an exception - // on error and print the error message to the debug console - GLenum error = ::glGetError(); - if (error != GL_NO_ERROR) - notImplemented(); -} - void GraphicsContext3D::makeContextCurrent() { CGLSetCurrentContext(m_contextObj); } -void GraphicsContext3D::beginPaint(CanvasRenderingContext3D* context) +void GraphicsContext3D::beginPaint(WebGLRenderingContext* context) { UNUSED_PARAM(context); } @@ -246,43 +237,42 @@ void GraphicsContext3D::activeTexture(unsigned long texture) ::glActiveTexture(texture); } -void GraphicsContext3D::attachShader(CanvasProgram* program, CanvasShader* shader) +void GraphicsContext3D::attachShader(WebGLProgram* program, WebGLShader* shader) { - if (!program || !shader) - return; + ASSERT(program); + ASSERT(shader); ensureContext(m_contextObj); ::glAttachShader((GLuint) program->object(), (GLuint) shader->object()); } -void GraphicsContext3D::bindAttribLocation(CanvasProgram* program, unsigned long index, const String& name) +void GraphicsContext3D::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name) { - if (!program) - return; + ASSERT(program); ensureContext(m_contextObj); ::glBindAttribLocation((GLuint) program->object(), index, name.utf8().data()); } -void GraphicsContext3D::bindBuffer(unsigned long target, CanvasBuffer* buffer) +void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer) { ensureContext(m_contextObj); ::glBindBuffer(target, buffer ? (GLuint) buffer->object() : 0); } -void GraphicsContext3D::bindFramebuffer(unsigned long target, CanvasFramebuffer* buffer) +void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer) { ensureContext(m_contextObj); ::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo); } -void GraphicsContext3D::bindRenderbuffer(unsigned long target, CanvasRenderbuffer* renderbuffer) +void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer) { ensureContext(m_contextObj); - ::glBindBuffer(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); + ::glBindRenderbufferEXT(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); } -void GraphicsContext3D::bindTexture(unsigned long target, CanvasTexture* texture) +void GraphicsContext3D::bindTexture(unsigned long target, WebGLTexture* texture) { ensureContext(m_contextObj); ::glBindTexture(target, texture ? (GLuint) texture->object() : 0); @@ -324,22 +314,22 @@ void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long ensureContext(m_contextObj); ::glBufferData(target, size, 0, usage); } -void GraphicsContext3D::bufferData(unsigned long target, CanvasArray* array, unsigned long usage) +void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage) { if (!array || !array->length()) return; ensureContext(m_contextObj); - ::glBufferData(target, array->sizeInBytes(), array->baseAddress(), usage); + ::glBufferData(target, array->byteLength(), array->baseAddress(), usage); } -void GraphicsContext3D::bufferSubData(unsigned long target, long offset, CanvasArray* array) +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array) { if (!array || !array->length()) return; ensureContext(m_contextObj); - ::glBufferSubData(target, offset, array->sizeInBytes(), array->baseAddress()); + ::glBufferSubData(target, offset, array->byteLength(), array->baseAddress()); } unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target) @@ -378,11 +368,9 @@ void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha) ::glColorMask(red, green, blue, alpha); } -void GraphicsContext3D::compileShader(CanvasShader* shader) +void GraphicsContext3D::compileShader(WebGLShader* shader) { - if (!shader) - return; - + ASSERT(shader); ensureContext(m_contextObj); ::glCompileShader((GLuint) shader->object()); } @@ -423,11 +411,10 @@ void GraphicsContext3D::depthRange(double zNear, double zFar) ::glDepthRange(zNear, zFar); } -void GraphicsContext3D::detachShader(CanvasProgram* program, CanvasShader* shader) +void GraphicsContext3D::detachShader(WebGLProgram* program, WebGLShader* shader) { - if (!program || !shader) - return; - + ASSERT(program); + ASSERT(shader); ensureContext(m_contextObj); ::glDetachShader((GLuint) program->object(), (GLuint) shader->object()); } @@ -480,22 +467,16 @@ void GraphicsContext3D::flush() ::glFlush(); } -void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, CanvasRenderbuffer* buffer) +void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer) { - if (!buffer) - return; - ensureContext(m_contextObj); - ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, (GLuint) buffer->object()); + ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer ? (GLuint) buffer->object() : 0); } -void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture* texture, long level) +void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level) { - if (!texture) - return; - ensureContext(m_contextObj); - ::glFramebufferTexture2DEXT(target, attachment, textarget, (GLuint) texture->object(), level); + ::glFramebufferTexture2DEXT(target, attachment, textarget, texture ? (GLuint) texture->object() : 0, level); } void GraphicsContext3D::frontFace(unsigned long mode) @@ -510,10 +491,12 @@ void GraphicsContext3D::generateMipmap(unsigned long target) ::glGenerateMipmapEXT(target); } -bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo& info) +bool GraphicsContext3D::getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo& info) { - if (!program->object()) + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); return false; + } ensureContext(m_contextObj); GLint maxAttributeSize = 0; ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize); @@ -530,10 +513,12 @@ bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long in return true; } -bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo& info) +bool GraphicsContext3D::getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo& info) { - if (!program->object()) + if (!program->object()) { + synthesizeGLError(INVALID_VALUE); return false; + } ensureContext(m_contextObj); GLint maxUniformSize = 0; ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize); @@ -550,7 +535,7 @@ bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long i return true; } -int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name) +int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& name) { if (!program) return -1; @@ -561,6 +546,13 @@ int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& n unsigned long GraphicsContext3D::getError() { + if (m_syntheticErrors.size() > 0) { + ListHashSet<unsigned long>::iterator iter = m_syntheticErrors.begin(); + unsigned long err = *iter; + m_syntheticErrors.remove(iter); + return err; + } + ensureContext(m_contextObj); return ::glGetError(); } @@ -577,7 +569,7 @@ void GraphicsContext3D::hint(unsigned long target, unsigned long mode) ::glHint(target, mode); } -bool GraphicsContext3D::isBuffer(CanvasBuffer* buffer) +bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer) { if (!buffer) return false; @@ -592,7 +584,7 @@ bool GraphicsContext3D::isEnabled(unsigned long cap) return ::glIsEnabled(cap); } -bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer) +bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer) { if (!framebuffer) return false; @@ -601,7 +593,7 @@ bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer) return ::glIsFramebufferEXT((GLuint) framebuffer->object()); } -bool GraphicsContext3D::isProgram(CanvasProgram* program) +bool GraphicsContext3D::isProgram(WebGLProgram* program) { if (!program) return false; @@ -610,7 +602,7 @@ bool GraphicsContext3D::isProgram(CanvasProgram* program) return ::glIsProgram((GLuint) program->object()); } -bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer) +bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer) { if (!renderbuffer) return false; @@ -619,7 +611,7 @@ bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer) return ::glIsRenderbufferEXT((GLuint) renderbuffer->object()); } -bool GraphicsContext3D::isShader(CanvasShader* shader) +bool GraphicsContext3D::isShader(WebGLShader* shader) { if (!shader) return false; @@ -628,7 +620,7 @@ bool GraphicsContext3D::isShader(CanvasShader* shader) return ::glIsShader((GLuint) shader->object()); } -bool GraphicsContext3D::isTexture(CanvasTexture* texture) +bool GraphicsContext3D::isTexture(WebGLTexture* texture) { if (!texture) return false; @@ -643,11 +635,9 @@ void GraphicsContext3D::lineWidth(double width) ::glLineWidth(static_cast<float>(width)); } -void GraphicsContext3D::linkProgram(CanvasProgram* program) +void GraphicsContext3D::linkProgram(WebGLProgram* program) { - if (!program) - return; - + ASSERT(program); ensureContext(m_contextObj); ::glLinkProgram((GLuint) program->object()); } @@ -664,7 +654,7 @@ void GraphicsContext3D::polygonOffset(double factor, double units) ::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units)); } -PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) +PassRefPtr<WebGLArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) { ensureContext(m_contextObj); @@ -675,7 +665,7 @@ PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned l if (type != GL_UNSIGNED_BYTE || format != GL_RGBA) return 0; - RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(width * height * 4); + RefPtr<WebGLUnsignedByteArray> array = WebGLUnsignedByteArray::create(width * height * 4); ::glReadPixels(x, y, width, height, format, type, (GLvoid*) array->data()); return array; } @@ -705,10 +695,9 @@ void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned lo ::glScissor(x, y, width, height); } -void GraphicsContext3D::shaderSource(CanvasShader* shader, const String& string) +void GraphicsContext3D::shaderSource(WebGLShader* shader, const String& string) { - if (!shader) - return; + ASSERT(shader); ensureContext(m_contextObj); const CString& cs = string.utf8(); @@ -889,19 +878,17 @@ void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* a ::glUniformMatrix4fv(location, size, transpose, array); } -void GraphicsContext3D::useProgram(CanvasProgram* program) +void GraphicsContext3D::useProgram(WebGLProgram* program) { - if (!program) - return; + ASSERT(program); ensureContext(m_contextObj); ::glUseProgram((GLuint) program->object()); } -void GraphicsContext3D::validateProgram(CanvasProgram* program) +void GraphicsContext3D::validateProgram(WebGLProgram* program) { - if (!program) - return; + ASSERT(program); ensureContext(m_contextObj); ::glValidateProgram((GLuint) program->object()); @@ -967,567 +954,156 @@ void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned l ::glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height)); } -static int sizeForGetParam(unsigned long pname) -{ - switch(pname) { - case GL_ACTIVE_TEXTURE: return 1; - case GL_ALIASED_LINE_WIDTH_RANGE: return 2; - case GL_ALIASED_POINT_SIZE_RANGE: return 2; - case GL_ALPHA_BITS: return 1; - case GL_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) - case GL_BLEND: return 1; - case GL_BLEND_COLOR: return 4; - case GL_BLEND_DST_ALPHA: return 1; - case GL_BLEND_DST_RGB: return 1; - case GL_BLEND_EQUATION_ALPHA: return 1; - case GL_BLEND_EQUATION_RGB: return 1; - case GL_BLEND_SRC_ALPHA: return 1; - case GL_BLEND_SRC_RGB: return 1; - case GL_BLUE_BITS: return 1; - case GL_COLOR_CLEAR_VALUE: return 4; - case GL_COLOR_WRITEMASK: return 4; - case GL_COMPRESSED_TEXTURE_FORMATS: return GL_NUM_COMPRESSED_TEXTURE_FORMATS; - case GL_CULL_FACE: return 1; - case GL_CULL_FACE_MODE: return 1; - case GL_CURRENT_PROGRAM: return 1; // (* actually a CanvasProgram*) - case GL_DEPTH_BITS: return 1; - case GL_DEPTH_CLEAR_VALUE: return 1; - case GL_DEPTH_FUNC: return 1; - case GL_DEPTH_RANGE: return 2; - case GL_DEPTH_TEST: return 1; - case GL_DEPTH_WRITEMASK: return 1; - case GL_DITHER: return 1; - case GL_ELEMENT_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) - case GL_FRAMEBUFFER_BINDING_EXT: return 1; // (* actually a CanvasFramebuffer*) - case GL_FRONT_FACE: return 1; - case GL_GENERATE_MIPMAP_HINT: return 1; - case GL_GREEN_BITS: return 1; - //case GL_IMPLEMENTATION_COLOR_READ_FORMAT:return 1; - //case GL_IMPLEMENTATION_COLOR_READ_TYPE: return 1; - case GL_LINE_WIDTH: return 1; - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:return 1; - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: return 1; - //case GL_MAX_FRAGMENT_UNIFORM_VECTORS: return 1; - case GL_MAX_RENDERBUFFER_SIZE_EXT: return 1; - case GL_MAX_TEXTURE_IMAGE_UNITS: return 1; - case GL_MAX_TEXTURE_SIZE: return 1; - //case GL_MAX_VARYING_VECTORS: return 1; - case GL_MAX_VERTEX_ATTRIBS: return 1; - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: return 1; - //case GL_MAX_VERTEX_UNIFORM_VECTORS: return 1; - case GL_MAX_VIEWPORT_DIMS: return 2; - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: return 1; - //case GL_NUM_SHADER_BINARY_FORMATS: return 1; - case GL_PACK_ALIGNMENT: return 1; - case GL_POLYGON_OFFSET_FACTOR: return 1; - case GL_POLYGON_OFFSET_FILL: return 1; - case GL_POLYGON_OFFSET_UNITS: return 1; - case GL_RED_BITS: return 1; - case GL_RENDERBUFFER_BINDING_EXT: return 1; // (* actually a CanvasRenderbuffer*) - case GL_SAMPLE_BUFFERS: return 1; - case GL_SAMPLE_COVERAGE_INVERT: return 1; - case GL_SAMPLE_COVERAGE_VALUE: return 1; - case GL_SAMPLES: return 1; - case GL_SCISSOR_BOX: return 4; - case GL_SCISSOR_TEST: return 1; - //case GL_SHADER_BINARY_FORMATS: return GL_NUM_SHADER_BINARY_FORMATS; - //case GL_SHADER_COMPILER: return 1; - case GL_STENCIL_BACK_FAIL: return 1; - case GL_STENCIL_BACK_FUNC: return 1; - case GL_STENCIL_BACK_PASS_DEPTH_FAIL: return 1; - case GL_STENCIL_BACK_PASS_DEPTH_PASS: return 1; - case GL_STENCIL_BACK_REF: return 1; - case GL_STENCIL_BACK_VALUE_MASK: return 1; - case GL_STENCIL_BACK_WRITEMASK: return 1; - case GL_STENCIL_BITS: return 1; - case GL_STENCIL_CLEAR_VALUE: return 1; - case GL_STENCIL_FAIL: return 1; - case GL_STENCIL_FUNC: return 1; - case GL_STENCIL_PASS_DEPTH_FAIL: return 1; - case GL_STENCIL_PASS_DEPTH_PASS: return 1; - case GL_STENCIL_REF: return 1; - case GL_STENCIL_TEST: return 1; - case GL_STENCIL_VALUE_MASK: return 1; - case GL_STENCIL_WRITEMASK: return 1; - case GL_SUBPIXEL_BITS: return 1; - case GL_TEXTURE_BINDING_2D: return 1; // (* actually a CanvasTexture*) - case GL_TEXTURE_BINDING_CUBE_MAP: return 1; // (* actually a CanvasTexture*) - case GL_UNPACK_ALIGNMENT: return 1; - case GL_VIEWPORT: return 4; - } - - return -1; -} - -bool GraphicsContext3D::getBoolean(unsigned long pname) -{ - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - - ensureContext(m_contextObj); - - bool isAlloced = false; - GLboolean buf[4]; - GLboolean* pbuf = buf; - - if (size > 4) { - pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); - isAlloced = true; - } - - ::glGetBooleanv(pname, pbuf); - - bool value = pbuf[0]; - - if (isAlloced) - free(pbuf); - - return value; -} - -PassRefPtr<CanvasUnsignedByteArray> GraphicsContext3D::getBooleanv(unsigned long pname) -{ - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - - ensureContext(m_contextObj); - - RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(size); - bool isAlloced = false; - GLboolean buf[4]; - GLboolean* pbuf = buf; - - if (size > 4) { - pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); - isAlloced = true; - } - - ::glGetBooleanv(pname, pbuf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<unsigned char>(pbuf[i])); - - if (isAlloced) - free(pbuf); - - return array; -} - -float GraphicsContext3D::getFloat(unsigned long pname) +void GraphicsContext3D::getBooleanv(unsigned long pname, unsigned char* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - bool isAlloced = false; - GLfloat buf[4]; - GLfloat* pbuf = buf; - - if (size > 4) { - pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); - isAlloced = true; - } - - ::glGetFloatv(pname, pbuf); - - float value = pbuf[0]; - - if (isAlloced) - free(pbuf); - - return value; + ::glGetBooleanv(pname, value); } -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getFloatv(unsigned long pname) +void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname, int* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); - bool isAlloced = false; - GLfloat buf[4]; - GLfloat* pbuf = buf; - - if (size > 4) { - pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); - isAlloced = true; - } - - ::glGetFloatv(pname, pbuf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<float>(pbuf[i])); - - if (isAlloced) - free(pbuf); - - return array; + ::glGetBufferParameteriv(target, pname, value); } -int GraphicsContext3D::getInteger(unsigned long pname) +void GraphicsContext3D::getFloatv(unsigned long pname, float* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - bool isAlloced = false; - GLint buf[4]; - GLint* pbuf = buf; - - if (size > 4) { - pbuf = (GLint*) malloc(size * sizeof(GLint)); - isAlloced = true; - } - - ::glGetIntegerv(pname, pbuf); - - int value = pbuf[0]; - - if (isAlloced) - free(pbuf); - - return value; + ::glGetFloatv(pname, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getIntegerv(unsigned long pname) +void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value) { - int size = sizeForGetParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); - bool isAlloced = false; - GLint buf[4]; - GLint* pbuf = buf; - - if (size > 4) { - pbuf = (GLint*) malloc(size * sizeof(GLint)); - isAlloced = true; - } - - ::glGetIntegerv(pname, pbuf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<int>(pbuf[i])); - - if (isAlloced) - free(pbuf); - - return array; + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value); } -int GraphicsContext3D::getBufferParameteri(unsigned long target, unsigned long pname) +void GraphicsContext3D::getIntegerv(unsigned long pname, int* value) { ensureContext(m_contextObj); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - return data; + ::glGetIntegerv(pname, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getProgramiv(WebGLProgram* program, unsigned long pname, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; + ::glGetProgramiv((GLuint) program->object(), pname, value); } -int GraphicsContext3D::getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname) +String GraphicsContext3D::getProgramInfoLog(WebGLProgram* program) { - ensureContext(m_contextObj); - GLint data; - ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname) -{ - ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; -} - -int GraphicsContext3D::getProgrami(CanvasProgram* program, unsigned long pname) -{ - ensureContext(m_contextObj); - GLint data; - ::glGetProgramiv((GLuint) program->object(), pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getProgramiv(CanvasProgram* program, unsigned long pname) -{ - ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetProgramiv((GLuint) program->object(), pname, &data); - array->set(0, static_cast<int>(data)); - - return array; -} - -String GraphicsContext3D::getProgramInfoLog(CanvasProgram* program) -{ - if (!program) - return String(); + ASSERT(program); ensureContext(m_contextObj); GLint length; ::glGetProgramiv((GLuint) program->object(), GL_INFO_LOG_LENGTH, &length); GLsizei size; - GLchar* info = (GLchar*) malloc(length); + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + ::glGetProgramInfoLog((GLuint) program->object(), length, &size, info); String s(info); - free(info); + fastFree(info); return s; } -int GraphicsContext3D::getRenderbufferParameteri(unsigned long target, unsigned long pname) -{ - ensureContext(m_contextObj); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetBufferParameteriv(target, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; + ::glGetRenderbufferParameterivEXT(target, pname, value); } -int GraphicsContext3D::getShaderi(CanvasShader* shader, unsigned long pname) +void GraphicsContext3D::getShaderiv(WebGLShader* shader, unsigned long pname, int* value) { - if (!shader) - return 0; - - ensureContext(m_contextObj); - GLint data; - ::glGetShaderiv((GLuint) shader->object(), pname, &data); - return data; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getShaderiv(CanvasShader* shader, unsigned long pname) -{ - if (!shader) - return 0; + ASSERT(shader); ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetShaderiv((GLuint) shader->object(), pname, &data); - array->set(0, static_cast<int>(data)); - - return array; + ::glGetShaderiv((GLuint) shader->object(), pname, value); } -String GraphicsContext3D::getShaderInfoLog(CanvasShader* shader) +String GraphicsContext3D::getShaderInfoLog(WebGLShader* shader) { - if (!shader) - return String(); + ASSERT(shader); ensureContext(m_contextObj); GLint length; ::glGetShaderiv((GLuint) shader->object(), GL_INFO_LOG_LENGTH, &length); GLsizei size; - GLchar* info = (GLchar*) malloc(length); + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + ::glGetShaderInfoLog((GLuint) shader->object(), length, &size, info); String s(info); - free(info); + fastFree(info); return s; } -String GraphicsContext3D::getShaderSource(CanvasShader* shader) +String GraphicsContext3D::getShaderSource(WebGLShader* shader) { - if (!shader) - return String(); - + ASSERT(shader); + ensureContext(m_contextObj); GLint length; ::glGetShaderiv((GLuint) shader->object(), GL_SHADER_SOURCE_LENGTH, &length); GLsizei size; - GLchar* info = (GLchar*) malloc(length); + GLchar* info = (GLchar*) fastMalloc(length); + if (!info) + return ""; + ::glGetShaderSource((GLuint) shader->object(), length, &size, info); String s(info); - free(info); + fastFree(info); return s; } -float GraphicsContext3D::getTexParameterf(unsigned long target, unsigned long pname) +void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname, float* value) { ensureContext(m_contextObj); - GLfloat data; - ::glGetTexParameterfv(target, pname, &data); - return data; + ::glGetTexParameterfv(target, pname, value); } -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(1); - GLfloat data; - ::glGetTexParameterfv(target, pname, &data); - array->set(0, static_cast<float>(data)); - - return array; + ::glGetTexParameteriv(target, pname, value); } -int GraphicsContext3D::getTexParameteri(unsigned long target, unsigned long pname) +void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value) { ensureContext(m_contextObj); - GLint data; - ::glGetTexParameteriv(target, pname, &data); - return data; + ::glGetUniformfv((GLuint) program->object(), location, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname) +void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value) { ensureContext(m_contextObj); - RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); - GLint data; - ::glGetTexParameteriv(target, pname, &data); - array->set(0, static_cast<int>(data)); - - return array; -} - -float GraphicsContext3D::getUniformf(CanvasProgram* program, long location) -{ - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; + ::glGetUniformiv((GLuint) program->object(), location, value); } -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getUniformfv(CanvasProgram* program, long location) +long GraphicsContext3D::getUniformLocation(WebGLProgram* program, const String& name) { - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; -} - -int GraphicsContext3D::getUniformi(CanvasProgram* program, long location) -{ - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; -} - -PassRefPtr<CanvasIntArray> GraphicsContext3D::getUniformiv(CanvasProgram* program, long location) -{ - // FIXME: We need to query glGetUniformLocation to determine the size needed - UNUSED_PARAM(program); - UNUSED_PARAM(location); - notImplemented(); - return 0; -} - -long GraphicsContext3D::getUniformLocation(CanvasProgram* program, const String& name) -{ - if (!program) - return -1; + ASSERT(program); ensureContext(m_contextObj); return ::glGetUniformLocation((GLuint) program->object(), name.utf8().data()); } -static int sizeForGetVertexAttribParam(unsigned long pname) -{ - switch(pname) { - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: return 1; - case GL_VERTEX_ATTRIB_ARRAY_SIZE: return 1; - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: return 1; - case GL_VERTEX_ATTRIB_ARRAY_TYPE: return 1; - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: return 1; - case GL_CURRENT_VERTEX_ATTRIB: return 4; - } - - return -1; -} - -float GraphicsContext3D::getVertexAttribf(unsigned long index, unsigned long pname) -{ - ensureContext(m_contextObj); - GLfloat buf[4]; - ::glGetVertexAttribfv(index, pname, buf); - return buf[0]; -} - -PassRefPtr<CanvasFloatArray> GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname) -{ - int size = sizeForGetVertexAttribParam(pname); - if (size < 1) - return 0; - - ensureContext(m_contextObj); - - RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); - GLfloat buf[4]; - ::glGetVertexAttribfv(index, pname, buf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<float>(buf[i])); - - return array; -} - -int GraphicsContext3D::getVertexAttribi(unsigned long index, unsigned long pname) +void GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname, float* value) { ensureContext(m_contextObj); - GLint buf[4]; - ::glGetVertexAttribiv(index, pname, buf); - return buf[0]; + ::glGetVertexAttribfv(index, pname, value); } -PassRefPtr<CanvasIntArray> GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname) +void GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname, int* value) { - int size = sizeForGetVertexAttribParam(pname); - if (size < 1) - return 0; - ensureContext(m_contextObj); - - RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); - GLint buf[4]; - ::glGetVertexAttribiv(index, pname, buf); - - for (int i = 0; i < size; ++i) - array->set(i, static_cast<int>(buf[i])); - - return array; + ::glGetVertexAttribiv(index, pname, value); } long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long pname) @@ -1552,18 +1128,21 @@ static void imageToTexture(Image* image, unsigned target, unsigned level) size_t textureWidth = CGImageGetWidth(textureImage); size_t textureHeight = CGImageGetHeight(textureImage); - GLubyte* textureData = (GLubyte*) malloc(textureWidth * textureHeight * 4); + GLubyte* textureData = (GLubyte*) fastMalloc(textureWidth * textureHeight * 4); + if (!textureData) + return; + CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4, CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast); - + CGContextSetBlendMode(textureContext, kCGBlendModeCopy); CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)textureWidth, (CGFloat)textureHeight), textureImage); CGContextRelease(textureContext); ::glTexImage2D(target, level, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData); - free(textureData); + fastFree(textureData); } -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, CanvasArray* pixels) +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, WebGLArray* pixels) { // FIXME: Need to do bounds checking on the buffer here. ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels->baseAddress()); @@ -1585,39 +1164,15 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned inte return -1; } -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLImageElement* image, bool flipY, bool premultiplyAlpha) +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha) { // FIXME: need to support flipY and premultiplyAlpha UNUSED_PARAM(flipY); UNUSED_PARAM(premultiplyAlpha); - - if (!image) - return -1; + ASSERT(image); ensureContext(m_contextObj); - CachedImage* cachedImage = image->cachedImage(); - if (!cachedImage) - return -1; - - imageToTexture(cachedImage->image(), target, level); - return 0; -} - -int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha) -{ - // FIXME: need to support flipY and premultiplyAlpha - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); - - if (!canvas) - return -1; - - ensureContext(m_contextObj); - ImageBuffer* buffer = canvas->buffer(); - if (!buffer) - return -1; - - imageToTexture(buffer->image(), target, level); + imageToTexture(image, target, level); return 0; } @@ -1634,7 +1189,7 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElem return -1; } -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, CanvasArray* pixels) +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, WebGLArray* pixels) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size UNUSED_PARAM(target); @@ -1664,7 +1219,7 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x return -1; } -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLImageElement* image, bool flipY, bool premultiplyAlpha) +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size UNUSED_PARAM(target); @@ -1681,23 +1236,6 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x return -1; } -int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha) -{ - // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size - UNUSED_PARAM(target); - UNUSED_PARAM(level); - UNUSED_PARAM(xoff); - UNUSED_PARAM(yoff); - UNUSED_PARAM(width); - UNUSED_PARAM(height); - UNUSED_PARAM(canvas); - - // FIXME: need to support flipY and premultiplyAlpha - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); - return -1; -} - int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) { // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size @@ -1745,7 +1283,7 @@ unsigned GraphicsContext3D::createRenderbuffer() return o; } -unsigned GraphicsContext3D::createShader(ShaderType type) +unsigned GraphicsContext3D::createShader(unsigned long type) { ensureContext(m_contextObj); return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER); @@ -1817,6 +1355,11 @@ int GraphicsContext3D::sizeInBytes(int type) } } +void GraphicsContext3D::synthesizeGLError(unsigned long error) +{ + m_syntheticErrors.add(error); +} + } #endif // ENABLE(3D_CANVAS) diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index 8cf51b4..8024091 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -54,6 +54,7 @@ public: // for hosting this GraphicsLayer in a native layer hierarchy virtual NativeLayer nativeLayer() const; + virtual bool setChildren(const Vector<GraphicsLayer*>&); virtual void addChild(GraphicsLayer*); virtual void addChildAtIndex(GraphicsLayer*, int index); virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index b351956..dea6bfc 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -47,6 +47,7 @@ #import "WebLayer.h" #import "WebTiledLayer.h" #import <limits.h> +#import <objc/objc-auto.h> #import <wtf/CurrentTime.h> #import <wtf/UnusedParam.h> #import <wtf/RetainPtr.h> @@ -298,6 +299,18 @@ static void clearLayerBackgroundColor(PlatformLayer* layer) [layer setBackgroundColor:0]; } +static void safeSetSublayers(CALayer* layer, NSArray* sublayers) +{ + // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC. + if (objc_collectingEnabled() && ![sublayers count]) { + while ([[layer sublayers] count]) + [[[layer sublayers] objectAtIndex:0] removeFromSuperlayer]; + return; + } + + [layer setSublayers:sublayers]; +} + static bool caValueFunctionSupported() { static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; @@ -315,18 +328,6 @@ GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoord return CompositingCoordinatesBottomUp; } -bool GraphicsLayer::showDebugBorders() -{ - static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"]; - return showDebugBorders; -} - -bool GraphicsLayer::showRepaintCounter() -{ - static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"]; - return showRepaintCounter; -} - static NSDictionary* nullActionsDictionary() { NSNull* nullValue = [NSNull null]; @@ -352,13 +353,13 @@ PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) } GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) -: GraphicsLayer(client) -, m_contentsLayerPurpose(NoContentsLayer) -, m_contentsLayerHasBackgroundColor(false) -, m_uncommittedChanges(NoChange) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) + , m_uncommittedChanges(NoChange) #if ENABLE(3D_CANVAS) -, m_platformGraphicsContext3D(NullPlatformGraphicsContext3D) -, m_platformTexture(NullPlatform3DObject) + , m_platformGraphicsContext3D(NullPlatformGraphicsContext3D) + , m_platformTexture(NullPlatform3DObject) #endif { BEGIN_BLOCK_OBJC_EXCEPTIONS @@ -409,6 +410,15 @@ NativeLayer GraphicsLayerCA::nativeLayer() const return m_layer.get(); } +bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + if (childrenChanged) + noteLayerPropertyChanged(ChildrenChanged); + + return childrenChanged; +} + void GraphicsLayerCA::addChild(GraphicsLayer* childLayer) { GraphicsLayer::addChild(childLayer); @@ -882,17 +892,16 @@ void GraphicsLayerCA::updateSublayerList() [newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)]; if (m_transformLayer) { - [m_transformLayer.get() setSublayers:newSublayers]; + safeSetSublayers(m_transformLayer.get(), newSublayers); if (m_contentsLayer) { // If we have a transform layer, then the contents layer is parented in the // primary layer (which is itself a child of the transform layer). - [m_layer.get() setSublayers:nil]; + safeSetSublayers(m_layer.get(), nil); [m_layer.get() addSublayer:m_contentsLayer.get()]; } - } else { - [m_layer.get() setSublayers:newSublayers]; - } + } else + safeSetSublayers(m_layer.get(), newSublayers); [newSublayers release]; } @@ -1757,7 +1766,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer) } [m_layer.get() setLayerOwner:this]; - [m_layer.get() setSublayers:[oldLayer.get() sublayers]]; + safeSetSublayers(m_layer.get(), [oldLayer.get() sublayers]); [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()]; diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm index 63abe59..aee7234 100644 --- a/WebCore/platform/graphics/mac/IconMac.mm +++ b/WebCore/platform/graphics/mac/IconMac.mm @@ -39,27 +39,32 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - // 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] != '/') + if (filenames.isEmpty()) return 0; - NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filename]; - if (!image) - return 0; + bool useIconFromFirstFile; +#ifdef BUILDING_ON_TIGER + // FIXME: find a better image for multiple files to use on Tiger. + useIconFromFirstFile = true; +#else + useIconFromFirstFile = filenames.size() == 1; +#endif + if (useIconFromFirstFile) { + // 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 (filenames[0].isEmpty() || filenames[0][0U] != '/') + return 0; - return adoptRef(new Icon(image)); -} + NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filenames[0]]; + if (!image) + return 0; -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) -{ - if (filenames.isEmpty()) - return 0; + return adoptRef(new Icon(image)); + } #ifdef BUILDING_ON_TIGER - // FIXME: find a better image to use on Tiger. - return createIconForFile(filenames[0]); + return 0; #else NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments]; if (!image) diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 0a63626..7aaf95d 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -101,6 +101,9 @@ private: void setVolume(float); void setPreservesPitch(bool); + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); + void setEndTime(float time); int dataRate() const; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 30d0c82..dfb5958 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -736,8 +736,13 @@ bool MediaPlayerPrivate::hasAudio() const } bool MediaPlayerPrivate::supportsFullscreen() const -{ +{ +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) return true; +#else + // See <rdar://problem/7389945> + return false; +#endif } void MediaPlayerPrivate::setVolume(float volume) @@ -746,6 +751,27 @@ void MediaPlayerPrivate::setVolume(float volume) [m_qtMovie.get() setVolume:volume]; } +bool MediaPlayerPrivate::hasClosedCaptions() const +{ + if (!metaDataAvailable()) + return false; + return wkQTMovieHasClosedCaptions(m_qtMovie.get()); +} + +void MediaPlayerPrivate::setClosedCaptionsVisible(bool closedCaptionsVisible) +{ + if (metaDataAvailable()) { + wkQTMovieSetShowClosedCaptions(m_qtMovie.get(), closedCaptionsVisible); + +#if USE(ACCELERATED_COMPOSITING) && (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + if (closedCaptionsVisible && m_qtVideoLayer) { + // Captions will be rendered upsided down unless we flag the movie as flipped (again). See <rdar://7408440>. + [m_qtVideoLayer.get() setGeometryFlipped:YES]; + } +#endif + } +} + void MediaPlayerPrivate::setRate(float rate) { if (m_qtMovie) @@ -1158,10 +1184,10 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) TextRun textRun(text.characters(), text.length()); const Color color(255, 0, 0); context->scale(FloatSize(1.0f, -1.0f)); - context->setStrokeColor(color); + context->setStrokeColor(color, styleToUse->colorSpace()); context->setStrokeStyle(SolidStroke); context->setStrokeThickness(1.0f); - context->setFillColor(color); + context->setFillColor(color, styleToUse->colorSpace()); context->drawText(styleToUse->font(), textRun, IntPoint(2, -3)); } } diff --git a/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp new file mode 100644 index 0000000..b4cdb09 --- /dev/null +++ b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#if ENABLE(OPENTYPE_SANITIZER) +#include "OpenTypeSanitizer.h" + +#include "SharedBuffer.h" +#include "opentype-sanitiser.h" +#include "ots-memory-stream.h" +#include <wtf/OwnArrayPtr.h> + +namespace WebCore { + +PassRefPtr<SharedBuffer> OpenTypeSanitizer::sanitize() +{ + if (!m_buffer) + return 0; + + // This is the largest web font size which we'll try to transcode. + static const size_t maxWebFontSize = 30 * 1024 * 1024; // 30 MB + if (m_buffer->size() > maxWebFontSize) + return 0; + + // A transcoded font is usually smaller than an original font. + // However, it can be slightly bigger than the original one due to + // name table replacement and/or padding for glyf table. + static const size_t padLen = 20 * 1024; // 20 kB + + OwnArrayPtr<unsigned char> transcodeRawBuffer(new unsigned char[m_buffer->size() + padLen]); + ots::MemoryStream output(transcodeRawBuffer.get(), m_buffer->size() + padLen); + if (!ots::Process(&output, reinterpret_cast<const uint8_t*>(m_buffer->data()), m_buffer->size())) + return 0; + + const size_t transcodeLen = output.Tell(); + return SharedBuffer::create(transcodeRawBuffer.get(), transcodeLen); +} + +} // namespace WebCore + +#endif // ENABLE(OPENTYPE_SANITIZER) diff --git a/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h new file mode 100644 index 0000000..3f93448 --- /dev/null +++ b/WebCore/platform/graphics/opentype/OpenTypeSanitizer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OpenTypeSanitizer_h +#define OpenTypeSanitizer_h + +#if ENABLE(OPENTYPE_SANITIZER) +#include <wtf/Forward.h> + +namespace WebCore { + +class SharedBuffer; + +class OpenTypeSanitizer { +public: + explicit OpenTypeSanitizer(SharedBuffer* buffer) + : m_buffer(buffer) + { + } + + PassRefPtr<SharedBuffer> sanitize(); + +private: + SharedBuffer* const m_buffer; +}; + +} // namespace WebCore + +#endif // ENABLE(OPENTYPE_SANITIZER) +#endif // OpenTypeSanitizer_h diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index b2e3d92..3a60160 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -435,7 +435,7 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) DWORD numFonts = 0; HANDLE fontHandle = AddFontMemResourceEx(rewrittenFontData.data(), fontData->size() + nameTableSize, 0, &numFonts); - if (fontHandle && numFonts != 1) { + if (fontHandle && numFonts < 1) { RemoveFontMemResourceEx(fontHandle); return 0; } diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index 1113eae..82fb709 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -34,260 +34,39 @@ #include <wtf/ListHashSet.h> #include <wtf/StdLibExtras.h> +#include <QFont> + using namespace WTF; namespace WebCore { -FontCache* fontCache() +void FontCache::platformInit() { - DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ()); - return &globalFontCache; } -FontCache::FontCache() -{ -} - -void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&) -{ -} - -// This type must be consistent with FontPlatformData's ctor - the one which -// gets FontDescription as it's parameter. -class FontPlatformDataCacheKey { -public: - FontPlatformDataCacheKey(const FontDescription& description) - : m_familyName() - , m_size(description.computedPixelSize()) - , m_bold(false) - , m_italic(description.italic()) - , m_smallCaps(description.smallCaps()) - , m_hash(0) - { - // FIXME: Map all FontWeight values to QFont weights in FontPlatformData's ctor and follow it here - if (FontPlatformData::toQFontWeight(description.weight()) > QFont::Normal) - m_bold = true; - - const FontFamily* family = &description.family(); - while (family) { - m_familyName.append(family->family()); - family = family->next(); - if (family) - m_familyName.append(','); - } - - computeHash(); - } - - FontPlatformDataCacheKey(const FontPlatformData& fontData) - : m_familyName(static_cast<String>(fontData.family())) - , m_size(fontData.pixelSize()) - , m_bold(fontData.bold()) - , m_italic(fontData.italic()) - , m_smallCaps(fontData.smallCaps()) - , m_hash(0) - { - computeHash(); - } - - FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { } - bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); } - - enum HashTableEmptyValueType { HashTableEmptyValue }; - - FontPlatformDataCacheKey(HashTableEmptyValueType) - : m_familyName() - , m_size(0) - , m_bold(false) - , m_italic(false) - , m_smallCaps(false) - , m_hash(0) - { - } - - bool operator==(const FontPlatformDataCacheKey& other) const - { - if (m_hash != other.m_hash) - return false; - - return equalIgnoringCase(m_familyName, other.m_familyName) && m_size == other.m_size && - m_bold == other.m_bold && m_italic == other.m_italic && m_smallCaps == other.m_smallCaps; - } - - unsigned hash() const - { - return m_hash; - } - - void computeHash() - { - unsigned hashCodes[] = { - CaseFoldingHash::hash(m_familyName), - m_size | static_cast<unsigned>(m_bold << sizeof(unsigned) * 8 - 1) - | static_cast<unsigned>(m_italic) << sizeof(unsigned) *8 - 2 - | static_cast<unsigned>(m_smallCaps) << sizeof(unsigned) * 8 - 3 - }; - m_hash = StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); - } - -private: - String m_familyName; - int m_size; - bool m_bold; - bool m_italic; - bool m_smallCaps; - unsigned m_hash; - - static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; } -}; - -struct FontPlatformDataCacheKeyHash { - static unsigned hash(const FontPlatformDataCacheKey& key) - { - return key.hash(); - } - - static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b) - { - return a == b; - } - - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> { - static const bool needsDestruction = true; - static const FontPlatformDataCacheKey& emptyValue() - { - DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (FontPlatformDataCacheKey::HashTableEmptyValue)); - return key; - } - static void constructDeletedValue(FontPlatformDataCacheKey& slot) - { - new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue); - } - static bool isDeletedValue(const FontPlatformDataCacheKey& value) - { - return value.isHashTableDeletedValue(); - } -}; - -typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache; - -// using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this. -static FontPlatformDataCache* gFontPlatformDataCache = 0; - -FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString&, bool) -{ - if (!gFontPlatformDataCache) - gFontPlatformDataCache = new FontPlatformDataCache; - - FontPlatformDataCacheKey key(description); - FontPlatformData* platformData = gFontPlatformDataCache->get(key); - if (!platformData) { - platformData = new FontPlatformData(description); - gFontPlatformDataCache->add(key, platformData); - } - return platformData; -} - -typedef HashMap<FontPlatformDataCacheKey, std::pair<SimpleFontData*, unsigned>, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontDataCache; - -static FontDataCache* gFontDataCache = 0; - -static const int cMaxInactiveFontData = 40; -static const int cTargetInactiveFontData = 32; - -static ListHashSet<const SimpleFontData*>* gInactiveFontDataSet = 0; - -SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* fontPlatformData) -{ - if (!gFontDataCache) { - gFontDataCache = new FontDataCache; - gInactiveFontDataSet = new ListHashSet<const SimpleFontData*>; - } - - FontPlatformDataCacheKey key(*fontPlatformData); - FontDataCache::iterator it = gFontDataCache->find(key); - if (it == gFontDataCache->end()) { - SimpleFontData* fontData = new SimpleFontData(*fontPlatformData); - gFontDataCache->add(key, std::pair<SimpleFontData*, unsigned>(fontData, 1)); - return fontData; - } - if (!it->second.second++) { - ASSERT(gInactiveFontDataSet->contains(it->second.first)); - gInactiveFontDataSet->remove(it->second.first); - } - return it->second.first; -} - -FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&) +const SimpleFontData* FontCache::getFontDataForCharacters(const Font&, const UChar*, int) { return 0; } -void FontCache::releaseFontData(const WebCore::SimpleFontData* fontData) +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) { - ASSERT(gFontDataCache); - ASSERT(!fontData->isCustomFont()); - - FontPlatformDataCacheKey key(fontData->platformData()); - FontDataCache::iterator it = gFontDataCache->find(key); - ASSERT(it != gFontDataCache->end()); - if (!--it->second.second) { - gInactiveFontDataSet->add(it->second.first); - if (gInactiveFontDataSet->size() > cMaxInactiveFontData) - purgeInactiveFontData(gInactiveFontDataSet->size() - cTargetInactiveFontData); - } -} - -void FontCache::purgeInactiveFontData(int count) -{ - static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData. - if (isPurging) - return; - - isPurging = true; - - ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontDataSet->begin(); - ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontDataSet->end(); - for (int i = 0; i < count && it != end; ++i, ++it) { - FontPlatformDataCacheKey key = (*it)->platformData(); - pair<SimpleFontData*, unsigned> fontDataPair = gFontDataCache->take(key); - ASSERT(fontDataPair.first != 0); - ASSERT(!fontDataPair.second); - delete fontDataPair.first; - - FontPlatformData* platformData = gFontPlatformDataCache->take(key); - if (platformData) - delete platformData; - } - - if (it == end) { - // Removed everything - gInactiveFontDataSet->clear(); - } else { - for (int i = 0; i < count; ++i) - gInactiveFontDataSet->remove(gInactiveFontDataSet->begin()); - } - - isPurging = false; + return 0; } -void FontCache::addClient(FontSelector*) +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) { + const AtomicString fallbackFamily = QFont(fontDescription.family().family()).lastResortFont(); + return new FontPlatformData(fontDescription, fallbackFamily); } -void FontCache::removeClient(FontSelector*) +void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&) { } -void FontCache::invalidate() +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) { - if (!gFontPlatformDataCache || !gFontDataCache) - return; - - purgeInactiveFontData(); + return new FontPlatformData(fontDescription, familyName); } } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp index a19464e..6e9d053 100644 --- a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp @@ -43,7 +43,7 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b font.setWeight(QFont::Bold); font.setItalic(italic); - return FontPlatformData(font, bold); + return FontPlatformData(font); } FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp deleted file mode 100644 index 8e1e4f6..0000000 --- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright (C) 2008 Holger Hans Peter Freyther - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - Replacement of the stock FontFallbackList as Qt is going to find us a - replacement font, will do caching and the other stuff we implement in - WebKit. -*/ - -#include "config.h" -#include "FontFallbackList.h" - -#include "Font.h" -#include "FontCache.h" -#include "SegmentedFontData.h" - -#include <QDebug> - -namespace WebCore { - -FontFallbackList::FontFallbackList() - : m_pageZero(0) - , m_cachedPrimarySimpleFontData(0) - , m_fontSelector(0) - , m_familyIndex(0) - , m_pitch(UnknownPitch) - , m_loadingCustomFonts(false) - , m_generation(0) -{ -} - -void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector) -{ - releaseFontData(); - m_fontList.clear(); - m_pageZero = 0; - m_pages.clear(); - m_cachedPrimarySimpleFontData = 0; - m_familyIndex = 0; - m_pitch = UnknownPitch; - m_loadingCustomFonts = false; - m_fontSelector = fontSelector; - m_generation = 0; -} - -void FontFallbackList::releaseFontData() -{ - unsigned numFonts = m_fontList.size(); - for (unsigned i = 0; i < numFonts; ++i) { - if (m_fontList[i].second) - delete m_fontList[i].first; - else { - ASSERT(!m_fontList[i].first->isSegmented()); - fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first)); - } - } -} - -void FontFallbackList::determinePitch(const WebCore::Font* font) const -{ - const FontData* fontData = primaryFontData(font); - if (!fontData->isSegmented()) - m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch(); - else { - const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); - unsigned numRanges = segmentedFontData->numRanges(); - if (numRanges == 1) - m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch(); - else - m_pitch = VariablePitch; - } -} - -const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigned index) const -{ - if (index != 0) - return 0; - - // Search for the WebCore font that is already in the list - for (int i = m_fontList.size() - 1; i >= 0; --i) { - pair<const FontData*, bool> item = m_fontList[i]; - // item.second means that the item was created locally or not - if (!item.second) - return item.first; - } - - // Use the FontSelector to get a WebCore font and then fallback to Qt - const FontDescription& description = _font->fontDescription(); - const FontFamily* family = &description.family(); - while (family) { - if (m_fontSelector) { - FontData* data = m_fontSelector->getFontData(description, family->family()); - if (data) { - if (data->isLoading()) - m_loadingCustomFonts = true; - if (!data->isCustomFont()) { - // Custom fonts can be freed anytime so we must not hold them - m_fontList.append(pair<const FontData*, bool>(data, false)); - } - return data; - } - } - family = family->next(); - } - - if (m_fontList.size()) - return m_fontList[0].first; - - const FontData* result = new SimpleFontData(FontPlatformData(description, _font->wordSpacing(), _font->letterSpacing()), true); - m_fontList.append(pair<const FontData*, bool>(result, true)); - return result; -} - -const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const -{ - return primaryFontData(font); -} - -void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData&) -{ - m_familyIndex = cAllFamiliesScanned; -} - -} diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h index 92219fd..4a3f8bc 100644 --- a/WebCore/platform/graphics/qt/FontPlatformData.h +++ b/WebCore/platform/graphics/qt/FontPlatformData.h @@ -26,20 +26,62 @@ #include "FontDescription.h" #include <QFont> +#include <QHash> namespace WebCore { class String; +class FontPlatformDataPrivate { +public: + FontPlatformDataPrivate() + : refCount(1) + , size(font.pointSizeF()) + , bold(font.bold()) + , oblique(false) + {} + FontPlatformDataPrivate(const float size, const bool bold, const bool oblique) + : refCount(1) + , size(size) + , bold(bold) + , oblique(oblique) + {} + FontPlatformDataPrivate(const QFont& font) + : refCount(1) + , font(font) + , size(font.pointSizeF()) + , bold(font.bold()) + , oblique(false) + {} + unsigned refCount; + QFont font; + float size; + bool bold : 1; + bool oblique : 1; +}; + + -class FontPlatformData -{ +class FontPlatformData : public FastAllocBase { public: -#if ENABLE(SVG_FONTS) FontPlatformData(float size, bool bold, bool oblique); -#endif - FontPlatformData(); - FontPlatformData(const FontDescription&, int wordSpacing = 0, int letterSpacing = 0); - FontPlatformData(const QFont&, bool bold); + FontPlatformData(const FontPlatformData &); + FontPlatformData(const FontDescription&, const AtomicString& familyName, int wordSpacing = 0, int letterSpacing = 0); + FontPlatformData(const QFont& font) + : m_data(new FontPlatformDataPrivate(font)) + {} + FontPlatformData(WTF::HashTableDeletedValueType) + : m_data(reinterpret_cast<FontPlatformDataPrivate*>(-1)) + {} + + ~FontPlatformData(); + + FontPlatformData& operator=(const FontPlatformData&); + bool operator==(const FontPlatformData&) const; + + bool isHashTableDeletedValue() const + { + return m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1); + } static inline QFont::Weight toQFontWeight(FontWeight fontWeight) { @@ -62,22 +104,62 @@ public: } } - QFont font() const { return m_font; } - float size() const { return m_size; } - QString family() const { return m_font.family(); } - bool bold() const { return m_bold; } - bool italic() const { return m_font.italic(); } - bool smallCaps() const { return m_font.capitalization() == QFont::SmallCaps; } - int pixelSize() const { return m_font.pixelSize(); } + QFont font() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font; + return QFont(); + } + float size() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->size; + return 0.0f; + } + QString family() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.family(); + return QString(); + } + bool bold() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->bold; + return false; + } + bool italic() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.italic(); + return false; + } + bool smallCaps() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.capitalization() == QFont::SmallCaps; + return false; + } + int pixelSize() const + { + Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)); + if (m_data) + return m_data->font.pixelSize(); + return 0; + } + unsigned hash() const; #ifndef NDEBUG String description() const; #endif - - float m_size; - bool m_bold; - bool m_oblique; - QFont m_font; +private: + FontPlatformDataPrivate* m_data; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp index 7709be6..2cc2fc6 100644 --- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp +++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -26,56 +26,104 @@ namespace WebCore { -FontPlatformData::FontPlatformData(const FontDescription& description, int wordSpacing, int letterSpacing) - : m_size(0.0f) - , m_bold(false) - , m_oblique(false) +static inline bool isEmtpyValue(const float size, const bool bold, const bool oblique) { - QString familyName; + // this is the empty value by definition of the trait FontDataCacheKeyTraits + return !bold && !oblique && size == 0.f; +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) +{ + if (isEmtpyValue(size, bold, oblique)) + m_data = 0; + else + m_data = new FontPlatformDataPrivate(size, bold, oblique); +} + +FontPlatformData::FontPlatformData(const FontPlatformData &other) : m_data(other.m_data) +{ + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) + ++m_data->refCount; +} + +FontPlatformData::FontPlatformData(const FontDescription& description, const AtomicString& familyName, int wordSpacing, int letterSpacing) + : m_data(new FontPlatformDataPrivate()) +{ + QString familyNames(familyName); + if (!familyName.isEmpty()) + familyNames += QLatin1Char(','); + const FontFamily* family = &description.family(); while (family) { - familyName += family->family(); + familyNames += family->family(); family = family->next(); if (family) - familyName += QLatin1Char(','); + familyNames += QLatin1Char(','); } + QFont& font = m_data->font; + font.setFamily(familyName); + font.setPixelSize(qRound(description.computedSize())); + font.setItalic(description.italic()); + font.setWeight(toQFontWeight(description.weight())); + font.setWordSpacing(wordSpacing); + font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); + const bool smallCaps = description.smallCaps(); + font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); + + m_data->bold = font.bold(); + m_data->size = font.pointSizeF(); +} - m_font.setFamily(familyName); - m_font.setPixelSize(qRound(description.computedSize())); - m_font.setItalic(description.italic()); - - m_font.setWeight(toQFontWeight(description.weight())); - m_bold = m_font.bold(); - - bool smallCaps = description.smallCaps(); - m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); - m_font.setWordSpacing(wordSpacing); - m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); - m_size = m_font.pointSize(); +FontPlatformData::~FontPlatformData() +{ + if (!m_data || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return; + --m_data->refCount; + if (!m_data->refCount) + delete m_data; } -FontPlatformData::FontPlatformData(const QFont& font, bool bold) - : m_size(font.pointSize()) - , m_bold(bold) - , m_oblique(false) - , m_font(font) +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) { + if (m_data == other.m_data) + return *this; + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) { + --m_data->refCount; + if (!m_data->refCount) + delete m_data; + } + m_data = other.m_data; + if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) + ++m_data->refCount; + return *this; } -#if ENABLE(SVG_FONTS) -FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) - : m_size(size) - , m_bold(bold) - , m_oblique(oblique) +bool FontPlatformData::operator==(const FontPlatformData& other) const { + if (m_data == other.m_data) + return true; + + if (!m_data || !other.m_data + || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1) || other.m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return false; + + const bool equals = (m_data->size == other.m_data->size + && m_data->bold == other.m_data->bold + && m_data->oblique == other.m_data->oblique + && m_data->font == other.m_data->font); + return equals; } -#endif -FontPlatformData::FontPlatformData() - : m_size(0.0f) - , m_bold(false) - , m_oblique(false) +unsigned FontPlatformData::hash() const { + if (!m_data) + return 0; + if (m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1)) + return 1; + return qHash(m_data->font.toString()) + ^ qHash(*reinterpret_cast<quint32*>(&m_data->size)) + ^ qHash(m_data->bold) + ^ qHash(m_data->oblique); } #ifndef NDEBUG diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index c5960ac..1e44626 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -42,7 +42,6 @@ #include <limits.h> -#if QT_VERSION >= 0x040400 namespace WebCore { static const QString qstring(const TextRun& run) @@ -229,5 +228,3 @@ QFont Font::font() const } -#endif - diff --git a/WebCore/platform/graphics/qt/FontQt43.cpp b/WebCore/platform/graphics/qt/FontQt43.cpp deleted file mode 100644 index 45bf05d..0000000 --- a/WebCore/platform/graphics/qt/FontQt43.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* - Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2008 Holger Hans Peter Freyther - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" -#include "Font.h" -#include "FontDescription.h" -#include "FontFallbackList.h" -#include "FontSelector.h" - -#include "GraphicsContext.h" -#include <QTextLayout> -#include <QPainter> -#include <QFontMetrics> -#include <QFontInfo> -#include <qalgorithms.h> -#include <qdebug.h> - -#include <limits.h> - -#if QT_VERSION < 0x040400 - -namespace WebCore { - -struct TextRunComponent { - TextRunComponent() : font(0) {} - TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false); - TextRunComponent(int spaces, bool rtl, const QFont *font, int offset); - - inline bool isSpace() const { return spaces != 0; } - - QString string; - const QFont *font; - int width; - int offset; - int spaces; -}; - -TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc) - : string(reinterpret_cast<const QChar*>(start), length) - , font(f) - , offset(o) - , spaces(0) -{ - if (sc) - string = string.toUpper(); - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = QFontMetrics(*font).width(string); -} - -TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o) - : string(s, QLatin1Char(' ')) - , font(f) - , offset(o) - , spaces(s) -{ - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = spaces * QFontMetrics(*font).width(QLatin1Char(' ')); -} - - -static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run) -{ -// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length()); - int letterSpacing = font.letterSpacing(); - int wordSpacing = font.wordSpacing(); - bool smallCaps = font.fontDescription().smallCaps(); - int padding = run.padding(); - int numSpaces = 0; - if (padding) { - for (int i = 0; i < run.length(); i++) - if (Font::treatAsSpace(run[i])) - ++numSpaces; - } - - int offset = 0; - const QFont *f = &font.font(); - if (letterSpacing || smallCaps) { - // need to draw every letter on it's own - int start = 0; - if (Font::treatAsSpace(run[0])) { - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + letterSpacing + components->last().width; - start = 1; -// qDebug() << "space at 0" << offset; - } else if (smallCaps) - f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - - for (int i = 1; i < run.length(); ++i) { - uint ch = run[i]; - if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate()) - ch = QChar::surrogateToUcs4(ch, run[i-1]); - if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing) - continue; - if (Font::treatAsSpace(run[i])) { - int add = 0; -// qDebug() << " treatAsSpace:" << i << start; - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(1) " << components->last().string << components->last().width; - } - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += wordSpacing + add + components->last().width + letterSpacing; - start = i + 1; - continue; - } else if (!letterSpacing) { -// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) << -// QFontInfo(*f).pointSizeF(); - if (QChar::category(ch) == QChar::Letter_Lowercase) { - if (f == &font.scFont()) - continue; - } else { - if (f == &font.font()) - continue; - } - } - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(2) " << components->last().string << components->last().width; - } - if (smallCaps) - f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - start = i; - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width; -// qDebug() << " appending(3) " << components->last().string << components->last().width; - } - offset += letterSpacing; - } else { - int start = 0; - for (int i = 0; i < run.length(); ++i) { - if (Font::treatAsSpace(run[i])) { - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + components->last().width; - if (i) - offset += wordSpacing; - start = i + 1; - } - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - } - return offset; -} - -void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - if (to < 0) - to = run.length(); - - QPainter *p = ctx->platformContext(); - Color color = ctx->fillColor(); - p->setPen(QColor(color)); - - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from > 0 || to < run.length()) { - FloatRect clip = selectionRectForComplexText(run, - IntPoint(qRound(point.x()), qRound(point.y())), - QFontMetrics(font()).height(), from, to); - QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height()); - p->save(); - p->setClipRect(rect.toRect()); - } - - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } else { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + components.at(i).offset, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } - if (from > 0 || to < run.length()) - p->restore(); -} - -float Font::floatWidthForComplexText(const TextRun& run) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - return w; -} - -int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - int offset = 0; - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - int xe = w - components.at(i).offset; - int xs = xe - components.at(i).width; - if (position >= xs) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else - offset += components.at(i).string.length() - 1; - } - } else { - for (int i = 0; i < components.size(); ++i) { - int xs = components.at(i).offset; - int xe = xs + components.at(i).width; - if (position <= xe) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset + components.at(i).string.length() - 1; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else - offset += components.at(i).string.length() - 1; - } - } - return run.length(); -} - -static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor) -{ - int start = 0; - for (int i = 0; i < components.size(); ++i) { - if (start + components.at(i).string.length() - 1 < cursor) { - start += components.at(i).string.length() - 1; - continue; - } - int xs = components.at(i).offset; - if (rtl) - xs = width - xs - components.at(i).width; - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return 0; - - l.setLineWidth(INT_MAX / 256); - layout.endLayout(); - - return xs + l.cursorToX(cursor - start + 1); - } - return width; -} - -FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, - int h, int from, int to) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from == 0 && to == run.length()) - return FloatRect(pt.x(), pt.y(), w, h); - - float x1 = cursorToX(components, w, run.rtl(), from); - float x2 = cursorToX(components, w, run.rtl(), to); - if (x2 < x1) - qSwap(x1, x2); - - return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); -} - -int Font::lineGap() const -{ - return QFontMetrics(m_font).leading(); -} - -} - -#endif diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 57a481a..a095476 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -256,8 +256,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } } @@ -639,24 +639,18 @@ void GraphicsContext::fillPath() QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - if ((m_common->state.fillColorSpace != SolidColorSpace) - || (fillColor().alpha())) { + if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) { drawFilledShadowPath(this, p, &path); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillPath(path, p->brush()); - break; - case PatternColorSpace: { + if (m_common->state.fillPattern) { TransformationMatrix affine; p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: + } else if (m_common->state.fillGradient) { QBrush brush(*m_common->state.fillGradient->platformGradient()); brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); p->fillPath(path, brush); - break; + } else { + if (fillColor().alpha()) + p->fillPath(path, p->brush()); } } m_data->currentPath = QPainterPath(); @@ -672,8 +666,7 @@ void GraphicsContext::strokePath() QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - if ((m_common->state.strokeColorSpace != SolidColorSpace) - || (strokeColor().alpha())) { + if (m_common->state.strokePattern || m_common->state.strokeGradient || strokeColor().alpha()) { IntSize shadowSize; int shadowBlur; Color shadowColor; @@ -685,26 +678,20 @@ void GraphicsContext::strokePath() p->strokePath(path, shadowPen); p->setWorldTransform(t); } - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - if (strokeColor().alpha()) - p->strokePath(path, pen); - break; - case PatternColorSpace: { + if (m_common->state.strokePattern) { TransformationMatrix affine; pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); p->setPen(pen); p->strokePath(path, pen); - break; - } - case GradientColorSpace: { + } else if (m_common->state.strokeGradient) { QBrush brush(*m_common->state.strokeGradient->platformGradient()); brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform()); pen.setBrush(brush); p->setPen(pen); p->strokePath(path, pen); - break; - } + } else { + if (strokeColor().alpha()) + p->strokePath(path, pen); } } m_data->currentPath = QPainterPath(); @@ -729,29 +716,23 @@ void GraphicsContext::fillRect(const FloatRect& rect) QPainter* p = m_data->p(); - if ((m_common->state.fillColorSpace != SolidColorSpace) - || (fillColor().alpha())) { + if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) { drawBorderlessRectShadow(this, p, rect); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillRect(rect, p->brush()); - break; - case PatternColorSpace: { + if (m_common->state.fillPattern) { TransformationMatrix affine; p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: + } else if (m_common->state.fillGradient) { QBrush brush(*m_common->state.fillGradient->platformGradient()); brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); p->fillRect(rect, brush); - break; + } else { + if (fillColor().alpha()) + p->fillRect(rect, p->brush()); } } } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -762,7 +743,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) p->fillRect(rect, m_data->solidColor); } -void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !color.alpha()) return; @@ -886,7 +867,7 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) return FloatRect(QRectF(result)); } -void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&) +void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&, ColorSpace) { // Qt doesn't support shadows natively, they are drawn manually in the draw* // functions @@ -1225,7 +1206,7 @@ void GraphicsContext::setURLForRect(const KURL&, const IntRect&) notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1255,7 +1236,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) p->setPen(newPen); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp index 98f4606..a9870fc 100644 --- a/WebCore/platform/graphics/qt/IconQt.cpp +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -40,15 +40,17 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - RefPtr<Icon> i = adoptRef(new Icon); - i->m_icon = QIcon(filename); - return i.release(); -} + if (filenames.isEmpty()) + return 0; + + if (filenames.size() == 1) { + RefPtr<Icon> i = adoptRef(new Icon); + i->m_icon = QIcon(filenames[0]); + return i.release(); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) -{ //FIXME: Implement this return 0; } diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index f8403b7..b6823dd 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -145,16 +145,8 @@ RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) return &frame; } -void ImageDecoderQt::clearFrameBufferCache(size_t index) +void ImageDecoderQt::clearFrameBufferCache(size_t /*index*/) { - // Currently QImageReader will be asked to read everything. This - // might change when we read gif images on demand. For now we - // can have a rather simple implementation. - if (index > m_frameBufferCache.size()) - return; - - for (size_t i = 0; i < index; ++index) - m_frameBufferCache[index].clear(); } void ImageDecoderQt::internalDecodeSize() diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index da6ddac..9a82911 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -44,9 +44,7 @@ #include <QPainter> #include <QImage> #include <QImageReader> -#if QT_VERSION >= 0x040300 #include <QTransform> -#endif #include <QDebug> @@ -64,6 +62,8 @@ static QPixmap loadResourcePixmap(const char *name) pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic); else if (qstrcmp(name, "textAreaResizeCorner") == 0) pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic); + else if (qstrcmp(name, "deleteButton") == 0) + pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic); return pixmap; } @@ -94,7 +94,7 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) } void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, - const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) { QPixmap* framePixmap = nativeImageForCurrentFrame(); if (!framePixmap) // If it's too early we won't have an image yet. @@ -120,6 +120,38 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const imageObserver()->didDraw(this); } +BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer) + : Image(observer) + , m_currentFrame(0) + , m_frames(0) + , m_frameTimer(0) + , m_repetitionCount(cAnimationNone) + , m_repetitionCountStatus(Unknown) + , m_repetitionsComplete(0) + , m_isSolidColor(false) + , m_checkedForSolidColor(false) + , m_animationFinished(true) + , m_allDataReceived(true) + , m_haveSize(true) + , m_sizeAvailable(true) + , m_decodedSize(0) + , m_haveFrameCount(true) + , m_frameCount(1) +{ + initPlatformData(); + + int width = pixmap->width(); + int height = pixmap->height(); + m_decodedSize = width * height * 4; + m_size = IntSize(width, height); + + m_frames.grow(1); + m_frames[0].m_frame = pixmap; + m_frames[0].m_hasAlpha = pixmap->hasAlpha(); + m_frames[0].m_haveMetadata = true; + checkForSolidColor(); +} + void BitmapImage::initPlatformData() { } @@ -130,7 +162,7 @@ void BitmapImage::invalidatePlatformData() // Drawing Routines void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, - const FloatRect& src, CompositeOperator op) + const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { startAnimation(); @@ -139,7 +171,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -181,6 +213,13 @@ void BitmapImage::checkForSolidColor() m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0)); } +#if PLATFORM(WIN_OS) +PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) +{ + return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap))); +} +#endif + } diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 7078d16..f446755 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -101,15 +101,15 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget)) widget->installEventFilter(this); - connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), - this, SLOT(stateChanged(Phonon::State, Phonon::State))); + connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), + this, SLOT(stateChanged(Phonon::State,Phonon::State))); connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool))); connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool))); connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int))); connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished())); - connect(m_mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), - this, SLOT(currentSourceChanged(const Phonon::MediaSource&))); + connect(m_mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)), + this, SLOT(currentSourceChanged(Phonon::MediaSource))); connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64))); } diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp index 95b3bc8..1db04a7 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.cpp +++ b/WebCore/platform/graphics/qt/StillImageQt.cpp @@ -50,7 +50,7 @@ NativeImagePtr StillImage::nativeImageForCurrentFrame() } void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst, - const FloatRect& src, CompositeOperator op) + const FloatRect& src, ColorSpace, CompositeOperator op) { if (m_pixmap.isNull()) return; diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h index 6c417b1..7be9136 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.h +++ b/WebCore/platform/graphics/qt/StillImageQt.h @@ -46,7 +46,7 @@ namespace WebCore { virtual IntSize size() const; virtual NativeImagePtr nativeImageForCurrentFrame(); - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); private: StillImage(const QPixmap& pixmap); diff --git a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h index 5d85652..9fb6a8b 100644 --- a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h +++ b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h @@ -72,7 +72,7 @@ public: } protected: - virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator); private: NativeImageSkia m_nativeImage; diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index 889c41b..f1536a6 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -293,7 +293,10 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness path.addOval(r, SkPath::kCW_Direction); // only perform the inset if we won't invert r if (2 * thickness < rect.width() && 2 * thickness < rect.height()) { - r.inset(SkIntToScalar(thickness), SkIntToScalar(thickness)); + // Adding one to the thickness doesn't make the border too thick as + // it's painted over afterwards. But without this adjustment the + // border appears a little anemic after anti-aliasing. + r.inset(SkIntToScalar(thickness + 1), SkIntToScalar(thickness + 1)); path.addOval(r, SkPath::kCCW_Direction); } platformContext()->clipPathAntiAliased(path); @@ -704,8 +707,6 @@ void GraphicsContext::fillPath() return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.fillColorSpace; - path.setFillType(state.fillRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); @@ -727,14 +728,13 @@ void GraphicsContext::fillRect(const FloatRect& rect) } const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.fillColorSpace; SkPaint paint; platformContext()->setupPaintForFilling(&paint); platformContext()->canvas()->drawRect(r, paint); } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -765,7 +765,8 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, - const Color& color) + const Color& color, + ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -782,7 +783,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, // Not all the radii fit, return a rect. This matches the behavior of // Path::createRoundedRectangle. Without this we attempt to draw a round // shadow for a square box. - fillRect(rect, color); + fillRect(rect, color, colorSpace); return; } @@ -950,7 +951,7 @@ void GraphicsContext::setMiterLimit(float limit) platformContext()->setMiterLimit(limit); } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -977,7 +978,8 @@ void GraphicsContext::setPlatformFillPattern(Pattern* pattern) void GraphicsContext::setPlatformShadow(const IntSize& size, int blurInt, - const Color& color) + const Color& color, + ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1019,7 +1021,7 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, dl->unref(); } -void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor) +void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -1118,7 +1120,6 @@ void GraphicsContext::strokePath() return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); @@ -1135,7 +1136,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) return; const GraphicsContextState& state = m_common->state; - ColorSpace colorSpace = state.strokeColorSpace; SkPaint paint; platformContext()->setupPaintForStroking(&paint, 0, 0); diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index a5c8926..c36f1ce 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -105,13 +105,16 @@ Image* ImageBuffer::image() const void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) { const SkBitmap& bitmap = *context()->platformContext()->bitmap(); + if (bitmap.isNull()) + return; + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); for (int y = 0; y < m_size.height(); ++y) { uint32_t* srcRow = bitmap.getAddr32(0, y); for (int x = 0; x < m_size.width(); ++x) { SkColor color = SkPMColorToColor(srcRow[x]); - srcRow[x] = SkPreMultiplyARGB(lookUpTable[SkColorGetA(color)], + srcRow[x] = SkPreMultiplyARGB(SkColorGetA(color), lookUpTable[SkColorGetR(color)], lookUpTable[SkColorGetG(color)], lookUpTable[SkColorGetB(color)]); @@ -164,11 +167,12 @@ PassRefPtr<ImageData> getImageData(const IntRect& rect, const SkBitmap& bitmap, for (int x = 0; x < numColumns; ++x) { unsigned char* destPixel = &destRow[x * 4]; if (multiplied == Unmultiplied) { - SkColor color = SkPMColorToColor(srcRow[x]); - destPixel[0] = SkColorGetR(color); - destPixel[1] = SkColorGetG(color); - destPixel[2] = SkColorGetB(color); - destPixel[3] = SkColorGetA(color); + SkColor color = srcRow[x]; + unsigned a = SkColorGetA(color); + destPixel[0] = a ? SkColorGetR(color) * 255 / a : 0; + destPixel[1] = a ? SkColorGetG(color) * 255 / a : 0; + destPixel[2] = a ? SkColorGetB(color) * 255 / a : 0; + destPixel[3] = a; } else { // Input and output are both pre-multiplied, we just need to re-arrange the // bytes from the bitmap format to RGBA. diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index ecab364..6d8ed22 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -302,6 +302,7 @@ void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, + ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect) { @@ -405,7 +406,7 @@ void BitmapImage::checkForSolidColor() } void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, - const FloatRect& srcRect, CompositeOperator compositeOp) + const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp) { if (!m_source.initialized()) return; @@ -437,6 +438,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, + ColorSpace styleColorSpace, CompositeOperator compositeOp) { FloatRect normDstRect = normalizeRect(dstRect); diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index a079da0..dfffa0d 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -343,6 +343,15 @@ void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const paint->setShader(m_state->m_fillShader); } +static SkScalar scalarBound(SkScalar v, SkScalar min, SkScalar max) +{ + if (v < min) + return min; + if (v > max) + return max; + return v; +} + float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const { setupPaintCommon(paint); @@ -351,10 +360,13 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i paint->setColor(m_state->applyAlpha(m_state->m_strokeColor)); paint->setShader(m_state->m_strokeShader); paint->setStyle(SkPaint::kStroke_Style); - paint->setStrokeWidth(SkFloatToScalar(width)); + // The limits here (512 and 256) were made up but are hopefully large + // enough to be reasonable. They are, empirically, small enough not to + // cause overflows in Skia. + paint->setStrokeWidth(scalarBound(SkFloatToScalar(width), 0, 512)); paint->setStrokeCap(m_state->m_lineCap); paint->setStrokeJoin(m_state->m_lineJoin); - paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit)); + paint->setStrokeMiter(scalarBound(SkFloatToScalar(m_state->m_miterLimit), 0, 256)); if (m_state->m_dash) paint->setPathEffect(m_state->m_dash); diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h index dd56408..08efd23 100644 --- a/WebCore/platform/graphics/transforms/TransformOperations.h +++ b/WebCore/platform/graphics/transforms/TransformOperations.h @@ -31,7 +31,7 @@ namespace WebCore { -class TransformOperations { +class TransformOperations : public FastAllocBase { public: TransformOperations(bool makeIdentity = false); diff --git a/WebCore/platform/graphics/transforms/TransformationMatrix.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h index a7fbb3d..33f9afe 100644 --- a/WebCore/platform/graphics/transforms/TransformationMatrix.h +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -29,6 +29,7 @@ #include "FloatPoint.h" #include "IntPoint.h" #include <string.h> //for memcpy +#include <wtf/FastAllocBase.h> #if PLATFORM(CG) #include <CoreGraphics/CGAffineTransform.h> @@ -49,7 +50,7 @@ class FloatPoint3D; class FloatRect; class FloatQuad; -class TransformationMatrix { +class TransformationMatrix : public FastAllocBase { public: typedef double Matrix4[4][4]; diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index e2ed130..e901669 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -362,14 +362,14 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo graphicsContext->clearShadow(); Color fillColor = graphicsContext->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - graphicsContext->setFillColor(shadowFillColor); + graphicsContext->setFillColor(shadowFillColor, DeviceColorSpace); CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } - graphicsContext->setFillColor(fillColor); + graphicsContext->setFillColor(fillColor, DeviceColorSpace); } CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); @@ -380,7 +380,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo } if (hasSimpleShadow) - graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); + graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor, DeviceColorSpace); wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); } diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 1923ecc..137b914 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -70,8 +70,8 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha) setPaintingDisabled(!m_data->m_cgContext); if (m_data->m_cgContext) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } } diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 2489e02..61ae76c 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -74,8 +74,8 @@ GraphicsContext::GraphicsContext(HDC dc, bool hasAlpha) if (m_data->cr) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), fillColorSpace()); + setPlatformStrokeColor(strokeColor(), strokeColorSpace()); } } diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp new file mode 100644 index 0000000..22faeb8 --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp @@ -0,0 +1,721 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR 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 USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayerCACF.h" + +#include "CString.h" +#include "FloatConversion.h" +#include "FloatRect.h" +#include "Image.h" +#include "PlatformString.h" +#include "SystemTime.h" +#include "WKCACFLayer.h" +#include <wtf/CurrentTime.h> +#include <wtf/StringExtras.h> + +using namespace std; + +namespace WebCore { + +static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t) +{ + toT3D.m11 = narrowPrecisionToFloat(t.m11()); + toT3D.m12 = narrowPrecisionToFloat(t.m12()); + toT3D.m13 = narrowPrecisionToFloat(t.m13()); + toT3D.m14 = narrowPrecisionToFloat(t.m14()); + toT3D.m21 = narrowPrecisionToFloat(t.m21()); + toT3D.m22 = narrowPrecisionToFloat(t.m22()); + toT3D.m23 = narrowPrecisionToFloat(t.m23()); + toT3D.m24 = narrowPrecisionToFloat(t.m24()); + toT3D.m31 = narrowPrecisionToFloat(t.m31()); + toT3D.m32 = narrowPrecisionToFloat(t.m32()); + toT3D.m33 = narrowPrecisionToFloat(t.m33()); + toT3D.m34 = narrowPrecisionToFloat(t.m34()); + toT3D.m41 = narrowPrecisionToFloat(t.m41()); + toT3D.m42 = narrowPrecisionToFloat(t.m42()); + toT3D.m43 = narrowPrecisionToFloat(t.m43()); + toT3D.m44 = narrowPrecisionToFloat(t.m44()); +} + +TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D) +{ + return TransformationMatrix( + fromT3D.m11, + fromT3D.m12, + fromT3D.m13, + fromT3D.m14, + fromT3D.m21, + fromT3D.m22, + fromT3D.m23, + fromT3D.m24, + fromT3D.m31, + fromT3D.m32, + fromT3D.m33, + fromT3D.m34, + fromT3D.m41, + fromT3D.m42, + fromT3D.m43, + fromT3D.m44); +} + +static void setLayerBorderColor(WKCACFLayer* layer, const Color& color) +{ + CGColorRef borderColor = createCGColor(color); + layer->setBorderColor(borderColor); + CGColorRelease(borderColor); +} + +static void clearBorderColor(WKCACFLayer* layer) +{ + layer->setBorderColor(0); +} + +static void setLayerBackgroundColor(WKCACFLayer* layer, const Color& color) +{ + CGColorRef bgColor = createCGColor(color); + layer->setBackgroundColor(bgColor); + CGColorRelease(bgColor); +} + +static void clearLayerBackgroundColor(WKCACFLayer* layer) +{ + layer->setBackgroundColor(0); +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoordinatesOrientation() +{ + return CompositingCoordinatesBottomUp; +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerCACF(client); +} + +GraphicsLayerCACF::GraphicsLayerCACF(GraphicsLayerClient* client) + : GraphicsLayer(client) + , m_contentsLayerPurpose(NoContentsLayer) + , m_contentsLayerHasBackgroundColor(false) +{ + m_layer = WKCACFLayer::create(kCACFLayer, this); + + updateDebugIndicators(); +} + +GraphicsLayerCACF::~GraphicsLayerCACF() +{ + // clean up the WK layer + if (m_layer) + m_layer->removeFromSuperlayer(); + + if (m_transformLayer) + m_transformLayer->removeFromSuperlayer(); +} + +void GraphicsLayerCACF::setName(const String& inName) +{ + String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + inName; + GraphicsLayer::setName(name); + + m_layer->setName(inName); +} + +NativeLayer GraphicsLayerCACF::nativeLayer() const +{ + return m_layer.get(); +} + +bool GraphicsLayerCACF::setChildren(const Vector<GraphicsLayer*>& children) +{ + bool childrenChanged = GraphicsLayer::setChildren(children); + // FIXME: GraphicsLayer::setChildren calls addChild() for each sublayer, which + // will end up calling updateSublayerList() N times. + if (childrenChanged) + updateSublayerList(); + + return childrenChanged; +} + +void GraphicsLayerCACF::addChild(GraphicsLayer* childLayer) +{ + GraphicsLayer::addChild(childLayer); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildAtIndex(GraphicsLayer* childLayer, int index) +{ + GraphicsLayer::addChildAtIndex(childLayer, index); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildBelow(childLayer, sibling); + updateSublayerList(); +} + +void GraphicsLayerCACF::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer *sibling) +{ + GraphicsLayer::addChildAbove(childLayer, sibling); + updateSublayerList(); +} + +bool GraphicsLayerCACF::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + if (GraphicsLayer::replaceChild(oldChild, newChild)) { + updateSublayerList(); + return true; + } + return false; +} + +void GraphicsLayerCACF::removeFromParent() +{ + GraphicsLayer::removeFromParent(); + layerForSuperlayer()->removeFromSuperlayer(); +} + +void GraphicsLayerCACF::setPosition(const FloatPoint& point) +{ + GraphicsLayer::setPosition(point); + updateLayerPosition(); +} + +void GraphicsLayerCACF::setAnchorPoint(const FloatPoint3D& point) +{ + if (point == m_anchorPoint) + return; + + GraphicsLayer::setAnchorPoint(point); + updateAnchorPoint(); +} + +void GraphicsLayerCACF::setSize(const FloatSize& size) +{ + if (size == m_size) + return; + + GraphicsLayer::setSize(size); + updateLayerSize(); +} + +void GraphicsLayerCACF::setTransform(const TransformationMatrix& t) +{ + if (t == m_transform) + return; + + GraphicsLayer::setTransform(t); + updateTransform(); +} + +void GraphicsLayerCACF::setChildrenTransform(const TransformationMatrix& t) +{ + if (t == m_childrenTransform) + return; + + GraphicsLayer::setChildrenTransform(t); + updateChildrenTransform(); +} + +void GraphicsLayerCACF::setPreserves3D(bool preserves3D) +{ + if (preserves3D == m_preserves3D) + return; + + GraphicsLayer::setPreserves3D(preserves3D); + updateLayerPreserves3D(); +} + +void GraphicsLayerCACF::setMasksToBounds(bool masksToBounds) +{ + if (masksToBounds == m_masksToBounds) + return; + + GraphicsLayer::setMasksToBounds(masksToBounds); + updateMasksToBounds(); +} + +void GraphicsLayerCACF::setDrawsContent(bool drawsContent) +{ + if (drawsContent == m_drawsContent) + return; + + GraphicsLayer::setDrawsContent(drawsContent); + updateLayerDrawsContent(); +} + +void GraphicsLayerCACF::setBackgroundColor(const Color& color) +{ + if (m_backgroundColorSet && m_backgroundColor == color) + return; + + GraphicsLayer::setBackgroundColor(color); + + m_contentsLayerHasBackgroundColor = true; + updateLayerBackgroundColor(); +} + +void GraphicsLayerCACF::clearBackgroundColor() +{ + if (!m_backgroundColorSet) + return; + + GraphicsLayer::clearBackgroundColor(); + clearLayerBackgroundColor(m_contentsLayer.get()); +} + +void GraphicsLayerCACF::setContentsOpaque(bool opaque) +{ + if (m_contentsOpaque == opaque) + return; + + GraphicsLayer::setContentsOpaque(opaque); + updateContentsOpaque(); +} + +void GraphicsLayerCACF::setBackfaceVisibility(bool visible) +{ + if (m_backfaceVisibility == visible) + return; + + GraphicsLayer::setBackfaceVisibility(visible); + updateBackfaceVisibility(); +} + +void GraphicsLayerCACF::setOpacity(float opacity) +{ + float clampedOpacity = max(min(opacity, 1.0f), 0.0f); + + if (m_opacity == clampedOpacity) + return; + + GraphicsLayer::setOpacity(clampedOpacity); + primaryLayer()->setOpacity(opacity); +} + +void GraphicsLayerCACF::setNeedsDisplay() +{ + if (drawsContent()) + m_layer->setNeedsDisplay(); +} + +void GraphicsLayerCACF::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (drawsContent()) + m_layer->setNeedsDisplay(rect); +} + +void GraphicsLayerCACF::setContentsRect(const IntRect& rect) +{ + if (rect == m_contentsRect) + return; + + GraphicsLayer::setContentsRect(rect); + updateContentsRect(); +} + +void GraphicsLayerCACF::setContentsToImage(Image* image) +{ + bool childrenChanged = false; + + if (image) { + m_pendingContentsImage = image->nativeImageForCurrentFrame(); + m_contentsLayerPurpose = ContentsLayerForImage; + if (!m_contentsLayer) + childrenChanged = true; + } else { + m_pendingContentsImage = 0; + m_contentsLayerPurpose = NoContentsLayer; + if (m_contentsLayer) + childrenChanged = true; + } + + updateContentsImage(); + + // This has to happen after updateContentsImage + if (childrenChanged) + updateSublayerList(); +} + +void GraphicsLayerCACF::setContentsToVideo(PlatformLayer* videoLayer) +{ + bool childrenChanged = false; + + if (videoLayer != m_contentsLayer.get()) + childrenChanged = true; + + m_contentsLayer = videoLayer; + m_contentsLayerPurpose = videoLayer ? ContentsLayerForVideo : NoContentsLayer; + + updateContentsVideo(); + + // This has to happen after updateContentsVideo + if (childrenChanged) + updateSublayerList(); +} + +void GraphicsLayerCACF::setGeometryOrientation(CompositingCoordinatesOrientation orientation) +{ + if (orientation == m_geometryOrientation) + return; + + GraphicsLayer::setGeometryOrientation(orientation); + updateGeometryOrientation(); +} + +PlatformLayer* GraphicsLayerCACF::hostLayerForSublayers() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerCACF::layerForSuperlayer() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerCACF::platformLayer() const +{ + return primaryLayer(); +} + +void GraphicsLayerCACF::setDebugBackgroundColor(const Color& color) +{ + if (color.isValid()) + setLayerBackgroundColor(m_layer.get(), color); + else + clearLayerBackgroundColor(m_layer.get()); +} + +void GraphicsLayerCACF::setDebugBorder(const Color& color, float borderWidth) +{ + if (color.isValid()) { + setLayerBorderColor(m_layer.get(), color); + m_layer->setBorderWidth(borderWidth); + } else { + clearBorderColor(m_layer.get()); + m_layer->setBorderWidth(0); + } +} + +GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCACF::defaultContentsOrientation() const +{ + return CompositingCoordinatesTopDown; +} + +void GraphicsLayerCACF::updateSublayerList() +{ + Vector<RefPtr<WKCACFLayer> > newSublayers; + + if (m_transformLayer) { + // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind. + newSublayers.append(m_layer.get()); + } else if (m_contentsLayer) { + // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. + newSublayers.append(m_contentsLayer.get()); + } + + const Vector<GraphicsLayer*>& childLayers = children(); + size_t numChildren = childLayers.size(); + for (size_t i = 0; i < numChildren; ++i) { + GraphicsLayerCACF* curChild = static_cast<GraphicsLayerCACF*>(childLayers[i]); + + WKCACFLayer* childLayer = curChild->layerForSuperlayer(); + newSublayers.append(childLayer); + } + + for (int i = 0; i < newSublayers.size(); ++i) + newSublayers[i]->removeFromSuperlayer(); + + if (m_transformLayer) { + m_transformLayer->setSublayers(newSublayers); + + if (m_contentsLayer) { + // If we have a transform layer, then the contents layer is parented in the + // primary layer (which is itself a child of the transform layer). + m_layer->removeAllSublayers(); + m_layer->addSublayer(m_contentsLayer); + } + } else + m_layer->setSublayers(newSublayers); +} + +void GraphicsLayerCACF::updateLayerPosition() +{ + // Position is offset on the layer by the layer anchor point. + CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(), + m_position.y() + m_anchorPoint.y() * m_size.height()); + + primaryLayer()->setPosition(posPoint); +} + +void GraphicsLayerCACF::updateLayerSize() +{ + CGRect rect = CGRectMake(0, 0, m_size.width(), m_size.height()); + if (m_transformLayer) { + m_transformLayer->setBounds(rect); + // The anchor of the contents layer is always at 0.5, 0.5, so the position is center-relative. + CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + m_layer->setPosition(centerPoint); + } + + m_layer->setBounds(rect); + + // Note that we don't resize m_contentsLayer. It's up the caller to do that. + + // if we've changed the bounds, we need to recalculate the position + // of the layer, taking anchor point into account. + updateLayerPosition(); +} + +void GraphicsLayerCACF::updateAnchorPoint() +{ + primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y())); + primaryLayer()->setAnchorPointZ(m_anchorPoint.z()); + updateLayerPosition(); +} + +void GraphicsLayerCACF::updateTransform() +{ + CATransform3D transform; + copyTransform(transform, m_transform); + primaryLayer()->setTransform(transform); +} + +void GraphicsLayerCACF::updateChildrenTransform() +{ + CATransform3D transform; + copyTransform(transform, m_childrenTransform); + primaryLayer()->setSublayerTransform(transform); +} + +void GraphicsLayerCACF::updateMasksToBounds() +{ + m_layer->setMasksToBounds(m_masksToBounds); + updateDebugIndicators(); +} + +void GraphicsLayerCACF::updateContentsOpaque() +{ + m_layer->setOpaque(m_contentsOpaque); +} + +void GraphicsLayerCACF::updateBackfaceVisibility() +{ + m_layer->setDoubleSided(m_backfaceVisibility); +} + +void GraphicsLayerCACF::updateLayerPreserves3D() +{ + if (m_preserves3D && !m_transformLayer) { + // Create the transform layer. + m_transformLayer = WKCACFLayer::create(kCACFTransformLayer, this); + +#ifndef NDEBUG + m_transformLayer->setName(String().format("Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this)); +#endif + // Copy the position from this layer. + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + m_layer->setPosition(point); + + m_layer->setAnchorPoint(CGPointMake(0.5f, 0.5f)); + m_layer->setTransform(CATransform3DIdentity); + + // Set the old layer to opacity of 1. Further down we will set the opacity on the transform layer. + m_layer->setOpacity(1); + + // Move this layer to be a child of the transform layer. + if (m_layer->superlayer()) + m_layer->superlayer()->replaceSublayer(m_layer.get(), m_transformLayer.get()); + m_transformLayer->addSublayer(m_layer.get()); + + updateSublayerList(); + } else if (!m_preserves3D && m_transformLayer) { + // Relace the transformLayer in the parent with this layer. + m_layer->removeFromSuperlayer(); + m_transformLayer->superlayer()->replaceSublayer(m_transformLayer.get(), m_layer.get()); + + // Release the transform layer. + m_transformLayer = 0; + + updateLayerPosition(); + updateLayerSize(); + updateAnchorPoint(); + updateTransform(); + updateChildrenTransform(); + + updateSublayerList(); + } + + updateOpacityOnLayer(); +} + +void GraphicsLayerCACF::updateLayerDrawsContent() +{ + if (m_drawsContent) + m_layer->setNeedsDisplay(); + else + m_layer->setContents(nil); + + updateDebugIndicators(); +} + +void GraphicsLayerCACF::updateLayerBackgroundColor() +{ + if (!m_contentsLayer) + return; + + // We never create the contents layer just for background color yet. + if (m_backgroundColorSet) + setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor); + else + clearLayerBackgroundColor(m_contentsLayer.get()); +} + +void GraphicsLayerCACF::updateContentsImage() +{ + if (m_pendingContentsImage) { + if (!m_contentsLayer.get()) { + RefPtr<WKCACFLayer> imageLayer = WKCACFLayer::create(kCACFLayer, this); +#ifndef NDEBUG + imageLayer->setName("Image Layer"); +#endif + setupContentsLayer(imageLayer.get()); + m_contentsLayer = imageLayer; + // m_contentsLayer will be parented by updateSublayerList + } + + // FIXME: maybe only do trilinear if the image is being scaled down, + // but then what if the layer size changes? + m_contentsLayer->setMinificationFilter(kCACFFilterTrilinear); + m_contentsLayer->setContents(m_pendingContentsImage.get()); + m_pendingContentsImage = 0; + + updateContentsRect(); + } else { + // No image. + // m_contentsLayer will be removed via updateSublayerList. + m_contentsLayer = 0; + } +} + +void GraphicsLayerCACF::updateContentsVideo() +{ + // Video layer was set as m_contentsLayer, and will get parented in updateSublayerList(). + if (m_contentsLayer) { + setupContentsLayer(m_contentsLayer.get()); + updateContentsRect(); + } +} + +void GraphicsLayerCACF::updateContentsRect() +{ + if (!m_contentsLayer) + return; + + CGPoint point = CGPointMake(m_contentsRect.x(), + m_contentsRect.y()); + CGRect rect = CGRectMake(0.0f, + 0.0f, + m_contentsRect.width(), + m_contentsRect.height()); + + m_contentsLayer->setPosition(point); + m_contentsLayer->setBounds(rect); +} + +void GraphicsLayerCACF::updateGeometryOrientation() +{ + switch (geometryOrientation()) { + case CompositingCoordinatesTopDown: + m_layer->setGeometryFlipped(false); + break; + + case CompositingCoordinatesBottomUp: + m_layer->setGeometryFlipped(true); + break; + } + // Geometry orientation is mapped onto children transform in older QuartzCores, + // so is handled via setGeometryOrientation(). +} + +void GraphicsLayerCACF::setupContentsLayer(WKCACFLayer* contentsLayer) +{ + if (contentsLayer == m_contentsLayer) + return; + + if (m_contentsLayer) { + m_contentsLayer->removeFromSuperlayer(); + m_contentsLayer = 0; + } + + if (contentsLayer) { + m_contentsLayer = contentsLayer; + + if (defaultContentsOrientation() == CompositingCoordinatesBottomUp) { + CATransform3D flipper = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + m_contentsLayer->setTransform(flipper); + m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 1.0f)); + } else + m_contentsLayer->setAnchorPoint(CGPointMake(0.0f, 0.0f)); + + // Insert the content layer first. Video elements require this, because they have + // shadow content that must display in front of the video. + m_layer->insertSublayer(m_contentsLayer.get(), 0); + + updateContentsRect(); + + if (showDebugBorders()) { + setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180)); + m_contentsLayer->setBorderWidth(1.0f); + } + } + updateDebugIndicators(); +} + +// This function simply mimics the operation of GraphicsLayerCA +void GraphicsLayerCACF::updateOpacityOnLayer() +{ + primaryLayer()->setOpacity(m_opacity); +} + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.h b/WebCore/platform/graphics/win/GraphicsLayerCACF.h new file mode 100644 index 0000000..93ddf25 --- /dev/null +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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 GraphicsLayerCACF_h_ +#define GraphicsLayerCACF_h_ + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayer.h" +#include "GraphicsContext.h" +#include <wtf/RetainPtr.h> + +namespace WebCore { + +class WKCACFLayer; + +class GraphicsLayerCACF : public GraphicsLayer { +public: + + GraphicsLayerCACF(GraphicsLayerClient*); + virtual ~GraphicsLayerCACF(); + + virtual void setName(const String& inName); + + // for hosting this GraphicsLayer in a native layer hierarchy + virtual NativeLayer nativeLayer() const; + + virtual bool setChildren(const Vector<GraphicsLayer*>&); + virtual void addChild(GraphicsLayer *layer); + virtual void addChildAtIndex(GraphicsLayer *layer, int index); + virtual void addChildAbove(GraphicsLayer *layer, GraphicsLayer *sibling); + virtual void addChildBelow(GraphicsLayer *layer, GraphicsLayer *sibling); + virtual bool replaceChild(GraphicsLayer *oldChild, GraphicsLayer *newChild); + + virtual void removeFromParent(); + + virtual void setPosition(const FloatPoint& inPoint); + virtual void setAnchorPoint(const FloatPoint3D& inPoint); + virtual void setSize(const FloatSize& inSize); + + virtual void setTransform(const TransformationMatrix&); + + virtual void setChildrenTransform(const TransformationMatrix&); + + virtual void setPreserves3D(bool); + virtual void setMasksToBounds(bool); + virtual void setDrawsContent(bool); + + virtual void setBackgroundColor(const Color&); + virtual void clearBackgroundColor(); + + virtual void setContentsOpaque(bool); + virtual void setBackfaceVisibility(bool); + + virtual void setOpacity(float opacity); + + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + + virtual void setContentsRect(const IntRect&); + + virtual void setContentsToImage(Image*); + virtual void setContentsToVideo(PlatformLayer*); + + virtual PlatformLayer* platformLayer() const; + + virtual void setDebugBackgroundColor(const Color&); + virtual void setDebugBorder(const Color&, float borderWidth); + + virtual void setGeometryOrientation(CompositingCoordinatesOrientation); + + void notifySyncRequired() { if (m_client) m_client->notifySyncRequired(this); } + +private: + void updateOpacityOnLayer(); + + WKCACFLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); } + WKCACFLayer* hostLayerForSublayers() const; + WKCACFLayer* layerForSuperlayer() const; + + CompositingCoordinatesOrientation defaultContentsOrientation() const; + void updateSublayerList(); + void updateLayerPosition(); + void updateLayerSize(); + void updateAnchorPoint(); + void updateTransform(); + void updateChildrenTransform(); + void updateMasksToBounds(); + void updateContentsOpaque(); + void updateBackfaceVisibility(); + void updateLayerPreserves3D(); + void updateLayerDrawsContent(); + void updateLayerBackgroundColor(); + + void updateContentsImage(); + void updateContentsVideo(); + void updateContentsRect(); + void updateGeometryOrientation(); + + void setupContentsLayer(WKCACFLayer*); + WKCACFLayer* contentsLayer() const { return m_contentsLayer.get(); } + + RefPtr<WKCACFLayer> m_layer; + RefPtr<WKCACFLayer> m_transformLayer; + RefPtr<WKCACFLayer> m_contentsLayer; + + enum ContentsLayerPurpose { + NoContentsLayer = 0, + ContentsLayerForImage, + ContentsLayerForVideo + }; + + ContentsLayerPurpose m_contentsLayerPurpose; + bool m_contentsLayerHasBackgroundColor : 1; + RetainPtr<CGImageRef> m_pendingContentsImage; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // GraphicsLayerCACF_h_ diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp index 61f1fd3..d71ca00 100644 --- a/WebCore/platform/graphics/win/IconWin.cpp +++ b/WebCore/platform/graphics/win/IconWin.cpp @@ -47,20 +47,22 @@ Icon::~Icon() DestroyIcon(m_hIcon); } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { - SHFILEINFO sfi; - memset(&sfi, 0, sizeof(sfi)); - - String tmpFilename = filename; - if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + if (filenames.isEmpty()) return 0; - return adoptRef(new Icon(sfi.hIcon)); -} + if (filenames.size() == 1) { + SHFILEINFO sfi; + memset(&sfi, 0, sizeof(sfi)); + + String tmpFilename = filenames[0]; + if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + return 0; + + return adoptRef(new Icon(sfi.hIcon)); + } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) -{ #if PLATFORM(WINCE) return 0; #else diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp index 285fb71..2c6d41d 100644 --- a/WebCore/platform/graphics/win/ImageCGWin.cpp +++ b/WebCore/platform/graphics/win/ImageCGWin.cpp @@ -77,9 +77,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) IntSize imageSize = BitmapImage::size(); if (size) - drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); // Do cleanup CGContextRelease(cgContext); @@ -88,7 +88,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) return true; } -void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { @@ -96,7 +96,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float 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); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), styleColorSpace, compositeOp); m_currentFrame = currentFrame; return; } @@ -104,7 +104,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float // 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); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), styleColorSpace, compositeOp); } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index 0b27438..e3c5ea0 100644 --- a/WebCore/platform/graphics/win/ImageCairoWin.cpp +++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp @@ -82,9 +82,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) IntSize imageSize = BitmapImage::size(); if (size) - drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); // Do cleanup cairo_destroy(targetRef); @@ -92,7 +92,7 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) return true; } -void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator compositeOp) +void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const FloatRect& dstRect, const IntSize& srcSize, ColorSpace styleColorSpace, CompositeOperator compositeOp) { size_t frames = frameCount(); for (size_t i = 0; i < frames; ++i) { @@ -100,7 +100,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float 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); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), DeviceColorSpace, compositeOp); m_currentFrame = currentFrame; return; } @@ -108,7 +108,7 @@ void BitmapImage::drawFrameMatchingSourceSize(GraphicsContext* ctxt, const Float // 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); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, compositeOp); } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/IntPointWin.cpp b/WebCore/platform/graphics/win/IntPointWin.cpp index a6ce0bb..73db199 100644 --- a/WebCore/platform/graphics/win/IntPointWin.cpp +++ b/WebCore/platform/graphics/win/IntPointWin.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntPoint.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/IntRectWin.cpp b/WebCore/platform/graphics/win/IntRectWin.cpp index 6228be8..fe25a7f 100644 --- a/WebCore/platform/graphics/win/IntRectWin.cpp +++ b/WebCore/platform/graphics/win/IntRectWin.cpp @@ -1,3 +1,4 @@ + /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * @@ -23,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntRect.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/IntSizeWin.cpp b/WebCore/platform/graphics/win/IntSizeWin.cpp index 8a27cdb..26e68da 100644 --- a/WebCore/platform/graphics/win/IntSizeWin.cpp +++ b/WebCore/platform/graphics/win/IntSizeWin.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "IntSize.h" #include <windows.h> diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index 15e1001..a5beea1 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -318,6 +318,20 @@ void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch) m_qtMovie->setPreservesPitch(preservesPitch); } +bool MediaPlayerPrivate::hasClosedCaptions() const +{ + if (!m_qtMovie) + return false; + return m_qtMovie->hasClosedCaptions(); +} + +void MediaPlayerPrivate::setClosedCaptionsVisible(bool visible) +{ + if (!m_qtMovie) + return; + m_qtMovie->setClosedCaptionsVisible(visible); +} + int MediaPlayerPrivate::dataRate() const { // This is not used at the moment diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index 4a3a28e..2bccbbf 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -49,7 +49,10 @@ public: static void registerMediaEngine(MediaEngineRegistrar); ~MediaPlayerPrivate(); - + +private: + MediaPlayerPrivate(MediaPlayer*); + IntSize naturalSize() const; bool hasVideo() const; bool hasAudio() const; @@ -93,8 +96,8 @@ public: bool hasSingleSecurityOrigin() const; -private: - MediaPlayerPrivate(MediaPlayer*); + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); void updateStates(); void doSeek(); diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index 56f3d0b..2d4c2ea 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -45,6 +45,12 @@ using namespace std; static const long minimumQuickTimeVersion = 0x07300000; // 7.3 +static const long closedCaptionTrackType = 'clcp'; +static const long subTitleTrackType = 'sbtl'; +static const long mpeg4ObjectDescriptionTrackType = 'odsm'; +static const long mpeg4SceneDescriptionTrackType = 'sdsm'; +static const long closedCaptionDisplayPropertyID = 'disp'; + // Resizing GWorlds is slow, give them a minimum size so size of small // videos can be animated smoothly static const int cGWorldMinWidth = 640; @@ -757,10 +763,10 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount, unsigned& allowedTrackTypes->add(SoundMediaType); allowedTrackTypes->add(TextMediaType); allowedTrackTypes->add(BaseMediaType); - allowedTrackTypes->add('clcp'); // Closed caption - allowedTrackTypes->add('sbtl'); // Subtitle - allowedTrackTypes->add('odsm'); // MPEG-4 object descriptor stream - allowedTrackTypes->add('sdsm'); // MPEG-4 scene description stream + allowedTrackTypes->add(closedCaptionTrackType); + allowedTrackTypes->add(subTitleTrackType); + allowedTrackTypes->add(mpeg4ObjectDescriptionTrackType); + allowedTrackTypes->add(mpeg4SceneDescriptionTrackType); allowedTrackTypes->add(TimeCodeMediaType); allowedTrackTypes->add(TimeCode64MediaType); } @@ -877,6 +883,27 @@ bool QTMovieWin::hasAudio() const return (GetMovieIndTrackType(m_private->m_movie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); } + +bool QTMovieWin::hasClosedCaptions() const +{ + if (!m_private->m_movie) + return false; + return GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType); +} + +void QTMovieWin::setClosedCaptionsVisible(bool visible) +{ + if (!m_private->m_movie) + return; + + Track ccTrack = GetMovieIndTrackType(m_private->m_movie, 1, closedCaptionTrackType, movieTrackMediaType); + if (!ccTrack) + return; + + Boolean doDisplay = visible; + QTSetTrackProperty(ccTrack, closedCaptionTrackType, closedCaptionDisplayPropertyID, sizeof(doDisplay), &doDisplay); +} + pascal OSErr movieDrawingCompleteProc(Movie movie, long data) { UppParam param; diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h index d178eb8..778f9aa 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -98,6 +98,9 @@ public: bool hasVideo() const; bool hasAudio() const; + bool hasClosedCaptions() const; + void setClosedCaptionsVisible(bool); + static unsigned countSupportedTypes(); static void getSupportedType(unsigned index, const UChar*& str, unsigned& len); diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp new file mode 100644 index 0000000..e97b530 --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR 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 USE(ACCELERATED_COMPOSITING) + +#include "WKCACFContextFlusher.h" + +#include <wtf/StdLibExtras.h> +#include <QuartzCore/CACFContext.h> + +namespace WebCore { + +WKCACFContextFlusher& WKCACFContextFlusher::shared() +{ + DEFINE_STATIC_LOCAL(WKCACFContextFlusher, flusher, ()); + return flusher; +} + +WKCACFContextFlusher::WKCACFContextFlusher() +{ +} + +WKCACFContextFlusher::~WKCACFContextFlusher() +{ +} + +void WKCACFContextFlusher::addContext(CACFContextRef context) +{ + ASSERT(context); + + m_contexts.add(context); + CFRetain(context); +} + +void WKCACFContextFlusher::removeContext(CACFContextRef context) +{ + ASSERT(context); + + ContextSet::iterator found = m_contexts.find(context); + if (found == m_contexts.end()) + return; + + CFRelease(*found); + m_contexts.remove(found); +} + +void WKCACFContextFlusher::flushAllContexts() +{ + // addContext might get called beneath CACFContextFlush, and we don't want m_contexts to change while + // we're iterating over it, so we move the contexts into a local ContextSet and iterate over that instead. + ContextSet contextsToFlush; + contextsToFlush.swap(m_contexts); + + ContextSet::const_iterator end = contextsToFlush.end(); + for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it) { + CACFContextRef context = *it; + CACFContextFlush(context); + CFRelease(context); + } +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.h b/WebCore/platform/graphics/win/WKCACFContextFlusher.h new file mode 100644 index 0000000..9ce76aa --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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 WKCACFContextFlusher_h +#define WKCACFContextFlusher_h + +#if USE(ACCELERATED_COMPOSITING) + +#include <wtf/Noncopyable.h> + +#include <wtf/HashSet.h> + +typedef struct _CACFContext* CACFContextRef; + +namespace WebCore { + +class WKCACFContextFlusher : public Noncopyable { +public: + static WKCACFContextFlusher& shared(); + + void addContext(CACFContextRef); + void removeContext(CACFContextRef); + + void flushAllContexts(); + +private: + WKCACFContextFlusher(); + ~WKCACFContextFlusher(); + + typedef HashSet<CACFContextRef> ContextSet; + ContextSet m_contexts; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFContextFlusher_h diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp new file mode 100644 index 0000000..21e010d --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR 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 USE(ACCELERATED_COMPOSITING) + +#include "WKCACFLayer.h" + +#include "WKCACFContextFlusher.h" + +#include <stdio.h> +#include <QuartzCore/CACFContext.h> +#include <QuartzCore/CARender.h> + +#pragma comment(lib, "QuartzCore")
+ +namespace WebCore { + +using namespace std; + +static void displayInContext(CACFLayerRef layer, CGContextRef context) +{ + ASSERT_ARG(layer, WKCACFLayer::layer(layer)); + WKCACFLayer::layer(layer)->display(context); +} + +// FIXME: It might be good to have a way of ensuring that all WKCACFLayers eventually +// get destroyed in debug builds. A static counter could accomplish this pretty easily. + +WKCACFLayer::WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner) + : m_layer(AdoptCF, CACFLayerCreate(className)) + , m_needsDisplayOnBoundsChange(false) + , m_owner(owner) +{ + CACFLayerSetUserData(layer(), this); + CACFLayerSetDisplayCallback(layer(), displayInContext); +} + +WKCACFLayer::~WKCACFLayer() +{ + // Our superlayer should be holding a reference to us, so there should be no way for us to be destroyed while we still have a superlayer. + ASSERT(!superlayer()); + + CACFLayerSetUserData(layer(), 0); + CACFLayerSetDisplayCallback(layer(), 0); +} + +void WKCACFLayer::display(PlatformGraphicsContext* context) +{ + if (!m_owner) + return; + + CGContextSaveGState(context); + + CGRect layerBounds = bounds(); + if (m_owner->contentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesTopDown) { + CGContextScaleCTM(context, 1, -1); + CGContextTranslateCTM(context, 0, -layerBounds.size.height); + } + + if (m_owner->client()) { + GraphicsContext graphicsContext(context); + + // It's important to get the clip from the context, because it may be significantly + // smaller than the layer bounds (e.g. tiled layers) + CGRect clipBounds = CGContextGetClipBoundingBox(context); + IntRect clip(enclosingIntRect(clipBounds)); + m_owner->paintGraphicsLayerContents(graphicsContext, clip); + } +#ifndef NDEBUG + else { + ASSERT_NOT_REACHED(); + + // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, + // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). + CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); + CGContextFillRect(context, layerBounds); + } +#endif + + if (m_owner->showRepaintCounter()) { + char text[16]; // that's a lot of repaints + _snprintf(text, sizeof(text), "%d", m_owner->incrementRepaintCount()); + + CGContextSaveGState(context); + CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); + + CGRect aBounds = layerBounds; + + aBounds.size.width = 10 + 12 * strlen(text); + aBounds.size.height = 25; + CGContextFillRect(context, aBounds); + + CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f); + + CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f)); + CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman); + CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text)); + + CGContextRestoreGState(context); + } + + CGContextRestoreGState(context); +} + +void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context) +{ + CACFContextSetLayer(context, layer()); + setNeedsCommit(); +} + +void WKCACFLayer::setNeedsCommit() +{ + CACFContextRef context = CACFLayerGetContext(rootLayer()->layer()); + + // The context might now be set yet. This happens if a property gets set + // before placing the layer in the tree. In this case we don't need to + // worry about remembering the context because we will when the layer is + // added to the tree. + if (context) + WKCACFContextFlusher::shared().addContext(context); + + // Call notifySyncRequired(), which in this implementation plumbs through to + // call setRootLayerNeedsDisplay() on the WebView, which causes the CACFRenderer + // to render a frame. + if (m_owner) + m_owner->notifySyncRequired(); +} + +void WKCACFLayer::addSublayer(PassRefPtr<WKCACFLayer> sublayer) +{ + insertSublayer(sublayer, numSublayers()); +} + +void WKCACFLayer::insertSublayer(PassRefPtr<WKCACFLayer> sublayer, size_t index) +{ + index = min(index, numSublayers()); + CACFLayerInsertSublayer(layer(), sublayer->layer(), index); + setNeedsCommit(); +} + +void WKCACFLayer::insertSublayerAboveLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference) +{ + if (!reference) { + insertSublayer(sublayer, 0); + return; + } + + int referenceIndex = indexOfSublayer(reference); + if (referenceIndex == -1) { + addSublayer(sublayer); + return; + } + + insertSublayer(sublayer, referenceIndex + 1); +} + +void WKCACFLayer::insertSublayerBelowLayer(PassRefPtr<WKCACFLayer> sublayer, const WKCACFLayer* reference) +{ + if (!reference) { + insertSublayer(sublayer, 0); + return; + } + + int referenceIndex = indexOfSublayer(reference); + if (referenceIndex == -1) { + addSublayer(sublayer); + return; + } + + insertSublayer(sublayer, referenceIndex); +} + +void WKCACFLayer::replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer> newLayer) +{ + ASSERT_ARG(reference, reference); + ASSERT_ARG(reference, reference->superlayer() == this); + + if (reference == newLayer) + return; + + if (!newLayer) { + removeSublayer(reference); + return; + } + + newLayer->removeFromSuperlayer(); + + int referenceIndex = indexOfSublayer(reference); + ASSERT(referenceIndex != -1); + if (referenceIndex == -1) + return; + + // FIXME: Can we make this more efficient? The current CACF API doesn't seem to give us a way to do so. + reference->removeFromSuperlayer(); + insertSublayer(newLayer, referenceIndex); +} + +void WKCACFLayer::removeFromSuperlayer() +{ + WKCACFLayer* superlayer = this->superlayer(); + if (!superlayer) + return; + + superlayer->removeSublayer(this); + CACFLayerRemoveFromSuperlayer(layer()); + superlayer->setNeedsCommit(); +} + +void WKCACFLayer::removeSublayer(const WKCACFLayer* sublayer) +{ + int foundIndex = indexOfSublayer(sublayer); + if (foundIndex == -1) + return; + + CACFLayerRemoveFromSuperlayer(sublayer->layer()); + setNeedsCommit(); +} + +int WKCACFLayer::indexOfSublayer(const WKCACFLayer* reference) +{ + CACFLayerRef ref = reference->layer(); + if (!ref) + return -1; + + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + size_t n = CFArrayGetCount(sublayers); + + for (size_t i = 0; i < n; ++i) + if (CFArrayGetValueAtIndex(sublayers, i) == ref) + return i; + + return -1; +} + +WKCACFLayer* WKCACFLayer::ancestorOrSelfWithSuperlayer(WKCACFLayer* superlayer) const +{ + WKCACFLayer* layer = const_cast<WKCACFLayer*>(this); + for (WKCACFLayer* ancestor = this->superlayer(); ancestor; layer = ancestor, ancestor = ancestor->superlayer()) { + if (ancestor == superlayer) + return layer; + } + return 0; +} + +void WKCACFLayer::setBounds(const CGRect& rect) +{ + if (CGRectEqualToRect(rect, bounds())) + return; + + CACFLayerSetBounds(layer(), rect); + setNeedsCommit(); + + if (m_needsDisplayOnBoundsChange) + setNeedsDisplay(); +} + +void WKCACFLayer::setFrame(const CGRect& rect) +{ + CGRect oldFrame = frame(); + if (CGRectEqualToRect(rect, oldFrame)) + return; + + CACFLayerSetFrame(layer(), rect); + setNeedsCommit(); + + if (m_needsDisplayOnBoundsChange) + setNeedsDisplay(); +} + +WKCACFLayer* WKCACFLayer::rootLayer() const +{ + WKCACFLayer* layer = const_cast<WKCACFLayer*>(this); + for (WKCACFLayer* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { } + return layer; +} + +void WKCACFLayer::removeAllSublayers() +{ + CACFLayerSetSublayers(layer(), 0); + setNeedsCommit(); +} + +void WKCACFLayer::setSublayers(const Vector<RefPtr<WKCACFLayer> >& sublayers) +{ + if (sublayers.isEmpty()) + CACFLayerSetSublayers(layer(), 0); + else { + // Create a vector of CACFLayers. + Vector<const void*> layers; + for (size_t i = 0; i < sublayers.size(); i++) + layers.append(sublayers[i]->layer()); + + RetainPtr<CFArrayRef> layersArray(AdoptCF, CFArrayCreate(0, layers.data(), layers.size(), 0)); + CACFLayerSetSublayers(layer(), layersArray.get()); + } + + setNeedsCommit(); +} + +void WKCACFLayer::moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer) +{ + if (!fromLayer || !toLayer) + return; + + CACFLayerSetSublayers(toLayer->layer(), CACFLayerGetSublayers(fromLayer->layer())); + fromLayer->setNeedsCommit(); + toLayer->setNeedsCommit(); +} + +WKCACFLayer* WKCACFLayer::superlayer() const +{ + CACFLayerRef super = CACFLayerGetSuperlayer(layer()); + if (!super) + return 0; + return WKCACFLayer::layer(super); +} + +void WKCACFLayer::setNeedsDisplay(const CGRect& dirtyRect) +{ + if (m_owner) + CACFLayerSetNeedsDisplay(layer(), &dirtyRect); + setNeedsCommit(); +} + +void WKCACFLayer::setNeedsDisplay() +{ + if (m_owner) + CACFLayerSetNeedsDisplay(layer(), 0); + setNeedsCommit(); +} + + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h new file mode 100644 index 0000000..6655f7a --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayer.h @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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 WKCACFLayer_h +#define WKCACFLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "StringHash.h" + +#include <wtf/RefCounted.h> + +#include <QuartzCore/CACFLayer.h> +#include <QuartzCore/CACFVector.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RetainPtr.h> +#include <wtf/Vector.h> + +#include "GraphicsContext.h" +#include "GraphicsLayerCACF.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" + +namespace WebCore { + +class WKCACFAnimation; +class WKCACFTimingFunction; + +class WKCACFLayer : public RefCounted<WKCACFLayer> { +public: + static PassRefPtr<WKCACFLayer> create(CFStringRef className, GraphicsLayerCACF* owner = 0) { return adoptRef(new WKCACFLayer(className, owner)); } + static WKCACFLayer* layer(CACFLayerRef layer) { return static_cast<WKCACFLayer*>(CACFLayerGetUserData(layer)); } + + ~WKCACFLayer(); + + // Makes this layer the root when the passed context is rendered + void becomeRootLayerForContext(CACFContextRef); + + static RetainPtr<CFTypeRef> cfValue(float value) { return RetainPtr<CFTypeRef>(AdoptCF, CFNumberCreate(0, kCFNumberFloat32Type, &value)); } + static RetainPtr<CFTypeRef> cfValue(const TransformationMatrix& value) + { + CATransform3D t; + t.m11 = value.m11(); + t.m12 = value.m12(); + t.m13 = value.m13(); + t.m14 = value.m14(); + t.m21 = value.m21(); + t.m22 = value.m22(); + t.m23 = value.m23(); + t.m24 = value.m24(); + t.m31 = value.m31(); + t.m32 = value.m32(); + t.m33 = value.m33(); + t.m34 = value.m34(); + t.m41 = value.m41(); + t.m42 = value.m42(); + t.m43 = value.m43(); + t.m44 = value.m44(); + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreateTransform(t)); + } + static RetainPtr<CFTypeRef> cfValue(const FloatPoint& value) + { + CGPoint p; + p.x = value.x(); p.y = value.y(); + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreatePoint(p)); + } + static RetainPtr<CFTypeRef> cfValue(const FloatRect& rect) + { + CGRect r; + r.origin.x = rect.x(); + r.origin.y = rect.y(); + r.size.width = rect.width(); + r.size.height = rect.height(); + CGFloat v[4] = { CGRectGetMinX(r), CGRectGetMinY(r), CGRectGetMaxX(r), CGRectGetMaxY(r) }; + return RetainPtr<CFTypeRef>(AdoptCF, CACFVectorCreate(4, v)); + } + static RetainPtr<CFTypeRef> cfValue(const Color& color) + { + return RetainPtr<CFTypeRef>(AdoptCF, CGColorCreateGenericRGB(color.red(), color.green(), color.blue(), color.alpha())); + } + + void display(PlatformGraphicsContext*); + + bool isTransformLayer() const { return CACFLayerGetClass(layer()) == kCACFTransformLayer; } + + void addSublayer(PassRefPtr<WKCACFLayer> sublayer); + void insertSublayer(PassRefPtr<WKCACFLayer>, size_t index); + void insertSublayerAboveLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); + void insertSublayerBelowLayer(PassRefPtr<WKCACFLayer>, const WKCACFLayer* reference); + void replaceSublayer(WKCACFLayer* reference, PassRefPtr<WKCACFLayer>); + void removeFromSuperlayer(); + static void moveSublayers(WKCACFLayer* fromLayer, WKCACFLayer* toLayer); + + WKCACFLayer* ancestorOrSelfWithSuperlayer(WKCACFLayer*) const; + + void setAnchorPoint(const CGPoint& p) { CACFLayerSetAnchorPoint(layer(), p); setNeedsCommit(); } + CGPoint anchorPoint() const { return CACFLayerGetAnchorPoint(layer()); } + + void setAnchorPointZ(CGFloat z) { CACFLayerSetAnchorPointZ(layer(), z); setNeedsCommit(); } + CGFloat anchorPointZ() const { return CACFLayerGetAnchorPointZ(layer()); } + + void setBackgroundColor(CGColorRef color) { CACFLayerSetBackgroundColor(layer(), color); setNeedsCommit(); } + CGColorRef backgroundColor() const { return CACFLayerGetBackgroundColor(layer()); } + + void setBorderColor(CGColorRef color) { CACFLayerSetBorderColor(layer(), color); setNeedsCommit(); } + CGColorRef borderColor() const { return CACFLayerGetBorderColor(layer()); } + + void setBorderWidth(CGFloat width) { CACFLayerSetBorderWidth(layer(), width); setNeedsCommit(); } + CGFloat borderWidth() const { return CACFLayerGetBorderWidth(layer()); } + + void setBounds(const CGRect&); + CGRect bounds() const { return CACFLayerGetBounds(layer()); } + + void setClearsContext(bool clears) { CACFLayerSetClearsContext(layer(), clears); setNeedsCommit(); } + bool clearsContext() const { return CACFLayerGetClearsContext(layer()); } + + void setContents(CGImageRef contents) { CACFLayerSetContents(layer(), contents); setNeedsCommit(); } + CGImageRef contents() const { return static_cast<CGImageRef>(const_cast<void*>(CACFLayerGetContents(layer()))); } + + void setContentsRect(const CGRect& contentsRect) { CACFLayerSetContentsRect(layer(), contentsRect); setNeedsCommit(); } + CGRect contentsRect() const { return CACFLayerGetContentsRect(layer()); } + + void setContentsGravity(CFStringRef str) { CACFLayerSetContentsGravity(layer(), str); setNeedsCommit(); } + CFStringRef contentsGravity() const { return CACFLayerGetContentsGravity(layer()); } + + void setDoubleSided(bool b) { CACFLayerSetDoubleSided(layer(), b); setNeedsCommit(); } + bool doubleSided() const { return CACFLayerIsDoubleSided(layer()); } + + void setEdgeAntialiasingMask(uint32_t mask) { CACFLayerSetEdgeAntialiasingMask(layer(), mask); setNeedsCommit(); } + uint32_t edgeAntialiasingMask() const { return CACFLayerGetEdgeAntialiasingMask(layer()); } + + void setFilters(CFArrayRef filters) { CACFLayerSetFilters(layer(), filters); setNeedsCommit(); } + CFArrayRef filters() const { return CACFLayerGetFilters(layer()); } + + void setFrame(const CGRect&); + CGRect frame() const { return CACFLayerGetFrame(layer()); } + + void setHidden(bool hidden) { CACFLayerSetHidden(layer(), hidden); setNeedsCommit(); } + bool isHidden() const { return CACFLayerIsHidden(layer()); } + + void setMasksToBounds(bool b) { CACFLayerSetMasksToBounds(layer(), b); } + bool masksToBounds() const { return CACFLayerGetMasksToBounds(layer()); } + + void setMagnificationFilter(const String& string) { CACFLayerSetMagnificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); } + String magnificationFilter() const { return CACFLayerGetMagnificationFilter(layer()); } + + void setMinificationFilter(const String& string) { CACFLayerSetMinificationFilter(layer(), RetainPtr<CFStringRef>(AdoptCF, string.createCFString()).get()); } + String minificationFilter() const { return CACFLayerGetMinificationFilter(layer()); } + + void setMinificationFilterBias(float bias) { CACFLayerSetMinificationFilterBias(layer(), bias); } + float minificationFilterBias() const { return CACFLayerGetMinificationFilterBias(layer()); } + + void setName(const String& name) { CACFLayerSetName(layer(), RetainPtr<CFStringRef>(AdoptCF, name.createCFString()).get()); } + String name() const { return CACFLayerGetName(layer()); } + + void setNeedsDisplay(const CGRect& dirtyRect); + void setNeedsDisplay(); + + void setNeedsDisplayOnBoundsChange(bool needsDisplay) { m_needsDisplayOnBoundsChange = needsDisplay; } + + void setOpacity(float opacity) { CACFLayerSetOpacity(layer(), opacity); setNeedsCommit(); } + float opacity() const { return CACFLayerGetOpacity(layer()); } + + void setOpaque(bool b) { CACFLayerSetOpaque(layer(), b); setNeedsCommit(); } + bool opaque() const { return CACFLayerIsOpaque(layer()); } + + void setPosition(const CGPoint& position) { CACFLayerSetPosition(layer(), position); setNeedsCommit(); } + CGPoint position() const { return CACFLayerGetPosition(layer()); } + + void setZPosition(CGFloat position) { CACFLayerSetZPosition(layer(), position); setNeedsCommit(); } + CGFloat zPosition() const { return CACFLayerGetZPosition(layer()); } + + void setSpeed(float speed) { CACFLayerSetSpeed(layer(), speed); } + CFTimeInterval speed() const { CACFLayerGetSpeed(layer()); } + + void setTimeOffset(CFTimeInterval t) { CACFLayerSetTimeOffset(layer(), t); } + CFTimeInterval timeOffset() const { CACFLayerGetTimeOffset(layer()); } + + WKCACFLayer* rootLayer() const; + + void setSortsSublayers(bool sorts) { CACFLayerSetSortsSublayers(layer(), sorts); setNeedsCommit(); } + bool sortsSublayers() const { return CACFLayerGetSortsSublayers(layer()); } + + void removeAllSublayers(); + + void setSublayers(const Vector<RefPtr<WKCACFLayer> >&); + + void setSublayerTransform(const CATransform3D& transform) { CACFLayerSetSublayerTransform(layer(), transform); setNeedsCommit(); } + CATransform3D sublayerTransform() const { return CACFLayerGetSublayerTransform(layer()); } + + WKCACFLayer* superlayer() const; + + void setTransform(const CATransform3D& transform) { CACFLayerSetTransform(layer(), transform); setNeedsCommit(); } + CATransform3D transform() const { return CACFLayerGetTransform(layer()); } + + void setGeometryFlipped(bool flipped) { CACFLayerSetGeometryFlipped(layer(), flipped); setNeedsCommit(); } + bool geometryFlipped() const { return CACFLayerIsGeometryFlipped(layer()); } + + WKCACFLayer(CFStringRef className, GraphicsLayerCACF* owner); + +private: + void setNeedsCommit(); + CACFLayerRef layer() const { return m_layer.get(); } + size_t numSublayers() const + { + CFArrayRef sublayers = CACFLayerGetSublayers(layer()); + return sublayers ? CFArrayGetCount(sublayers) : 0; + } + + // Returns the index of the passed layer in this layer's sublayers list + // or -1 if not found + int indexOfSublayer(const WKCACFLayer*); + + // This should only be called from removeFromSuperlayer. + void removeSublayer(const WKCACFLayer*); + + RetainPtr<CACFLayerRef> m_layer; + bool m_needsDisplayOnBoundsChange; + GraphicsLayerCACF* m_owner; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFLayer_h diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp new file mode 100644 index 0000000..9fbd0fc --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR 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 USE(ACCELERATED_COMPOSITING) + +#include "WKCACFLayerRenderer.h" + +#include "WKCACFContextFlusher.h" +#include "WKCACFLayer.h" +#include <CoreGraphics/CGSRegion.h> +#include <QuartzCore/CACFContext.h> +#include <QuartzCore/CARenderOGL.h> +#include <wtf/HashMap.h> +#include <wtf/OwnArrayPtr.h> +#include <d3d9.h> +#include <d3dx9.h> +#include <dxerr9.h> + +#pragma comment(lib, "d3d9")
+#pragma comment(lib, "d3dx9")
+#pragma comment(lib, "QuartzCore")
+ +static IDirect3D9* s_d3d = 0; +static IDirect3D9* d3d() +{ + if (s_d3d) + return s_d3d; + + if (!LoadLibrary(TEXT("d3d9.dll"))) + return 0; + + s_d3d = Direct3DCreate9(D3D_SDK_VERSION); + + return s_d3d; +} + +inline static CGRect winRectToCGRect(RECT rc) +{ + return CGRectMake(rc.left, rc.top, (rc.right - rc.left), (rc.bottom - rc.top)); +} + +inline static CGRect winRectToCGRect(RECT rc, RECT relativeToRect) +{ + return CGRectMake(rc.left, (relativeToRect.bottom-rc.bottom), (rc.right - rc.left), (rc.bottom - rc.top)); +} + +namespace WebCore { + +typedef HashMap<CACFContextRef, WKCACFLayerRenderer*> ContextToWindowMap; + +static ContextToWindowMap& windowsForContexts() +{ + DEFINE_STATIC_LOCAL(ContextToWindowMap, map, ()); + return map; +} + +static D3DPRESENT_PARAMETERS initialPresentationParameters() +{ + D3DPRESENT_PARAMETERS parameters = {0}; + parameters.Windowed = TRUE; + parameters.SwapEffect = D3DSWAPEFFECT_COPY; + parameters.BackBufferCount = 1; + parameters.BackBufferFormat = D3DFMT_A8R8G8B8; + parameters.MultiSampleType = D3DMULTISAMPLE_NONE; + + return parameters; +} + +bool WKCACFLayerRenderer::acceleratedCompositingAvailable()
+{
+ static bool available;
+ static bool tested;
+
+ if (tested)
+ return available;
+
+ tested = true;
+ HMODULE library = LoadLibrary(TEXT("d3d9.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ library = LoadLibrary(TEXT("QuartzCore.dll"));
+ if (!library)
+ return false;
+
+ FreeLibrary(library);
+ available = true;
+ return available;
+}
+
+void WKCACFLayerRenderer::didFlushContext(CACFContextRef context) +{ + WKCACFLayerRenderer* window = windowsForContexts().get(context); + if (!window) + return; + + window->renderSoon(); +} + +PassOwnPtr<WKCACFLayerRenderer> WKCACFLayerRenderer::create() +{ + if (!acceleratedCompositingAvailable()) + return 0; + return new WKCACFLayerRenderer; +} + +WKCACFLayerRenderer::WKCACFLayerRenderer() + : m_triedToCreateD3DRenderer(false) + , m_renderContext(0) + , m_renderer(0) + , m_hostWindow(0) + , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired) + , m_scrollFrameWidth(1) // Default to 1 to avoid 0 size frames + , m_scrollFrameHeight(1) // Default to 1 to avoid 0 size frames +{ +} + +WKCACFLayerRenderer::~WKCACFLayerRenderer() +{ + destroyRenderer(); +} + +void WKCACFLayerRenderer::setScrollFrame(int width, int height, int scrollX, int scrollY) +{ + m_scrollFrameWidth = width; + m_scrollFrameHeight = height; + + CGRect contentsRect = CGRectMake(scrollX, scrollY, width, height); + m_scrollLayer->setFrame(contentsRect); + + if (m_rootChildLayer) { + contentsRect.origin.x = 0; + contentsRect.origin.y = 0; + m_rootChildLayer->setFrame(contentsRect); + } +} + +void WKCACFLayerRenderer::setRootContents(CGImageRef image) +{ + ASSERT(m_rootLayer); + m_rootLayer->setContents(image); + renderSoon(); +} + +void WKCACFLayerRenderer::setRootChildLayer(WebCore::PlatformLayer* layer) +{ + if (!m_scrollLayer) + return; + + m_scrollLayer->removeAllSublayers(); + if (layer) { + m_scrollLayer->addSublayer(layer); + + // Set the frame + layer->setFrame(CGRectMake(0, 0, m_scrollFrameWidth, m_scrollFrameHeight)); + } + + m_rootChildLayer = layer; + +} + +void WKCACFLayerRenderer::setNeedsDisplay() +{ + ASSERT(m_rootLayer); + m_rootLayer->setNeedsDisplay(); + renderSoon(); +} + +void WKCACFLayerRenderer::createRenderer() +{ + if (m_triedToCreateD3DRenderer) + return; + + m_triedToCreateD3DRenderer = true; + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + + if (!d3d() || !::IsWindow(m_hostWindow)) + return; + + // D3D doesn't like to make back buffers for 0 size windows. We skirt this problem if we make the + // passed backbuffer width and height non-zero. The window will necessarily get set to a non-zero + // size eventually, and then the backbuffer size will get reset. + RECT rect; + GetClientRect(m_hostWindow, &rect); + + if (rect.left-rect.right == 0 || rect.bottom-rect.top == 0) { + parameters.BackBufferWidth = 1; + parameters.BackBufferHeight = 1; + } + + if (FAILED(d3d()->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hostWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, ¶meters, &m_d3dDevice))) + return; + + D3DXMATRIXA16 projection; + D3DXMatrixOrthoOffCenterRH(&projection, rect.left, rect.right, rect.top, rect.bottom, -1.0f, 1.0f); + + m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); + + m_context.adoptCF(CACFContextCreate(0)); + windowsForContexts().set(m_context.get(), this); + + m_renderContext = static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get())); + m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0); + + // Create the root hierarchy + m_rootLayer = WKCACFLayer::create(kCACFLayer); + m_scrollLayer = WKCACFLayer::create(kCACFLayer); + + m_rootLayer->addSublayer(m_scrollLayer); + m_scrollLayer->setMasksToBounds(true); + +#ifndef NDEBUG + CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204)); + m_rootLayer->setBackgroundColor(debugColor); + CGColorRelease(debugColor); +#endif + + if (IsWindow(m_hostWindow)) { + m_rootLayer->setFrame(bounds()); + + // For now this will include the scroll bars. Later in the setScrollFrame + // we will fix it + m_scrollLayer->setFrame(bounds()); + } + + if (m_context) + m_rootLayer->becomeRootLayerForContext(m_context.get()); +} + +void WKCACFLayerRenderer::destroyRenderer() +{ + if (m_context) { + windowsForContexts().remove(m_context.get()); + WKCACFContextFlusher::shared().removeContext(m_context.get()); + } + + if (m_renderer) + CARenderOGLDestroy(m_renderer); + m_renderer = 0; + m_d3dDevice = 0; + if (s_d3d) + s_d3d->Release(); + + s_d3d = 0; + m_rootLayer = 0; + m_scrollLayer = 0; + m_rootChildLayer = 0; + + m_triedToCreateD3DRenderer = false; +} + +void WKCACFLayerRenderer::resize() +{ + if (!m_d3dDevice) + return; + + resetDevice(); + + if (m_rootLayer) { + m_rootLayer->setFrame(bounds()); + WKCACFContextFlusher::shared().flushAllContexts(); + } +} + +static void getDirtyRects(HWND window, Vector<CGRect>& outRects) +{ + ASSERT_ARG(outRects, outRects.isEmpty()); + + RECT clientRect; + if (!GetClientRect(window, &clientRect)) + return; + + HRGN region = CreateRectRgn(0, 0, 0, 0); + int regionType = GetUpdateRgn(window, region, false); + if (regionType != COMPLEXREGION) { + RECT dirtyRect; + if (GetUpdateRect(window, &dirtyRect, false)) + outRects.append(winRectToCGRect(dirtyRect, clientRect)); + return; + } + + DWORD dataSize = GetRegionData(region, 0, 0); + OwnArrayPtr<unsigned char> regionDataBuffer(new unsigned char[dataSize]); + RGNDATA* regionData = reinterpret_cast<RGNDATA*>(regionDataBuffer.get()); + if (!GetRegionData(region, dataSize, regionData)) + return; + + outRects.resize(regionData->rdh.nCount); + + RECT* rect = reinterpret_cast<RECT*>(regionData->Buffer); + for (size_t i = 0; i < outRects.size(); ++i, ++rect) + outRects[i] = winRectToCGRect(*rect, clientRect); + + DeleteObject(region); +} + +void WKCACFLayerRenderer::renderTimerFired(Timer<WKCACFLayerRenderer>*) +{ + paint(); +} + +void WKCACFLayerRenderer::paint() +{ + if (!m_d3dDevice) + return; + + Vector<CGRect> dirtyRects; + getDirtyRects(m_hostWindow, dirtyRects); + render(dirtyRects); +} + +void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) +{ + ASSERT(m_d3dDevice); + + // Flush the root layer to the render tree. + WKCACFContextFlusher::shared().flushAllContexts(); + + CGRect bounds = this->bounds(); + + CFTimeInterval t = CACurrentMediaTime(); + + // Give the renderer some space to use. This needs to be valid until the + // CARenderUpdateFinish() call below. + char space[4096]; + CARenderUpdate* u = CARenderUpdateBegin(space, sizeof(space), t, 0, 0, &bounds); + if (!u) + return; + + CARenderContextLock(m_renderContext); + CARenderUpdateAddContext(u, m_renderContext); + CARenderContextUnlock(m_renderContext); + + for (size_t i = 0; i < dirtyRects.size(); ++i) + CARenderUpdateAddRect(u, &dirtyRects[i]); + + HRESULT err = S_OK; + do { + CGSRegionObj rgn = CARenderUpdateCopyRegion(u); + + if (!rgn) + break; + + // FIXME: don't need to clear dirty region if layer tree is opaque. + + Vector<D3DRECT, 64> rects; + CGSRegionEnumeratorObj e = CGSRegionEnumerator(rgn); + for (const CGRect* r = CGSNextRect(e); r; r = CGSNextRect(e)) { + D3DRECT rect; + rect.x1 = r->origin.x; + rect.x2 = rect.x1 + r->size.width; + rect.y1 = bounds.origin.y + bounds.size.height - (r->origin.y + r->size.height); + rect.y2 = rect.y1 + r->size.height; + + rects.append(rect); + } + CGSReleaseRegionEnumerator(e); + CGSReleaseRegion(rgn); + + if (rects.isEmpty()) + break; + + m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0); + + m_d3dDevice->BeginScene(); + CARenderOGLRender(m_renderer, u); + m_d3dDevice->EndScene(); + + err = m_d3dDevice->Present(0, 0, 0, 0); + + if (err == D3DERR_DEVICELOST) { + // Lost device situation. + CARenderOGLPurge(m_renderer); + resetDevice(); + CARenderUpdateAddRect(u, &bounds); + } + } while (err == D3DERR_DEVICELOST); + + CARenderUpdateFinish(u); +} + +void WKCACFLayerRenderer::renderSoon() +{ + if (!m_renderTimer.isActive()) + m_renderTimer.startOneShot(0); +} + +CGRect WKCACFLayerRenderer::bounds() const +{ + RECT clientRect; + GetClientRect(m_hostWindow, &clientRect); + + return winRectToCGRect(clientRect); +} + +void WKCACFLayerRenderer::initD3DGeometry() +{ + ASSERT(m_d3dDevice); + + CGRect bounds = this->bounds(); + + float x0 = bounds.origin.x; + float y0 = bounds.origin.y; + float x1 = x0 + bounds.size.width; + float y1 = y0 + bounds.size.height; + + D3DXMATRIXA16 projection; + D3DXMatrixOrthoOffCenterRH(&projection, x0, x1, y0, y1, -1.0f, 1.0f); + + m_d3dDevice->SetTransform(D3DTS_PROJECTION, &projection); +} + +void WKCACFLayerRenderer::resetDevice() +{ + ASSERT(m_d3dDevice); + + D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); + m_d3dDevice->Reset(¶meters); + initD3DGeometry(); +} + +} + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h new file mode 100644 index 0000000..12cde48 --- /dev/null +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (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 WKCACFLayerRenderer_h +#define WKCACFLayerRenderer_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "COMPtr.h" +#include "Timer.h" +#include "WKCACFLayer.h" + +#include <wtf/Noncopyable.h> + +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/RetainPtr.h> + +#include <CoreGraphics/CGGeometry.h> + +interface IDirect3DDevice9; +typedef struct _CACFContext* CACFContextRef; +typedef struct _CARenderContext CARenderContext; +typedef struct _CARenderOGLContext CARenderOGLContext; + +namespace WebCore { + +// FIXME: Currently there is a WKCACFLayerRenderer for each WebView and each +// has its own CARenderOGLContext and Direct3DDevice9, which is inefficient. +// (https://bugs.webkit.org/show_bug.cgi?id=31855) +class WKCACFLayerRenderer : public Noncopyable { +public: + static PassOwnPtr<WKCACFLayerRenderer> create(); + ~WKCACFLayerRenderer(); + + static bool acceleratedCompositingAvailable(); + static void didFlushContext(CACFContextRef); + + void setScrollFrame(int width, int height, int scrollX, int scrollY); + void setRootContents(CGImageRef); + void setRootChildLayer(WebCore::PlatformLayer* layer); + void setNeedsDisplay(); + void setHostWindow(HWND window) { m_hostWindow = window; createRenderer(); } + + void createRenderer(); + void destroyRenderer(); + void resize(); + void renderSoon(); + +protected: + WKCACFLayer* rootLayer() const { return m_rootLayer.get(); } + +private: + WKCACFLayerRenderer(); + + void renderTimerFired(Timer<WKCACFLayerRenderer>*); + + CGRect bounds() const; + + void initD3DGeometry(); + void resetDevice(); + + void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); + void paint(); + + bool m_triedToCreateD3DRenderer; + COMPtr<IDirect3DDevice9> m_d3dDevice; + RefPtr<WKCACFLayer> m_rootLayer; + RefPtr<WKCACFLayer> m_viewLayer; + RefPtr<WKCACFLayer> m_scrollLayer; + RefPtr<WKCACFLayer> m_rootChildLayer; + RetainPtr<CACFContextRef> m_context; + CARenderContext* m_renderContext; + CARenderOGLContext* m_renderer; + HWND m_hostWindow; + Timer<WKCACFLayerRenderer> m_renderTimer; + int m_scrollFrameWidth, m_scrollFrameHeight; +}; + +} + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WKCACFLayerRenderer_h diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp index f308840..f22e6c9 100644 --- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp +++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp @@ -947,7 +947,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points } } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled() || !m_data->m_opacity) return; @@ -1051,12 +1051,12 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int wi notImplemented(); } -void GraphicsContext::setPlatformFillColor(const Color& col) +void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace) { notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& col) +void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace) { notImplemented(); } @@ -1088,7 +1088,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) return; } - fillRect(rect, Color(Color::white)); + fillRect(rect, Color(Color::white), DeviceColorSpace); } void GraphicsContext::strokeRect(const FloatRect& rect, float width) @@ -1238,7 +1238,7 @@ static inline IntPoint rectCenterPoint(const RECT& rect) { return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2); } -void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c) +void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c, ColorSpace colorSpace) { ScopeDCProvider dcProvider(m_data); if (!m_data->m_dc) @@ -1355,7 +1355,7 @@ Color gradientAverageColor(const Gradient* gradient) void GraphicsContext::fillPath() { - Color c = m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient + Color c = m_common->state.fillGradient ? gradientAverageColor(m_common->state.fillGradient.get()) : fillColor(); @@ -1449,7 +1449,7 @@ void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient) if (numStops == 1) { const Gradient::ColorStop& stop = stops.first(); Color color(stop.red, stop.green, stop.blue, stop.alpha); - fillRect(r, color); + fillRect(r, color, DeviceColorSpace); return; } @@ -1539,13 +1539,13 @@ void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) void GraphicsContext::fillRect(const FloatRect& rect) { - if (m_common->state.fillColorSpace == GradientColorSpace && m_common->state.fillGradient) + if (m_common->state.fillGradient) fillRect(rect, m_common->state.fillGradient.get()); else - fillRect(rect, fillColor()); + fillRect(rect, fillColor(), DeviceColorSpace); } -void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&) +void GraphicsContext::setPlatformShadow(const IntSize&, int, const Color&, ColorSpace) { notImplemented(); } diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp index de92fcd..fd3322f 100644 --- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp +++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp @@ -111,7 +111,7 @@ unsigned FontPlatformData::computeHash() const { // a font whose properties are equal should generate the same hash uintptr_t hashCodes[6] = { thisFont->GetPointSize(), thisFont->GetFamily(), thisFont->GetStyle(), thisFont->GetWeight(), thisFont->GetUnderlined(), - StringImpl::computeHash(thisFont->GetFaceName().mb_str(wxConvUTF8)) }; + StringImpl::computeHash(thisFont->GetFaceName().utf8_str()) }; return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); } diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 39f14f4..9c05ce5 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -119,8 +119,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor()); - setPlatformStrokeColor(strokeColor()); + setPlatformFillColor(fillColor(), DeviceColorSpace); + setPlatformStrokeColor(strokeColor(), DeviceColorSpace); } #if USE(WXGC) m_data->context = (wxGCDC*)context; @@ -252,7 +252,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points delete [] polygon; } -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -262,7 +262,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& 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) +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -438,7 +438,7 @@ void GraphicsContext::addPath(const Path& path) notImplemented(); } -void GraphicsContext::setPlatformStrokeColor(const Color& color) +void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -457,7 +457,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) } -void GraphicsContext::setPlatformFillColor(const Color& color) +void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace) { if (paintingDisabled()) return; @@ -511,7 +511,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; } -void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&) +void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&, ColorSpace) { notImplemented(); } @@ -566,4 +566,72 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness notImplemented(); } +#if PLATFORM(WIN_OS) +HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + 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(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); + if (!bitmap) + return 0; + + HDC displayDC = ::GetDC(0); + HDC bitmapDC = ::CreateCompatibleDC(displayDC); + ::ReleaseDC(0, displayDC); + + ::SelectObject(bitmapDC, bitmap); + + // Fill our buffer with clear if we're going to alpha blend. + if (supportAlphaBlend) { + BITMAP bmpInfo; + GetObject(bitmap, sizeof(bmpInfo), &bmpInfo); + int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight; + memset(bmpInfo.bmBits, 0, bufferSize); + } + return bitmapDC; +} + +void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) +{ + if (hdc) { + + if (!dstRect.isEmpty()) { + + HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP)); + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + wxBitmap bmp; + bmp.SetHBITMAP(bitmap); +#if !wxCHECK_VERSION(2,9,0) + if (supportAlphaBlend) + bmp.UseAlpha(); +#endif + m_data->context->DrawBitmap(bmp, dstRect.x(), dstRect.y(), supportAlphaBlend); + + ::DeleteObject(bitmap); + } + + ::DeleteDC(hdc); + } +} +#endif + } diff --git a/WebCore/platform/graphics/wx/IconWx.cpp b/WebCore/platform/graphics/wx/IconWx.cpp index e82091e..d3cc961 100644 --- a/WebCore/platform/graphics/wx/IconWx.cpp +++ b/WebCore/platform/graphics/wx/IconWx.cpp @@ -32,12 +32,6 @@ Icon::~Icon() { } -PassRefPtr<Icon> Icon::createIconForFile(const String& filename) -{ - notImplemented(); - return 0; -} - PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) { notImplemented(); diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index bd129cf..ff60d6f 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -86,13 +86,13 @@ void BitmapImage::initPlatformData() // Drawing Routines -void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op) { if (!m_source.initialized()) return; if (mayFillWithSolidColor()) { - fillWithSolidColor(ctxt, dst, solidColor(), op); + fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op); return; } @@ -176,7 +176,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR observer->didDraw(this); } -void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& dstRect) { if (!m_source.initialized()) return; @@ -261,7 +261,7 @@ void BitmapImage::invalidatePlatformData() } -void Image::drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& destRect) +void Image::drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& destRect) { notImplemented(); } |
