diff options
Diffstat (limited to 'WebCore/platform/graphics')
176 files changed, 5046 insertions, 2376 deletions
diff --git a/WebCore/platform/graphics/ANGLEWebKitBridge.cpp b/WebCore/platform/graphics/ANGLEWebKitBridge.cpp index 9a14820..64f19c4 100644 --- a/WebCore/platform/graphics/ANGLEWebKitBridge.cpp +++ b/WebCore/platform/graphics/ANGLEWebKitBridge.cpp @@ -44,8 +44,6 @@ ANGLEWebKitBridge::~ANGLEWebKitBridge() ShDestruct(m_fragmentCompiler); ShDestruct(m_vertexCompiler); } - - ShFinalize(); } bool ANGLEWebKitBridge::validateShaderSource(const char* shaderSource, ANGLEShaderType shaderType, String& translatedShaderSource, String& shaderValidationLog) diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp index f28d51c..fa7346e 100644 --- a/WebCore/platform/graphics/Color.cpp +++ b/WebCore/platform/graphics/Color.cpp @@ -175,8 +175,7 @@ Color::Color(const char* name) m_valid = parseHexColor(&name[1], m_color); else { const NamedColor* foundColor = findColor(name, strlen(name)); - m_color = foundColor ? foundColor->RGBValue : 0; - m_color |= 0xFF000000; + m_color = foundColor ? foundColor->ARGBValue : 0; m_valid = foundColor; } } @@ -219,8 +218,7 @@ static inline const NamedColor* findNamedColor(const String& name) void Color::setNamedColor(const String& name) { const NamedColor* foundColor = findNamedColor(name); - m_color = foundColor ? foundColor->RGBValue : 0; - m_color |= 0xFF000000; + m_color = foundColor ? foundColor->ARGBValue : 0; m_valid = foundColor; } diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index 22a8a8f..276e69f 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-6 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,6 +31,7 @@ #include <wtf/unicode/Unicode.h> #if PLATFORM(CG) +#include "ColorSpace.h" typedef struct CGColor* CGColorRef; #endif @@ -180,7 +181,7 @@ Color colorFromPremultipliedARGB(unsigned); unsigned premultipliedARGBFromColor(const Color&); #if PLATFORM(CG) -CGColorRef createCGColor(const Color&); +CGColorRef cachedCGColor(const Color&, ColorSpace); #endif } // namespace WebCore diff --git a/WebCore/platform/graphics/ColorSpace.h b/WebCore/platform/graphics/ColorSpace.h index 1bad58c..7622c47 100644 --- a/WebCore/platform/graphics/ColorSpace.h +++ b/WebCore/platform/graphics/ColorSpace.h @@ -28,7 +28,11 @@ namespace WebCore { - enum ColorSpace { DeviceColorSpace, sRGBColorSpace }; +enum ColorSpace { + ColorSpaceDeviceRGB, + ColorSpaceSRGB, + ColorSpaceLinearRGB +}; } // namespace WebCore diff --git a/WebCore/platform/graphics/ContextShadow.cpp b/WebCore/platform/graphics/ContextShadow.cpp index 1007962..87a1c5c 100644 --- a/WebCore/platform/graphics/ContextShadow.cpp +++ b/WebCore/platform/graphics/ContextShadow.cpp @@ -39,18 +39,20 @@ namespace WebCore { ContextShadow::ContextShadow() : m_type(NoShadow) - , m_blurRadius(0) + , m_blurDistance(0) + , m_layerContext(0) { } ContextShadow::ContextShadow(const Color& color, float radius, const FloatSize& offset) : m_color(color) - , m_blurRadius(round(radius)) + , m_blurDistance(round(radius)) , m_offset(offset) + , m_layerContext(0) { // See comments in http://webkit.org/b/40793, it seems sensible // to follow Skia's limit of 128 pixels of blur radius - m_blurRadius = min(m_blurRadius, 128); + m_blurDistance = min(m_blurDistance, 128); // The type of shadow is decided by the blur radius, shadow offset, and shadow color. if (!m_color.isValid() || !color.alpha()) { @@ -71,7 +73,7 @@ void ContextShadow::clear() { m_type = NoShadow; m_color = Color(); - m_blurRadius = 0; + m_blurDistance = 0; m_offset = FloatSize(); } @@ -85,8 +87,9 @@ static const int BlurSumShift = 15; void ContextShadow::blurLayerImage(unsigned char* imageData, const IntSize& size, int rowStride) { int channels[4] = { 3, 0, 1, 3 }; - int dmax = m_blurRadius >> 1; - int dmin = dmax - 1 + (m_blurRadius & 1); + int d = max(2, static_cast<int>(floorf((2 / 3.f) * m_blurDistance))); + int dmax = d >> 1; + int dmin = dmax - 1 + (d & 1); if (dmin < 0) dmin = 0; @@ -153,8 +156,8 @@ void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const destinationRect.move(m_offset); m_layerRect = enclosingIntRect(destinationRect); - // We expand the area by the blur radius * 2 to give extra space for the blur transition. - m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0); + // We expand the area by the blur radius to give extra space for the blur transition. + m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0); if (!clipRect.contains(m_layerRect)) { // No need to have the buffer larger than the clip. @@ -167,7 +170,7 @@ void ContextShadow::calculateLayerBoundingRect(const FloatRect& layerArea, const // We adjust again because the pixels at the borders are still // potentially affected by the pixels outside the buffer. if (m_type == BlurShadow) - m_layerRect.inflate((m_type == BlurShadow) ? ceil(m_blurRadius * 2) : 0); + m_layerRect.inflate(m_type == BlurShadow ? m_blurDistance : 0); } } diff --git a/WebCore/platform/graphics/ContextShadow.h b/WebCore/platform/graphics/ContextShadow.h index ede9336..0160f8a 100644 --- a/WebCore/platform/graphics/ContextShadow.h +++ b/WebCore/platform/graphics/ContextShadow.h @@ -31,6 +31,7 @@ #include "Color.h" #include "FloatRect.h" +#include "GraphicsContext.h" #include "IntRect.h" #include "RefCounted.h" @@ -65,7 +66,7 @@ public: } m_type; Color m_color; - int m_blurRadius; + int m_blurDistance; FloatSize m_offset; ContextShadow(); @@ -98,6 +99,9 @@ public: PlatformContext beginShadowLayer(PlatformContext, const FloatRect& layerArea); void endShadowLayer(PlatformContext); static void purgeScratchBuffer(); +#if PLATFORM(CAIRO) + void drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius = IntSize(), const IntSize& topRightRadius = IntSize(), const IntSize& bottomLeftRadius = IntSize(), const IntSize& bottomRightRadius = IntSize()); +#endif #if PLATFORM(QT) QPointF offset() { return QPointF(m_offset.width(), m_offset.height()); } @@ -111,6 +115,9 @@ private: void blurLayerImage(unsigned char*, const IntSize& imageSize, int stride); void calculateLayerBoundingRect(const FloatRect& layerArea, const IntRect& clipRect); +#if PLATFORM(CAIRO) + void drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha); +#endif }; } // namespace WebCore diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index e387927..10ad838 100644 --- a/WebCore/platform/graphics/FloatRect.h +++ b/WebCore/platform/graphics/FloatRect.h @@ -59,6 +59,10 @@ class BRect; struct SkRect; #endif +#if PLATFORM(CAIRO) +typedef struct _cairo_rectangle cairo_rectangle_t; +#endif + namespace WebCore { #if PLATFORM(OPENVG) @@ -172,6 +176,11 @@ public: operator VGRect() const; #endif +#if PLATFORM(CAIRO) + FloatRect(const cairo_rectangle_t&); + operator cairo_rectangle_t() const; +#endif + private: FloatPoint m_location; FloatSize m_size; diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index 3dfdb20..ec15d26 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -219,7 +219,7 @@ void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setStrokeColor(Color::black, DeviceColorSpace); + setStrokeColor(Color::black, ColorSpaceDeviceRGB); return; } m_common->state.strokeGradient.clear(); @@ -231,7 +231,7 @@ void GraphicsContext::setFillPattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); if (!pattern) { - setFillColor(Color::black, DeviceColorSpace); + setFillColor(Color::black, ColorSpaceDeviceRGB); return; } m_common->state.fillGradient.clear(); @@ -243,7 +243,7 @@ void GraphicsContext::setStrokeGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setStrokeColor(Color::black, DeviceColorSpace); + setStrokeColor(Color::black, ColorSpaceDeviceRGB); return; } m_common->state.strokeGradient = gradient; @@ -255,7 +255,7 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) { ASSERT(gradient); if (!gradient) { - setFillColor(Color::black, DeviceColorSpace); + setFillColor(Color::black, ColorSpaceDeviceRGB); return; } m_common->state.fillGradient = gradient; @@ -500,7 +500,9 @@ void GraphicsContext::addRoundedRectClip(const IntRect& rect, const IntSize& top if (paintingDisabled()) return; - clip(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); + Path path; + path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + clip(path); } void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, @@ -509,7 +511,9 @@ void GraphicsContext::clipOutRoundedRect(const IntRect& rect, const IntSize& top if (paintingDisabled()) return; - clipOut(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); + Path path; + path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + clipOut(path); } void GraphicsContext::clipToImageBuffer(ImageBuffer* buffer, const FloatRect& rect) diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index fd3bf2c..b1fa48a 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -41,6 +41,9 @@ typedef struct CGContext PlatformGraphicsContext; #elif PLATFORM(CAIRO) #include "PlatformRefPtrCairo.h" +namespace WebCore { +class ContextShadow; +} typedef struct _cairo PlatformGraphicsContext; #elif PLATFORM(OPENVG) namespace WebCore { @@ -333,11 +336,6 @@ namespace WebCore { void setAlpha(float); #if PLATFORM(CAIRO) float getAlpha(); - void applyPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius); - PlatformRefPtr<cairo_surface_t> createShadowMask(PassOwnPtr<ImageBuffer>, const FloatRect&, float radius); - - static void calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowOffset, float shadowBlur); - void drawTiledShadow(const IntRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius, ColorSpace colorSpace); #endif void setCompositeOperation(CompositeOperator); @@ -438,6 +436,9 @@ namespace WebCore { void pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask); QPen pen(); static QPainter::CompositionMode toQtCompositionMode(CompositeOperator op); +#endif + +#if PLATFORM(QT) || PLATFORM(CAIRO) ContextShadow* contextShadow(); #endif diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp index 86e9569..d2e9057 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.cpp +++ b/WebCore/platform/graphics/GraphicsContext3D.cpp @@ -31,11 +31,27 @@ #include "GraphicsContext3D.h" #include "ArrayBufferView.h" +#include "DrawingBuffer.h" #include "Image.h" #include "ImageData.h" namespace WebCore { +static uint8_t convertColor16LittleTo8(uint16_t value) +{ + return value >> 8; +} + +static uint8_t convertColor16BigTo8(uint16_t value) +{ + return static_cast<uint8_t>(value & 0x00FF); +} + +PassRefPtr<DrawingBuffer> GraphicsContext3D::createDrawingBuffer(const IntSize& size) +{ + return DrawingBuffer::create(this, size); +} + bool GraphicsContext3D::computeFormatAndTypeParameters(unsigned int format, unsigned int type, unsigned long* componentsPerPixel, @@ -247,6 +263,22 @@ void unpackRGBA8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = source[3]; } +void unpackRGBA16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16LittleTo8(source[0]); + destination[1] = convertColor16LittleTo8(source[1]); + destination[2] = convertColor16LittleTo8(source[2]); + destination[3] = convertColor16LittleTo8(source[3]); +} + +void unpackRGBA16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16BigTo8(source[0]); + destination[1] = convertColor16BigTo8(source[1]); + destination[2] = convertColor16BigTo8(source[2]); + destination[3] = convertColor16BigTo8(source[3]); +} + void unpackRGB8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = source[0]; @@ -255,6 +287,22 @@ void unpackRGB8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = 0xFF; } +void unpackRGB16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16LittleTo8(source[0]); + destination[1] = convertColor16LittleTo8(source[1]); + destination[2] = convertColor16LittleTo8(source[2]); + destination[3] = 0xFF; +} + +void unpackRGB16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16BigTo8(source[0]); + destination[1] = convertColor16BigTo8(source[1]); + destination[2] = convertColor16BigTo8(source[2]); + destination[3] = 0xFF; +} + void unpackARGB8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = source[1]; @@ -263,6 +311,22 @@ void unpackARGB8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = source[0]; } +void unpackARGB16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16LittleTo8(source[1]); + destination[1] = convertColor16LittleTo8(source[2]); + destination[2] = convertColor16LittleTo8(source[3]); + destination[3] = convertColor16LittleTo8(source[0]); +} + +void unpackARGB16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16BigTo8(source[1]); + destination[1] = convertColor16BigTo8(source[2]); + destination[2] = convertColor16BigTo8(source[3]); + destination[3] = convertColor16BigTo8(source[0]); +} + void unpackBGRA8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = source[2]; @@ -271,6 +335,22 @@ void unpackBGRA8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = source[3]; } +void unpackBGRA16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16LittleTo8(source[2]); + destination[1] = convertColor16LittleTo8(source[1]); + destination[2] = convertColor16LittleTo8(source[0]); + destination[3] = convertColor16LittleTo8(source[3]); +} + +void unpackBGRA16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16BigTo8(source[2]); + destination[1] = convertColor16BigTo8(source[1]); + destination[2] = convertColor16BigTo8(source[0]); + destination[3] = convertColor16BigTo8(source[3]); +} + void unpackRGBA5551ToRGBA8(const uint16_t* source, uint8_t* destination) { uint16_t packedValue = source[0]; @@ -316,6 +396,22 @@ void unpackR8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = 0xFF; } +void unpackR16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16LittleTo8(source[0]); + destination[1] = convertColor16LittleTo8(source[0]); + destination[2] = convertColor16LittleTo8(source[0]); + destination[3] = 0xFF; +} + +void unpackR16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16BigTo8(source[0]); + destination[1] = convertColor16BigTo8(source[0]); + destination[2] = convertColor16BigTo8(source[0]); + destination[3] = 0xFF; +} + void unpackRA8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = source[0]; @@ -324,6 +420,22 @@ void unpackRA8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = source[1]; } +void unpackRA16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16LittleTo8(source[0]); + destination[1] = convertColor16LittleTo8(source[0]); + destination[2] = convertColor16LittleTo8(source[0]); + destination[3] = convertColor16LittleTo8(source[1]); +} + +void unpackRA16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16BigTo8(source[0]); + destination[1] = convertColor16BigTo8(source[0]); + destination[2] = convertColor16BigTo8(source[0]); + destination[3] = convertColor16BigTo8(source[1]); +} + void unpackAR8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = source[1]; @@ -332,6 +444,22 @@ void unpackAR8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = source[0]; } +void unpackAR16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16LittleTo8(source[1]); + destination[1] = convertColor16LittleTo8(source[1]); + destination[2] = convertColor16LittleTo8(source[1]); + destination[3] = convertColor16LittleTo8(source[0]); +} + +void unpackAR16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = convertColor16BigTo8(source[1]); + destination[1] = convertColor16BigTo8(source[1]); + destination[2] = convertColor16BigTo8(source[1]); + destination[3] = convertColor16BigTo8(source[0]); +} + void unpackA8ToRGBA8(const uint8_t* source, uint8_t* destination) { destination[0] = 0x0; @@ -340,6 +468,22 @@ void unpackA8ToRGBA8(const uint8_t* source, uint8_t* destination) destination[3] = source[0]; } +void unpackA16LittleToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = 0x0; + destination[1] = 0x0; + destination[2] = 0x0; + destination[3] = convertColor16LittleTo8(source[0]); +} + +void unpackA16BigToRGBA8(const uint16_t* source, uint8_t* destination) +{ + destination[0] = 0x0; + destination[1] = 0x0; + destination[2] = 0x0; + destination[3] = convertColor16BigTo8(source[0]); +} + //---------------------------------------------------------------------- // Pixel packing routines. // @@ -602,6 +746,7 @@ static void computeIncrementParameters(unsigned int width, { unsigned int elementSizeInBytes = sizeof(SourceType); ASSERT(elementSizeInBytes <= bytesPerPixel); + ASSERT(!(bytesPerPixel % elementSizeInBytes)); unsigned int validRowBytes = width * bytesPerPixel; unsigned int totalRowBytes = validRowBytes; if (unpackAlignment) { @@ -644,24 +789,72 @@ static void doPacking(const void* sourceData, } break; } + case GraphicsContext3D::kSourceFormatRGBA16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackRGBA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatRGBA16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackRGBA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatRGB8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 3, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); doUnpackingAndPacking<uint8_t, DestType, unpackRGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatRGB16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackRGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatRGB16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 6, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackRGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatARGB8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); doUnpackingAndPacking<uint8_t, DestType, unpackARGB8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatARGB16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackARGB16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatARGB16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackARGB16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatBGRA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); doUnpackingAndPacking<uint8_t, DestType, unpackBGRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatBGRA16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackBGRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatBGRA16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 8, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackBGRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatRGBA5551: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); @@ -686,24 +879,72 @@ static void doPacking(const void* sourceData, doUnpackingAndPacking<uint8_t, DestType, unpackR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatR16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatR16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatRA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); doUnpackingAndPacking<uint8_t, DestType, unpackRA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatRA16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackRA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatRA16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackRA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatAR8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); doUnpackingAndPacking<uint8_t, DestType, unpackAR8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatAR16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackAR16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatAR16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 4, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackAR16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } case GraphicsContext3D::kSourceFormatA8: { unsigned int sourceElementsPerPixel, sourceElementsPerRow; computeIncrementParameters<uint8_t>(width, 1, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); doUnpackingAndPacking<uint8_t, DestType, unpackA8ToRGBA8, packingFunc>(static_cast<const uint8_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); break; } + case GraphicsContext3D::kSourceFormatA16Little: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackA16LittleToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } + case GraphicsContext3D::kSourceFormatA16Big: { + unsigned int sourceElementsPerPixel, sourceElementsPerRow; + computeIncrementParameters<uint16_t>(width, 2, sourceUnpackAlignment, &sourceElementsPerPixel, &sourceElementsPerRow); + doUnpackingAndPacking<uint16_t, DestType, unpackA16BigToRGBA8, packingFunc>(static_cast<const uint16_t*>(sourceData), width, height, sourceElementsPerPixel, sourceElementsPerRow, destinationData, destinationElementsPerPixel); + break; + } } } diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h index a12b1c4..d74c97c 100644 --- a/WebCore/platform/graphics/GraphicsContext3D.h +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -26,16 +26,12 @@ #ifndef GraphicsContext3D_h #define GraphicsContext3D_h -#if PLATFORM(MAC) -#include "ANGLEWebKitBridge.h" -#endif #include "GraphicsLayer.h" #include "PlatformString.h" #include <wtf/HashMap.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) && OS(WINDOWS)) || PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS))) @@ -43,6 +39,7 @@ #endif #if PLATFORM(MAC) +#include "ANGLEWebKitBridge.h" #include <OpenGL/OpenGL.h> #include <wtf/RetainPtr.h> @@ -78,6 +75,7 @@ const Platform3DObject NullPlatform3DObject = 0; namespace WebCore { class CanvasRenderingContext; +class DrawingBuffer; class HostWindow; class Image; class ImageData; @@ -94,7 +92,7 @@ struct ActiveInfo { class GraphicsContext3DInternal; #endif -class GraphicsContext3D : public Noncopyable { +class GraphicsContext3D : public RefCounted<GraphicsContext3D> { public: enum WebGLEnumType { DEPTH_BUFFER_BIT = 0x00000100, @@ -409,7 +407,13 @@ public: // GL_CHROMIUM_map_sub (enums inherited from GL_ARB_vertex_buffer_object) READ_ONLY = 0x88B8, - WRITE_ONLY = 0x88B9 + WRITE_ONLY = 0x88B9, + + // GL_ARB_robustness enums + GUILTY_CONTEXT_RESET_ARB = 0x8253, + INNOCENT_CONTEXT_RESET_ARB = 0x8254, + UNKNOWN_CONTEXT_RESET_ARB = 0x8255 + }; // Context creation attributes. @@ -435,8 +439,8 @@ public: RenderDirectlyToHostWindow }; - static PassOwnPtr<GraphicsContext3D> create(Attributes attrs, HostWindow* hostWindow, RenderStyle renderStyle = RenderOffscreen); - virtual ~GraphicsContext3D(); + static PassRefPtr<GraphicsContext3D> create(Attributes, HostWindow*, RenderStyle = RenderOffscreen); + ~GraphicsContext3D(); #if PLATFORM(MAC) PlatformGraphicsContext3D platformGraphicsContext3D() const { return m_contextObj; } @@ -463,6 +467,8 @@ public: #endif void makeContextCurrent(); + PassRefPtr<DrawingBuffer> createDrawingBuffer(const IntSize& = IntSize()); + #if PLATFORM(MAC) || PLATFORM(CHROMIUM) // With multisampling on, blit from multisampleFBO to regular FBO. void prepareTexture(); @@ -535,16 +541,32 @@ public: // by non-member functions. enum SourceDataFormat { kSourceFormatRGBA8, + kSourceFormatRGBA16Little, + kSourceFormatRGBA16Big, kSourceFormatRGB8, + kSourceFormatRGB16Little, + kSourceFormatRGB16Big, kSourceFormatBGRA8, + kSourceFormatBGRA16Little, + kSourceFormatBGRA16Big, kSourceFormatARGB8, + kSourceFormatARGB16Little, + kSourceFormatARGB16Big, kSourceFormatRGBA5551, kSourceFormatRGBA4444, kSourceFormatRGB565, kSourceFormatR8, + kSourceFormatR16Little, + kSourceFormatR16Big, kSourceFormatRA8, + kSourceFormatRA16Little, + kSourceFormatRA16Big, kSourceFormatAR8, - kSourceFormatA8 + kSourceFormatAR16Little, + kSourceFormatAR16Big, + kSourceFormatA8, + kSourceFormatA16Little, + kSourceFormatA16Big }; //---------------------------------------------------------------------- @@ -777,6 +799,9 @@ public: bool supportsCopyTextureToParentTextureCHROMIUM(); void copyTextureToParentTextureCHROMIUM(unsigned texture, unsigned parentTexture); + // GL_ARB_robustness + int getGraphicsResetStatusARB(); + private: GraphicsContext3D(Attributes attrs, HostWindow* hostWindow, bool renderDirectlyToHostWindow); diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h index 903c7e3..985cad9 100644 --- a/WebCore/platform/graphics/GraphicsContextPrivate.h +++ b/WebCore/platform/graphics/GraphicsContextPrivate.h @@ -39,10 +39,10 @@ namespace WebCore { , strokeStyle(SolidStroke) , strokeThickness(0) , strokeColor(Color::black) - , strokeColorSpace(DeviceColorSpace) + , strokeColorSpace(ColorSpaceDeviceRGB) , fillRule(RULE_NONZERO) , fillColor(Color::black) - , fillColorSpace(DeviceColorSpace) + , fillColorSpace(ColorSpaceDeviceRGB) , shouldAntialias(true) , paintingDisabled(false) , shadowBlur(0) diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index 412f06d..08b79ab 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -33,6 +33,7 @@ #include "RotateTransformOperation.h" #include "TextStream.h" #include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> #ifndef NDEBUG #include <stdio.h> @@ -249,7 +250,7 @@ void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const I String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property) { // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier. - return String::format("-|transition%c-", property); + return makeString("-|transition", static_cast<char>(property), '-'); } void GraphicsLayer::suspendAnimations(double) diff --git a/WebCore/platform/graphics/ImageBuffer.cpp b/WebCore/platform/graphics/ImageBuffer.cpp index 71b8189..4a76be4 100644 --- a/WebCore/platform/graphics/ImageBuffer.cpp +++ b/WebCore/platform/graphics/ImageBuffer.cpp @@ -32,17 +32,17 @@ namespace WebCore { -void ImageBuffer::transformColorSpace(ImageColorSpace srcColorSpace, ImageColorSpace dstColorSpace) +void ImageBuffer::transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace) { if (srcColorSpace == dstColorSpace) return; // only sRGB <-> linearRGB are supported at the moment - if ((srcColorSpace != LinearRGB && srcColorSpace != DeviceRGB) || - (dstColorSpace != LinearRGB && dstColorSpace != DeviceRGB)) + if ((srcColorSpace != ColorSpaceLinearRGB && srcColorSpace != ColorSpaceDeviceRGB) + || (dstColorSpace != ColorSpaceLinearRGB && dstColorSpace != ColorSpaceDeviceRGB)) return; - if (dstColorSpace == LinearRGB) { + if (dstColorSpace == ColorSpaceLinearRGB) { if (m_linearRgbLUT.isEmpty()) { for (unsigned i = 0; i < 256; i++) { float color = i / 255.0f; @@ -53,7 +53,7 @@ void ImageBuffer::transformColorSpace(ImageColorSpace srcColorSpace, ImageColorS } } platformTransformColorSpace(m_linearRgbLUT); - } else if (dstColorSpace == DeviceRGB) { + } else if (dstColorSpace == ColorSpaceDeviceRGB) { if (m_deviceRgbLUT.isEmpty()) { for (unsigned i = 0; i < 256; i++) { float color = i / 255.0f; diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h index 3c0508e..822a0ff 100644 --- a/WebCore/platform/graphics/ImageBuffer.h +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -29,6 +29,7 @@ #define ImageBuffer_h #include "AffineTransform.h" +#include "ColorSpace.h" #include "FloatRect.h" #include "Image.h" #include "IntSize.h" @@ -44,13 +45,6 @@ namespace WebCore { class ImageData; class IntPoint; class IntRect; - - enum ImageColorSpace { - Unknown, - DeviceRGB, // like sRGB - GrayScale, - LinearRGB - }; enum Multiply { Premultiplied, @@ -60,7 +54,7 @@ namespace WebCore { class ImageBuffer : public Noncopyable { public: // Will return a null pointer on allocation failure. - static PassOwnPtr<ImageBuffer> create(const IntSize& size, ImageColorSpace colorSpace = DeviceRGB) + static PassOwnPtr<ImageBuffer> create(const IntSize& size, ColorSpace colorSpace = ColorSpaceDeviceRGB) { bool success = false; OwnPtr<ImageBuffer> buf(new ImageBuffer(size, colorSpace, success)); @@ -89,7 +83,7 @@ namespace WebCore { String toDataURL(const String& mimeType, const double* quality = 0) const; #if !PLATFORM(CG) AffineTransform baseTransform() const { return AffineTransform(); } - void transformColorSpace(ImageColorSpace srcColorSpace, ImageColorSpace dstColorSpace); + void transformColorSpace(ColorSpace srcColorSpace, ColorSpace dstColorSpace); void platformTransformColorSpace(const Vector<int>&); #else AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, m_size.height()); } @@ -119,7 +113,7 @@ namespace WebCore { // This constructor will place its success into the given out-variable // so that create() knows when it should return failure. - ImageBuffer(const IntSize&, ImageColorSpace colorSpace, bool& success); + ImageBuffer(const IntSize&, ColorSpace colorSpace, bool& success); }; } // namespace WebCore diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h index c5990ef..c8d7c71 100644 --- a/WebCore/platform/graphics/IntRect.h +++ b/WebCore/platform/graphics/IntRect.h @@ -56,6 +56,8 @@ typedef cairo_rectangle_int_t GdkRectangle; #endif #elif PLATFORM(HAIKU) class BRect; +#elif PLATFORM(EFL) +typedef struct _Eina_Rectangle Eina_Rectangle; #endif #if PLATFORM(WX) @@ -158,6 +160,9 @@ public: #elif PLATFORM(HAIKU) explicit IntRect(const BRect&); operator BRect() const; +#elif PLATFORM(EFL) + explicit IntRect(const Eina_Rectangle&); + operator Eina_Rectangle() const; #endif #if PLATFORM(CG) diff --git a/WebCore/platform/graphics/Path.cpp b/WebCore/platform/graphics/Path.cpp index 4e2de53..55760b1 100644 --- a/WebCore/platform/graphics/Path.cpp +++ b/WebCore/platform/graphics/Path.cpp @@ -35,8 +35,9 @@ #include <math.h> #include <wtf/MathExtras.h> -static const float QUARTER = 0.552f; // approximation of control point positions on a bezier - // to simulate a quarter of a circle. +// Approximation of control point positions on a bezier to simulate a quarter of a circle. +static const float gCircleControlPoint = 0.448f; + namespace WebCore { #if !PLATFORM(OPENVG) && !PLATFORM(QT) @@ -47,7 +48,7 @@ static void pathLengthApplierFunction(void* info, const PathElement* element) return; traversalState.m_previous = traversalState.m_current; FloatPoint* points = element->points; - float segmentLength = 0.0f; + float segmentLength = 0; switch (element->type) { case PathElementMoveToPoint: segmentLength = traversalState.moveTo(points[0]); @@ -75,10 +76,8 @@ static void pathLengthApplierFunction(void* info, const PathElement* element) if (traversalState.m_action == PathTraversalState::TraversalPointAtLength) { float offset = traversalState.m_desiredLength - traversalState.m_totalLength; traversalState.m_current.move(offset * cosf(slope), offset * sinf(slope)); - } else { - static const float rad2deg = 180.0f / piFloat; - traversalState.m_normalAngle = slope * rad2deg; - } + } else + traversalState.m_normalAngle = rad2deg(slope); traversalState.m_success = true; } @@ -110,167 +109,83 @@ float Path::normalAngleAtLength(float length, bool& ok) } #endif -Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& roundingRadii) +void Path::addRoundedRect(const FloatRect& rect, const FloatSize& roundingRadii) { - Path path; - float x = rectangle.x(); - float y = rectangle.y(); - float width = rectangle.width(); - float height = rectangle.height(); - float rx = roundingRadii.width(); - float ry = roundingRadii.height(); - if (width <= 0.0f || height <= 0.0f) - return path; + if (rect.isEmpty()) + return; + + FloatSize radius(roundingRadii); + FloatSize halfSize(rect.width() / 2, rect.height() / 2); - float dx = rx, dy = ry; // If rx is greater than half of the width of the rectangle // then set rx to half of the width (required in SVG spec) - if (dx > width * 0.5f) - dx = width * 0.5f; + if (radius.width() > halfSize.width()) + radius.setWidth(halfSize.width()); // If ry is greater than half of the height of the rectangle // then set ry to half of the height (required in SVG spec) - if (dy > height * 0.5f) - dy = height * 0.5f; + if (radius.height() > halfSize.height()) + radius.setHeight(halfSize.height()); - path.moveTo(FloatPoint(x + dx, y)); + moveTo(FloatPoint(rect.x() + radius.width(), rect.y())); - if (dx < width * 0.5f) - path.addLineTo(FloatPoint(x + width - rx, y)); + if (radius.width() < halfSize.width()) + addLineTo(FloatPoint(rect.x() + rect.width() - roundingRadii.width(), rect.y())); - path.addBezierCurveTo(FloatPoint(x + width - dx * (1 - QUARTER), y), FloatPoint(x + width, y + dy * (1 - QUARTER)), FloatPoint(x + width, y + dy)); + addBezierCurveTo(FloatPoint(rect.x() + rect.width() - radius.width() * gCircleControlPoint, rect.y()), FloatPoint(rect.x() + rect.width(), rect.y() + radius.height() * gCircleControlPoint), FloatPoint(rect.x() + rect.width(), rect.y() + radius.height())); - if (dy < height * 0.5) - path.addLineTo(FloatPoint(x + width, y + height - dy)); + if (radius.height() < halfSize.height()) + addLineTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - radius.height())); - path.addBezierCurveTo(FloatPoint(x + width, y + height - dy * (1 - QUARTER)), FloatPoint(x + width - dx * (1 - QUARTER), y + height), FloatPoint(x + width - dx, y + height)); + addBezierCurveTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - radius.height() * gCircleControlPoint), FloatPoint(rect.x() + rect.width() - radius.width() * gCircleControlPoint, rect.y() + rect.height()), FloatPoint(rect.x() + rect.width() - radius.width(), rect.y() + rect.height())); - if (dx < width * 0.5) - path.addLineTo(FloatPoint(x + dx, y + height)); + if (radius.width() < halfSize.width()) + addLineTo(FloatPoint(rect.x() + radius.width(), rect.y() + rect.height())); - path.addBezierCurveTo(FloatPoint(x + dx * (1 - QUARTER), y + height), FloatPoint(x, y + height - dy * (1 - QUARTER)), FloatPoint(x, y + height - dy)); + addBezierCurveTo(FloatPoint(rect.x() + radius.width() * gCircleControlPoint, rect.y() + rect.height()), FloatPoint(rect.x(), rect.y() + rect.height() - radius.height() * gCircleControlPoint), FloatPoint(rect.x(), rect.y() + rect.height() - radius.height())); - if (dy < height * 0.5) - path.addLineTo(FloatPoint(x, y + dy)); + if (radius.height() < halfSize.height()) + addLineTo(FloatPoint(rect.x(), rect.y() + radius.height())); - path.addBezierCurveTo(FloatPoint(x, y + dy * (1 - QUARTER)), FloatPoint(x + dx * (1 - QUARTER), y), FloatPoint(x + dx, y)); + addBezierCurveTo(FloatPoint(rect.x(), rect.y() + radius.height() * gCircleControlPoint), FloatPoint(rect.x() + radius.width() * gCircleControlPoint, rect.y()), FloatPoint(rect.x() + radius.width(), rect.y())); - path.closeSubpath(); - - return path; + closeSubpath(); } -Path Path::createRoundedRectangle(const FloatRect& rectangle, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius) +void Path::addRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius) { - Path path; - - float width = rectangle.width(); - float height = rectangle.height(); - if (width <= 0.0 || height <= 0.0) - return path; + if (rect.isEmpty()) + return; - if (width < topLeftRadius.width() + topRightRadius.width() - || width < bottomLeftRadius.width() + bottomRightRadius.width() - || height < topLeftRadius.height() + bottomLeftRadius.height() - || height < topRightRadius.height() + bottomRightRadius.height()) + if (rect.width() < topLeftRadius.width() + topRightRadius.width() + || rect.width() < bottomLeftRadius.width() + bottomRightRadius.width() + || rect.height() < topLeftRadius.height() + bottomLeftRadius.height() + || rect.height() < topRightRadius.height() + bottomRightRadius.height()) { // If all the radii cannot be accommodated, return a rect. - return createRectangle(rectangle); - - float x = rectangle.x(); - float y = rectangle.y(); - - path.moveTo(FloatPoint(x + topLeftRadius.width(), y)); - - path.addLineTo(FloatPoint(x + width - topRightRadius.width(), y)); - - path.addBezierCurveTo(FloatPoint(x + width - topRightRadius.width() * (1 - QUARTER), y), FloatPoint(x + width, y + topRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width, y + topRightRadius.height())); - - path.addLineTo(FloatPoint(x + width, y + height - bottomRightRadius.height())); - - path.addBezierCurveTo(FloatPoint(x + width, y + height - bottomRightRadius.height() * (1 - QUARTER)), FloatPoint(x + width - bottomRightRadius.width() * (1 - QUARTER), y + height), FloatPoint(x + width - bottomRightRadius.width(), y + height)); - - path.addLineTo(FloatPoint(x + bottomLeftRadius.width(), y + height)); - - path.addBezierCurveTo(FloatPoint(x + bottomLeftRadius.width() * (1 - QUARTER), y + height), FloatPoint(x, y + height - bottomLeftRadius.height() * (1 - QUARTER)), FloatPoint(x, y + height - bottomLeftRadius.height())); - - path.addLineTo(FloatPoint(x, y + topLeftRadius.height())); - - path.addBezierCurveTo(FloatPoint(x, y + topLeftRadius.height() * (1 - QUARTER)), FloatPoint(x + topLeftRadius.width() * (1 - QUARTER), y), FloatPoint(x + topLeftRadius.width(), y)); - - path.closeSubpath(); - - return path; -} - -Path Path::createRectangle(const FloatRect& rectangle) -{ - Path path; - float x = rectangle.x(); - float y = rectangle.y(); - float width = rectangle.width(); - float height = rectangle.height(); - if (width <= 0.0f || height <= 0.0f) - return path; - - path.moveTo(FloatPoint(x, y)); - path.addLineTo(FloatPoint(x + width, y)); - path.addLineTo(FloatPoint(x + width, y + height)); - path.addLineTo(FloatPoint(x, y + height)); - path.closeSubpath(); - - return path; -} - -Path Path::createEllipse(const FloatPoint& center, float rx, float ry) -{ - float cx = center.x(); - float cy = center.y(); - Path path; - if (rx <= 0.0f || ry <= 0.0f) - return path; - - float x = cx; - float y = cy; - - unsigned step = 0, num = 100; - bool running = true; - while (running) - { - if (step == num) - { - running = false; - break; - } - - float angle = static_cast<float>(step) / static_cast<float>(num) * 2.0f * piFloat; - x = cx + cosf(angle) * rx; - y = cy + sinf(angle) * ry; - - step++; - if (step == 1) - path.moveTo(FloatPoint(x, y)); - else - path.addLineTo(FloatPoint(x, y)); + addRect(rect); + return; } - path.closeSubpath(); - - return path; -} - -Path Path::createCircle(const FloatPoint& center, float r) -{ - return createEllipse(center, r, r); -} - -Path Path::createLine(const FloatPoint& start, const FloatPoint& end) -{ - Path path; - - path.moveTo(start); - path.addLineTo(end); - - return path; + moveTo(FloatPoint(rect.x() + topLeftRadius.width(), rect.y())); + + addLineTo(FloatPoint(rect.x() + rect.width() - topRightRadius.width(), rect.y())); + addBezierCurveTo(FloatPoint(rect.x() + rect.width() - topRightRadius.width() * gCircleControlPoint, rect.y()), + FloatPoint(rect.x() + rect.width(), rect.y() + topRightRadius.height() * gCircleControlPoint), + FloatPoint(rect.x() + rect.width(), rect.y() + topRightRadius.height())); + addLineTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - bottomRightRadius.height())); + addBezierCurveTo(FloatPoint(rect.x() + rect.width(), rect.y() + rect.height() - bottomRightRadius.height() * gCircleControlPoint), + FloatPoint(rect.x() + rect.width() - bottomRightRadius.width() * gCircleControlPoint, rect.y() + rect.height()), + FloatPoint(rect.x() + rect.width() - bottomRightRadius.width(), rect.y() + rect.height())); + addLineTo(FloatPoint(rect.x() + bottomLeftRadius.width(), rect.y() + rect.height())); + addBezierCurveTo(FloatPoint(rect.x() + bottomLeftRadius.width() * gCircleControlPoint, rect.y() + rect.height()), + FloatPoint(rect.x(), rect.y() + rect.height() - bottomLeftRadius.height() * gCircleControlPoint), + FloatPoint(rect.x(), rect.y() + rect.height() - bottomLeftRadius.height())); + addLineTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height())); + addBezierCurveTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height() * gCircleControlPoint), + FloatPoint(rect.x() + topLeftRadius.width() * gCircleControlPoint, rect.y()), + FloatPoint(rect.x() + topLeftRadius.width(), rect.y())); + + closeSubpath(); } } diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index 43ba889..86ba831 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -137,20 +137,13 @@ namespace WebCore { void addArc(const FloatPoint&, float radius, float startAngle, float endAngle, bool anticlockwise); void addRect(const FloatRect&); void addEllipse(const FloatRect&); + void addRoundedRect(const FloatRect&, const FloatSize& roundingRadii); + void addRoundedRect(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); void translate(const FloatSize&); - String debugString() const; - PlatformPathPtr platformPath() const { return m_path; } - static Path createRoundedRectangle(const FloatRect&, const FloatSize& roundingRadii); - static Path createRoundedRectangle(const FloatRect&, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius); - static Path createRectangle(const FloatRect&); - static Path createEllipse(const FloatPoint& center, float rx, float ry); - static Path createCircle(const FloatPoint& center, float r); - static Path createLine(const FloatPoint&, const FloatPoint&); - void apply(void* info, PathApplierFunction) const; void transform(const AffineTransform&); diff --git a/WebCore/platform/graphics/brew/ImageBrew.cpp b/WebCore/platform/graphics/brew/ImageBrew.cpp index f5c855d..b574b0a 100644 --- a/WebCore/platform/graphics/brew/ImageBrew.cpp +++ b/WebCore/platform/graphics/brew/ImageBrew.cpp @@ -36,13 +36,13 @@ #include "SharedBuffer.h" #include <wtf/text/CString.h> -#include <wtf/text/WTFString.h> +#include <wtf/text/StringConcatenate.h> namespace WebCore { PassRefPtr<Image> Image::loadPlatformResource(const char *name) { - String resourcePath = homeDirectoryPath() + String::format("res/%s.png", name); + String resourcePath = makeString(homeDirectoryPath(), "res/", name, ".png"); RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(resourcePath.utf8().data()); if (!buffer) diff --git a/WebCore/platform/graphics/cairo/CairoUtilities.cpp b/WebCore/platform/graphics/cairo/CairoUtilities.cpp index 8c2049f..7af5577 100644 --- a/WebCore/platform/graphics/cairo/CairoUtilities.cpp +++ b/WebCore/platform/graphics/cairo/CairoUtilities.cpp @@ -26,8 +26,15 @@ #include "config.h" #include "CairoUtilities.h" +#include "AffineTransform.h" +#include "CairoPath.h" #include "Color.h" -#include <cairo.h> +#include "FloatPoint.h" +#include "FloatRect.h" +#include "IntRect.h" +#include "OwnPtrCairo.h" +#include "Path.h" +#include "PlatformRefPtrCairo.h" #include <wtf/Vector.h> namespace WebCore { @@ -56,4 +63,96 @@ void setSourceRGBAFromColor(cairo_t* context, const Color& color) cairo_set_source_rgba(context, red, green, blue, alpha); } +void appendPathToCairoContext(cairo_t* to, cairo_t* from) +{ + OwnPtr<cairo_path_t> cairoPath(cairo_copy_path(from)); + cairo_append_path(to, cairoPath.get()); +} + +void setPathOnCairoContext(cairo_t* to, cairo_t* from) +{ + cairo_new_path(to); + appendPathToCairoContext(to, from); +} + +void appendWebCorePathToCairoContext(cairo_t* context, const Path& path) +{ + appendPathToCairoContext(context, path.platformPath()->context()); +} + +cairo_operator_t toCairoOperator(CompositeOperator op) +{ + switch (op) { + case CompositeClear: + return CAIRO_OPERATOR_CLEAR; + case CompositeCopy: + return CAIRO_OPERATOR_SOURCE; + case CompositeSourceOver: + return CAIRO_OPERATOR_OVER; + case CompositeSourceIn: + return CAIRO_OPERATOR_IN; + case CompositeSourceOut: + return CAIRO_OPERATOR_OUT; + case CompositeSourceAtop: + return CAIRO_OPERATOR_ATOP; + case CompositeDestinationOver: + return CAIRO_OPERATOR_DEST_OVER; + case CompositeDestinationIn: + return CAIRO_OPERATOR_DEST_IN; + case CompositeDestinationOut: + return CAIRO_OPERATOR_DEST_OUT; + case CompositeDestinationAtop: + return CAIRO_OPERATOR_DEST_ATOP; + case CompositeXOR: + return CAIRO_OPERATOR_XOR; + case CompositePlusDarker: + return CAIRO_OPERATOR_SATURATE; + case CompositeHighlight: + // There is no Cairo equivalent for CompositeHighlight. + return CAIRO_OPERATOR_OVER; + case CompositePlusLighter: + return CAIRO_OPERATOR_ADD; + default: + return CAIRO_OPERATOR_SOURCE; + } +} + +void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect, + const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect) +{ + // Avoid NaN + if (!isfinite(phase.x()) || !isfinite(phase.y())) + return; + + cairo_save(cr); + + PlatformRefPtr<cairo_surface_t> clippedImageSurface = 0; + if (tileRect.size() != imageSize) { + IntRect imageRect = enclosingIntRect(tileRect); + clippedImageSurface = adoptPlatformRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height())); + PlatformRefPtr<cairo_t> clippedImageContext(cairo_create(clippedImageSurface.get())); + cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y()); + cairo_paint(clippedImageContext.get()); + image = clippedImageSurface.get(); + } + + cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + + cairo_matrix_t patternMatrix = cairo_matrix_t(patternTransform); + cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()}; + cairo_matrix_t combined; + cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix); + cairo_matrix_invert(&combined); + cairo_pattern_set_matrix(pattern, &combined); + + cairo_set_operator(cr, op); + cairo_set_source(cr, pattern); + cairo_pattern_destroy(pattern); + cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height()); + cairo_fill(cr); + + cairo_restore(cr); +} + } // namespace WebCore diff --git a/WebCore/platform/graphics/cairo/CairoUtilities.h b/WebCore/platform/graphics/cairo/CairoUtilities.h index 0675b90..d8fff8d 100644 --- a/WebCore/platform/graphics/cairo/CairoUtilities.h +++ b/WebCore/platform/graphics/cairo/CairoUtilities.h @@ -26,13 +26,25 @@ #ifndef CairoUtilities_h #define CairoUtilities_h -typedef struct _cairo cairo_t; +#include <GraphicsTypes.h> +#include <cairo.h> namespace WebCore { +class AffineTransform; class Color; +class FloatRect; +class FloatPoint; +class IntSize; +class Path; void copyContextProperties(cairo_t* srcCr, cairo_t* dstCr); void setSourceRGBAFromColor(cairo_t*, const Color&); +void appendPathToCairoContext(cairo_t* to, cairo_t* from); +void setPathOnCairoContext(cairo_t* to, cairo_t* from); +void appendWebCorePathToCairoContext(cairo_t* context, const Path& path); +cairo_operator_t toCairoOperator(CompositeOperator op); +void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect, + const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect); } // namespace WebCore diff --git a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp index 4b94cb3..8299b6a 100644 --- a/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp +++ b/WebCore/platform/graphics/cairo/ContextShadowCairo.cpp @@ -29,10 +29,15 @@ #include "config.h" #include "ContextShadow.h" +#include "AffineTransform.h" #include "CairoUtilities.h" +#include "OwnPtrCairo.h" +#include "Path.h" #include "Timer.h" #include <cairo.h> +using WTF::max; + namespace WebCore { static cairo_surface_t* scratchBuffer = 0; @@ -105,10 +110,13 @@ void ContextShadow::endShadowLayer(cairo_t* cr) cairo_destroy(m_layerContext); m_layerContext = 0; - if (m_type == BlurShadow) + if (m_type == BlurShadow) { + cairo_surface_flush(m_layerImage); blurLayerImage(cairo_image_surface_get_data(m_layerImage), IntSize(cairo_image_surface_get_width(m_layerImage), cairo_image_surface_get_height(m_layerImage)), cairo_image_surface_get_stride(m_layerImage)); + cairo_surface_mark_dirty(m_layerImage); + } cairo_save(cr); setSourceRGBAFromColor(cr, m_color); @@ -119,4 +127,223 @@ void ContextShadow::endShadowLayer(cairo_t* cr) scheduleScratchBufferPurge(); } +void ContextShadow::drawRectShadowWithoutTiling(PlatformContext context, const IntRect& shadowRect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius, float alpha) +{ + beginShadowLayer(context, shadowRect); + + if (!m_layerContext) + return; + + Path path; + path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + + appendWebCorePathToCairoContext(m_layerContext, path); + cairo_set_source_rgba(m_layerContext, 0, 0, 0, alpha); + cairo_fill(m_layerContext); + + endShadowLayer(context); +} + +static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile) +{ + FloatPoint phase = dest.location(); + phase.move(-tile.x(), -tile.y()); + + return phase; +} + +/* + This function uses tiling to improve the performance of the shadow + drawing of rounded rectangles. The code basically does the following + steps: + + 1. Calculate the size of the shadow template, a rectangle that + contains all the necessary tiles to draw the complete shadow. + + 2. If that size is smaller than the real rectangle render the new + template rectangle and its shadow in a new surface, in other case + render the shadow of the real rectangle in the destination + surface. + + 3. Calculate the sizes and positions of the tiles and their + destinations and use drawPattern to render the final shadow. The + code divides the rendering in 8 tiles: + + 1 | 2 | 3 + ----------- + 4 | | 5 + ----------- + 6 | 7 | 8 + + The corners are directly copied from the template rectangle to the + real one and the side tiles are 1 pixel width, we use them as + + tiles to cover the destination side. The corner tiles are bigger + than just the side of the rounded corner, we need to increase it + because the modifications caused by the corner over the blur + effect. We fill the central part with solid color to complete the + shadow. + */ +void ContextShadow::drawRectShadow(GraphicsContext* context, const IntRect& rect, const IntSize& topLeftRadius, const IntSize& topRightRadius, const IntSize& bottomLeftRadius, const IntSize& bottomRightRadius) +{ + + // drawShadowedRect still does not work with rotations. + // https://bugs.webkit.org/show_bug.cgi?id=45042 + float radiusTwice = m_blurDistance * 2; + cairo_t* cr = context->platformContext(); + if ((!context->getCTM().isIdentityOrTranslationOrFlipped()) || (radiusTwice > rect.width()) + || (radiusTwice > rect.height()) || (m_type != BlurShadow)) { + drawRectShadowWithoutTiling(cr, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha()); + return; + } + + // Calculate size of the template shadow buffer. + IntSize shadowBufferSize = IntSize(rect.width() + radiusTwice, rect.height() + radiusTwice); + + // Determine dimensions of shadow rect. + FloatRect shadowRect = FloatRect(rect.location(), shadowBufferSize); + shadowRect.move(- m_blurDistance, - m_blurDistance); + + // Size of the tiling side. + int sideTileWidth = 1; + + // Find the extra space needed from the curve of the corners. + int extraWidthFromCornerRadii = radiusTwice + max(topLeftRadius.width(), bottomLeftRadius.width()) + + radiusTwice + max(topRightRadius.width(), bottomRightRadius.width()); + int extraHeightFromCornerRadii = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) + + radiusTwice + max(bottomLeftRadius.height(), bottomRightRadius.height()); + + // The length of a side of the buffer is the enough space for four blur radii, + // the radii of the corners, and then 1 pixel to draw the side tiles. + IntSize shadowTemplateSize = IntSize(sideTileWidth + extraWidthFromCornerRadii, + sideTileWidth + extraHeightFromCornerRadii); + + // Reduce the size of what we have to draw with the clip area. + double x1, x2, y1, y2; + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + calculateLayerBoundingRect(shadowRect, IntRect(x1, y1, x2 - x1, y2 - y1)); + + if ((shadowTemplateSize.width() * shadowTemplateSize.height() > m_layerRect.width() * m_layerRect.height())) { + drawRectShadowWithoutTiling(cr, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius, context->getAlpha()); + return; + } + + shadowRect.move(m_offset.width(), m_offset.height()); + + m_layerImage = getScratchBuffer(shadowTemplateSize); + + // Draw shadow into a new ImageBuffer. + m_layerContext = cairo_create(m_layerImage); + + // Clear the surface first. + cairo_set_operator(m_layerContext, CAIRO_OPERATOR_CLEAR); + cairo_paint(m_layerContext); + cairo_set_operator(m_layerContext, CAIRO_OPERATOR_OVER); + + // Draw the rectangle. + IntRect templateRect = IntRect(m_blurDistance, m_blurDistance, shadowTemplateSize.width() - radiusTwice, shadowTemplateSize.height() - radiusTwice); + Path path; + path.addRoundedRect(templateRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + appendWebCorePathToCairoContext(m_layerContext, path); + + cairo_set_source_rgba(m_layerContext, 0, 0, 0, context->getAlpha()); + cairo_fill(m_layerContext); + + // Blur the image. + cairo_surface_flush(m_layerImage); + blurLayerImage(cairo_image_surface_get_data(m_layerImage), shadowTemplateSize, cairo_image_surface_get_stride(m_layerImage)); + cairo_surface_mark_dirty(m_layerImage); + + // Mask the image with the shadow color. + cairo_set_operator(m_layerContext, CAIRO_OPERATOR_IN); + setSourceRGBAFromColor(m_layerContext, m_color); + cairo_paint(m_layerContext); + + cairo_destroy(m_layerContext); + m_layerContext = 0; + + // Fill the internal part of the shadow. + shadowRect.inflate(-radiusTwice); + if (!shadowRect.isEmpty()) { + cairo_save(cr); + path.clear(); + path.addRoundedRect(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + appendWebCorePathToCairoContext(cr, path); + setSourceRGBAFromColor(cr, m_color); + cairo_fill(cr); + cairo_restore(cr); + } + shadowRect.inflate(radiusTwice); + + // Draw top side. + FloatRect tileRect = FloatRect(radiusTwice + topLeftRadius.width(), 0, sideTileWidth, radiusTwice); + FloatRect destRect = tileRect; + destRect.move(shadowRect.x(), shadowRect.y()); + destRect.setWidth(shadowRect.width() - topLeftRadius.width() - topRightRadius.width() - m_blurDistance * 4); + FloatPoint phase = getPhase(destRect, tileRect); + AffineTransform patternTransform; + patternTransform.makeIdentity(); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Draw the bottom side. + tileRect = FloatRect(radiusTwice + bottomLeftRadius.width(), shadowTemplateSize.height() - radiusTwice, sideTileWidth, radiusTwice); + destRect = tileRect; + destRect.move(shadowRect.x(), shadowRect.y() + radiusTwice + rect.height() - shadowTemplateSize.height()); + destRect.setWidth(shadowRect.width() - bottomLeftRadius.width() - bottomRightRadius.width() - m_blurDistance * 4); + phase = getPhase(destRect, tileRect); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Draw the right side. + tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice, radiusTwice + topRightRadius.height(), radiusTwice, sideTileWidth); + destRect = tileRect; + destRect.move(shadowRect.x() + radiusTwice + rect.width() - shadowTemplateSize.width(), shadowRect.y()); + destRect.setHeight(shadowRect.height() - topRightRadius.height() - bottomRightRadius.height() - m_blurDistance * 4); + phase = getPhase(destRect, tileRect); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Draw the left side. + tileRect = FloatRect(0, radiusTwice + topLeftRadius.height(), radiusTwice, sideTileWidth); + destRect = tileRect; + destRect.move(shadowRect.x(), shadowRect.y()); + destRect.setHeight(shadowRect.height() - topLeftRadius.height() - bottomLeftRadius.height() - m_blurDistance * 4); + phase = FloatPoint(destRect.x() - tileRect.x(), destRect.y() - tileRect.y()); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Draw the top left corner. + tileRect = FloatRect(0, 0, radiusTwice + topLeftRadius.width(), radiusTwice + topLeftRadius.height()); + destRect = tileRect; + destRect.move(shadowRect.x(), shadowRect.y()); + phase = getPhase(destRect, tileRect); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Draw the top right corner. + tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - topRightRadius.width(), 0, radiusTwice + topRightRadius.width(), + radiusTwice + topRightRadius.height()); + destRect = tileRect; + destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice, shadowRect.y()); + phase = getPhase(destRect, tileRect); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Draw the bottom right corner. + tileRect = FloatRect(shadowTemplateSize.width() - radiusTwice - bottomRightRadius.width(), + shadowTemplateSize.height() - radiusTwice - bottomRightRadius.height(), + radiusTwice + bottomRightRadius.width(), radiusTwice + bottomRightRadius.height()); + destRect = tileRect; + destRect.move(shadowRect.x() + rect.width() - shadowTemplateSize.width() + radiusTwice, + shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice); + phase = getPhase(destRect, tileRect); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Draw the bottom left corner. + tileRect = FloatRect(0, shadowTemplateSize.height() - radiusTwice - bottomLeftRadius.height(), + radiusTwice + bottomLeftRadius.width(), radiusTwice + bottomLeftRadius.height()); + destRect = tileRect; + destRect.move(shadowRect.x(), shadowRect.y() + rect.height() - shadowTemplateSize.height() + radiusTwice); + phase = getPhase(destRect, tileRect); + drawPatternToCairoContext(cr, m_layerImage, shadowTemplateSize, tileRect, patternTransform, phase, CAIRO_OPERATOR_OVER, destRect); + + // Schedule a purge of the scratch buffer. + scheduleScratchBufferPurge(); +} + } diff --git a/WebCore/platform/graphics/cairo/FloatRectCairo.cpp b/WebCore/platform/graphics/cairo/FloatRectCairo.cpp new file mode 100644 index 0000000..9f86f74 --- /dev/null +++ b/WebCore/platform/graphics/cairo/FloatRectCairo.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatRect.h" + +#include <cairo.h> + +namespace WebCore { + +FloatRect::FloatRect(const cairo_rectangle_t& r) + : m_location(r.x, r.y) + , m_size(r.width, r.height) +{ +} + +FloatRect::operator cairo_rectangle_t() const +{ + cairo_rectangle_t r = { x(), y(), width(), height() }; + return r; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp b/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp index febad12..5dca010 100644 --- a/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp +++ b/WebCore/platform/graphics/cairo/FontCacheFreeType.cpp @@ -87,12 +87,12 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigne { } -static CString getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family) +static String getFamilyNameStringFromFontDescriptionAndFamily(const FontDescription& fontDescription, const AtomicString& family) { // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the name into // the fallback name (like "monospace") that fontconfig understands. if (family.length() && !family.startsWith("-webkit-")) - return family.string().utf8(); + return family.string(); switch (fontDescription.genericFamily()) { case FontDescription::StandardFamily: @@ -112,23 +112,14 @@ static CString getFamilyNameStringFromFontDescriptionAndFamily(const FontDescrip } } - -static bool isFallbackFontAllowed(const CString& familyName) -{ - return !strcasecmp(familyName.data(), "sans") - || !strcasecmp(familyName.data(), "sans-serif") - || !strcasecmp(familyName.data(), "serif") - || !strcasecmp(familyName.data(), "monospace"); -} - FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) { // The CSS font matching algorithm (http://www.w3.org/TR/css3-fonts/#font-matching-algorithm) // says that we must find an exact match for font family, slant (italic or oblique can be used) // and font weight (we only match bold/non-bold here). PlatformRefPtr<FcPattern> pattern = adoptPlatformRef(FcPatternCreate()); - CString familyNameString = getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family); - if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.data()))) + String familyNameString(getFamilyNameStringFromFontDescriptionAndFamily(fontDescription, family)); + if (!FcPatternAddString(pattern.get(), FC_FAMILY, reinterpret_cast<const FcChar8*>(familyNameString.utf8().data()))) return 0; bool italic = fontDescription.italic(); @@ -140,53 +131,39 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD if (!FcPatternAddDouble(pattern.get(), FC_PIXEL_SIZE, fontDescription.computedPixelSize())) return 0; - // The following comment and strategy are originally from Skia (src/ports/SkFontHost_fontconfig.cpp): - // Font matching: - // CSS often specifies a fallback list of families: - // font-family: a, b, c, serif; - // However, fontconfig will always do its best to find *a* font when asked - // for something so we need a way to tell if the match which it has found is - // "good enough" for us. Otherwise, we can return null which gets piped up - // and lets WebKit know to try the next CSS family name. However, fontconfig - // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we - // wish to support that. - // - // Thus, if a specific family is requested we set @family_requested. Then we - // record two strings: the family name after config processing and the - // family name after resolving. If the two are equal, it's a good match. - // - // So consider the case where a user has mapped Arial to Helvetica in their - // config. - // requested family: "Arial" - // post_config_family: "Helvetica" - // post_match_family: "Helvetica" - // -> good match - // - // and for a missing font: - // requested family: "Monaco" - // post_config_family: "Monaco" - // post_match_family: "Times New Roman" - // -> BAD match - // + // The strategy is originally from Skia (src/ports/SkFontHost_fontconfig.cpp): + + // Allow Fontconfig to do pre-match substitution. Unless we are accessing a "fallback" + // family like "sans," this is the only time we allow Fontconfig to substitute one + // family name for another (i.e. if the fonts are aliased to each other). FcConfigSubstitute(0, pattern.get(), FcMatchPattern); FcDefaultSubstitute(pattern.get()); - FcChar8* familyNameAfterConfiguration; - FcPatternGetString(pattern.get(), FC_FAMILY, 0, &familyNameAfterConfiguration); + FcChar8* fontConfigFamilyNameAfterConfiguration; + FcPatternGetString(pattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterConfiguration); + String familyNameAfterConfiguration = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterConfiguration)); FcResult fontConfigResult; PlatformRefPtr<FcPattern> resultPattern = adoptPlatformRef(FcFontMatch(0, pattern.get(), &fontConfigResult)); if (!resultPattern) // No match. return 0; - // Properly handle the situation where Fontconfig gives us a font that has a different family than we requested. - FcChar8* familyNameAfterMatching; - FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &familyNameAfterMatching); - if (strcasecmp(reinterpret_cast<char*>(familyNameAfterConfiguration), - reinterpret_cast<char*>(familyNameAfterMatching)) && !isFallbackFontAllowed(familyNameString)) - return 0; - - return new FontPlatformData(resultPattern.get(), fontDescription); + FcChar8* fontConfigFamilyNameAfterMatching; + FcPatternGetString(resultPattern.get(), FC_FAMILY, 0, &fontConfigFamilyNameAfterMatching); + String familyNameAfterMatching = String::fromUTF8(reinterpret_cast<char*>(fontConfigFamilyNameAfterMatching)); + if (equalIgnoringCase(familyNameAfterConfiguration, familyNameAfterMatching)) + return new FontPlatformData(resultPattern.get(), fontDescription); + + // If Fontconfig gave use a different font family than the one we requested, we should ignore it + // and allow WebCore to give us the next font on the CSS fallback list. The only exception is if + // this family name is a commonly used generic family. + if (equalIgnoringCase(familyNameString, "sans") || equalIgnoringCase(familyNameString, "sans-serif") + || equalIgnoringCase(familyNameString, "serif") || equalIgnoringCase(familyNameString, "monospace") + || equalIgnoringCase(familyNameString, "fantasy") || equalIgnoringCase(familyNameString, "cursive")) + return new FontPlatformData(resultPattern.get(), fontDescription); + + // Fontconfig did not return a good match. + return 0; } } diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index cd5d362..3d55c70 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -31,6 +31,8 @@ #include "Font.h" #include "AffineTransform.h" +#include "CairoUtilities.h" +#include "ContextShadow.h" #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContext.h" @@ -38,18 +40,63 @@ #include "Pattern.h" #include "SimpleFontData.h" -#define SYNTHETIC_OBLIQUE_ANGLE 14 - namespace WebCore { -void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, - int from, int numGlyphs, const FloatPoint& point) const +static void prepareContextForGlyphDrawing(cairo_t* context, const SimpleFontData* font, const FloatPoint& point) { - cairo_t* cr = context->platformContext(); - cairo_save(cr); + static const float syntheticObliqueSkew = -tanf(14 * acosf(0) / 90); + cairo_set_scaled_font(context, font->platformData().scaledFont()); + if (font->platformData().syntheticOblique()) { + cairo_matrix_t mat = {1, 0, syntheticObliqueSkew, 1, point.x(), point.y()}; + cairo_transform(context, &mat); + } else + cairo_translate(context, point.x(), point.y()); +} - cairo_set_scaled_font(cr, font->platformData().scaledFont()); +static void drawGlyphsToContext(cairo_t* context, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) +{ + cairo_show_glyphs(context, glyphs, numGlyphs); + if (font->syntheticBoldOffset()) { + // We could use cairo_save/cairo_restore here, but two translations are likely faster. + cairo_translate(context, font->syntheticBoldOffset(), 0); + cairo_show_glyphs(context, glyphs, numGlyphs); + cairo_translate(context, -font->syntheticBoldOffset(), 0); + } +} + +static void drawGlyphsShadow(GraphicsContext* graphicsContext, cairo_t* context, const FloatPoint& point, const SimpleFontData* font, GlyphBufferGlyph* glyphs, int numGlyphs) +{ + ContextShadow* shadow = graphicsContext->contextShadow(); + ASSERT(shadow); + + if (!(graphicsContext->textDrawingMode() & cTextFill) || shadow->m_type == ContextShadow::NoShadow) + return; + + if (shadow->m_type == ContextShadow::SolidShadow) { + // Optimize non-blurry shadows, by just drawing text without the ContextShadow. + cairo_save(context); + cairo_translate(context, shadow->m_offset.width(), shadow->m_offset.height()); + setSourceRGBAFromColor(context, shadow->m_color); + prepareContextForGlyphDrawing(context, font, point); + cairo_show_glyphs(context, glyphs, numGlyphs); + cairo_restore(context); + return; + } + + cairo_text_extents_t extents; + cairo_scaled_font_glyph_extents(font->platformData().scaledFont(), glyphs, numGlyphs, &extents); + FloatRect fontExtentsRect(point.x(), point.y() - extents.height, extents.width, extents.height); + cairo_t* shadowContext = shadow->beginShadowLayer(context, fontExtentsRect); + if (shadowContext) { + prepareContextForGlyphDrawing(shadowContext, font, point); + drawGlyphsToContext(shadowContext, font, glyphs, numGlyphs); + shadow->endShadowLayer(context); + } +} +void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, + int from, int numGlyphs, const FloatPoint& point) const +{ GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); float offset = 0.0f; @@ -59,75 +106,11 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons offset += glyphBuffer.advanceAt(from + i); } - Color fillColor = context->fillColor(); - - // Synthetic Oblique - if(font->platformData().syntheticOblique()) { - cairo_matrix_t mat = {1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, point.x(), point.y()}; - cairo_transform(cr, &mat); - } else { - cairo_translate(cr, point.x(), point.y()); - } - - // Text shadow, inspired by FontMac - FloatSize shadowOffset; - float shadowBlur = 0; - Color shadowColor; - bool hasShadow = context->textDrawingMode() & cTextFill - && context->getShadow(shadowOffset, shadowBlur, shadowColor); - - // TODO: Blur support - if (hasShadow) { - // Disable graphics context shadows (not yet implemented) and paint them manually - context->clearShadow(); - Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); - cairo_save(cr); - - float red, green, blue, alpha; - shadowFillColor.getRGBA(red, green, blue, alpha); - cairo_set_source_rgba(cr, red, green, blue, alpha); - -#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 radius = 0; - context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, 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, radius, extents.height + radius); - - 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->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); -#else - cairo_translate(cr, shadowOffset.width(), shadowOffset.height()); - cairo_show_glyphs(cr, glyphs, numGlyphs); - if (font->syntheticBoldOffset()) { - cairo_save(cr); - cairo_translate(cr, font->syntheticBoldOffset(), 0); - cairo_show_glyphs(cr, glyphs, numGlyphs); - cairo_restore(cr); - } -#endif - - cairo_restore(cr); - } + cairo_t* cr = context->platformContext(); + drawGlyphsShadow(context, cr, point, font, glyphs, numGlyphs); + cairo_save(cr); + prepareContextForGlyphDrawing(cr, font, point); if (context->textDrawingMode() & cTextFill) { if (context->fillGradient()) { cairo_set_source(cr, context->fillGradient()->platformGradient()); @@ -148,16 +131,10 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_pattern_destroy(pattern); } else { float red, green, blue, alpha; - fillColor.getRGBA(red, green, blue, alpha); + context->fillColor().getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); } - cairo_show_glyphs(cr, glyphs, numGlyphs); - if (font->syntheticBoldOffset()) { - cairo_save(cr); - cairo_translate(cr, font->syntheticBoldOffset(), 0); - cairo_show_glyphs(cr, glyphs, numGlyphs); - cairo_restore(cr); - } + drawGlyphsToContext(cr, font, glyphs, numGlyphs); } // Prevent running into a long computation within cairo. If the stroke width is @@ -183,20 +160,15 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons } cairo_pattern_destroy(pattern); } else { - Color strokeColor = context->strokeColor(); float red, green, blue, alpha; - strokeColor.getRGBA(red, green, blue, alpha); + context->strokeColor().getRGBA(red, green, blue, alpha); cairo_set_source_rgba(cr, red, green, blue, alpha * context->getAlpha()); - } + } cairo_glyph_path(cr, glyphs, numGlyphs); cairo_set_line_width(cr, context->strokeThickness()); cairo_stroke(cr); } - // Re-enable the platform shadow we disabled earlier - if (hasShadow) - context->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace); - cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp index 0617e6c..ba307fa 100644 --- a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp +++ b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.cpp @@ -75,40 +75,65 @@ void setCairoFontOptionsFromFontConfigPattern(cairo_font_options_t* options, FcP FcBool booleanResult; int integerResult; - // We will determine if subpixel anti-aliasing is enabled via the FC_RGBA setting. - if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &booleanResult) == FcResultMatch && booleanResult) - cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); - if (FcPatternGetInteger(pattern, FC_RGBA, 0, &integerResult) == FcResultMatch) { + cairo_font_options_set_subpixel_order(options, convertFontConfigSubpixelOrder(integerResult)); + + // Based on the logic in cairo-ft-font.c in the cairo source, a font with + // a subpixel order implies that is uses subpixel antialiasing. if (integerResult != FC_RGBA_NONE) cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL); - cairo_font_options_set_subpixel_order(options, convertFontConfigSubpixelOrder(integerResult)); + } + + if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &booleanResult) == FcResultMatch) { + // Only override the anti-aliasing setting if was previously turned off. Otherwise + // we'll override the preference which decides between gray anti-aliasing and + // subpixel anti-aliasing. + if (!booleanResult) + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_NONE); + else if (cairo_font_options_get_antialias(options) == CAIRO_ANTIALIAS_NONE) + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); } if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &integerResult) == FcResultMatch) cairo_font_options_set_hint_style(options, convertFontConfigHintStyle(integerResult)); - if (FcPatternGetBool(pattern, FC_HINTING, 0, &booleanResult) == FcResultMatch && !booleanResult) cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); } +static const cairo_font_options_t* getDefaultFontOptions() +{ + static const cairo_font_options_t* options = cairo_font_options_create(); +#if PLATFORM(GTK) || ENABLE(GLIB_SUPPORT) + if (GdkScreen* screen = gdk_screen_get_default()) { + const cairo_font_options_t* screenOptions = gdk_screen_get_font_options(screen); + if (screenOptions) + options = screenOptions; + } +#endif + return options; +} + FontPlatformData::FontPlatformData(FcPattern* pattern, const FontDescription& fontDescription) : m_pattern(pattern) , m_fallbacks(0) , m_size(fontDescription.computedPixelSize()) , m_syntheticBold(false) , m_syntheticOblique(false) + , m_fixedWidth(false) { - cairo_font_options_t* options = cairo_font_options_create(); - setCairoFontOptionsFromFontConfigPattern(options, pattern); + PlatformRefPtr<cairo_font_face_t> fontFace = adoptPlatformRef(cairo_ft_font_face_create_for_pattern(m_pattern.get())); + initializeWithFontFace(fontFace.get()); - cairo_matrix_t fontMatrix; - cairo_matrix_init_scale(&fontMatrix, m_size, m_size); - cairo_matrix_t ctm; - cairo_matrix_init_identity(&ctm); + int spacing; + if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch && spacing == FC_MONO) + m_fixedWidth = true; - PlatformRefPtr<cairo_font_face_t> fontFace = adoptPlatformRef(cairo_ft_font_face_create_for_pattern(m_pattern.get())); - m_scaledFont = adoptPlatformRef(cairo_scaled_font_create(fontFace.get(), &fontMatrix, &ctm, options)); + if (fontDescription.weight() >= FontWeightBold) { + // The FC_EMBOLDEN property instructs us to fake the boldness of the font. + FcBool fontConfigEmbolden; + if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &fontConfigEmbolden) == FcResultMatch) + m_syntheticBold = fontConfigEmbolden; + } } FontPlatformData::FontPlatformData(float size, bool bold, bool italic) @@ -116,7 +141,9 @@ FontPlatformData::FontPlatformData(float size, bool bold, bool italic) , m_size(size) , m_syntheticBold(bold) , m_syntheticOblique(italic) + , m_fixedWidth(false) { + // We cannot create a scaled font here. } FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic) @@ -125,24 +152,13 @@ FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool , m_syntheticBold(bold) , m_syntheticOblique(italic) { - cairo_matrix_t fontMatrix; - cairo_matrix_init_scale(&fontMatrix, size, size); - cairo_matrix_t ctm; - cairo_matrix_init_identity(&ctm); - static const cairo_font_options_t* defaultOptions = cairo_font_options_create(); - const cairo_font_options_t* options = NULL; - -#if !PLATFORM(EFL) || ENABLE(GLIB_SUPPORT) - if (GdkScreen* screen = gdk_screen_get_default()) - options = gdk_screen_get_font_options(screen); -#endif - - // gdk_screen_get_font_options() returns NULL if no default options are - // set, so we always have to check. - if (!options) - options = defaultOptions; + initializeWithFontFace(fontFace); - m_scaledFont = adoptPlatformRef(cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options)); + FT_Face fontConfigFace = cairo_ft_scaled_font_lock_face(m_scaledFont.get()); + if (fontConfigFace) { + m_fixedWidth = fontConfigFace->face_flags & FT_FACE_FLAG_FIXED_WIDTH; + cairo_ft_scaled_font_unlock_face(m_scaledFont.get()); + } } FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) @@ -154,6 +170,7 @@ FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) m_size = other.m_size; m_syntheticBold = other.m_syntheticBold; m_syntheticOblique = other.m_syntheticOblique; + m_fixedWidth = other.m_fixedWidth; m_scaledFont = other.m_scaledFont; m_pattern = other.m_pattern; @@ -172,6 +189,16 @@ FontPlatformData::FontPlatformData(const FontPlatformData& other) *this = other; } +FontPlatformData::FontPlatformData(const FontPlatformData& other, float size) +{ + *this = other; + + // We need to reinitialize the instance, because the difference in size + // necessitates a new scaled font instance. + m_size = size; + initializeWithFontFace(cairo_scaled_font_get_font_face(m_scaledFont.get())); +} + FontPlatformData::~FontPlatformData() { if (m_fallbacks) { @@ -182,14 +209,7 @@ FontPlatformData::~FontPlatformData() bool FontPlatformData::isFixedPitch() { - // TODO: Support isFixedPitch() for custom fonts. - if (!m_pattern) - return false; - - int spacing; - if (FcPatternGetInteger(m_pattern.get(), FC_SPACING, 0, &spacing) == FcResultMatch) - return spacing == FC_MONO; - return false; + return m_fixedWidth; } bool FontPlatformData::operator==(const FontPlatformData& other) const @@ -208,4 +228,37 @@ String FontPlatformData::description() const } #endif +void FontPlatformData::initializeWithFontFace(cairo_font_face_t* fontFace) +{ + cairo_font_options_t* options = cairo_font_options_copy(getDefaultFontOptions()); + + cairo_matrix_t ctm; + cairo_matrix_init_identity(&ctm); + + cairo_matrix_t fontMatrix; + if (!m_pattern) + cairo_matrix_init_scale(&fontMatrix, m_size, m_size); + else { + setCairoFontOptionsFromFontConfigPattern(options, m_pattern.get()); + + // FontConfig may return a list of transformation matrices with the pattern, for instance, + // for fonts that are oblique. We use that to initialize the cairo font matrix. + FcMatrix fontConfigMatrix, *tempFontConfigMatrix; + FcMatrixInit(&fontConfigMatrix); + + // These matrices may be stacked in the pattern, so it's our job to get them all and multiply them. + for (int i = 0; FcPatternGetMatrix(m_pattern.get(), FC_MATRIX, i, &tempFontConfigMatrix) == FcResultMatch; i++) + FcMatrixMultiply(&fontConfigMatrix, &fontConfigMatrix, tempFontConfigMatrix); + cairo_matrix_init(&fontMatrix, fontConfigMatrix.xx, -fontConfigMatrix.yx, + -fontConfigMatrix.xy, fontConfigMatrix.yy, 0, 0); + + // The matrix from FontConfig does not include the scale. + cairo_matrix_scale(&fontMatrix, m_size, m_size); + } + + m_scaledFont = adoptPlatformRef(cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options)); + cairo_font_options_destroy(options); +} + + } diff --git a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h index f3488ef..7d3ff99 100644 --- a/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h +++ b/WebCore/platform/graphics/cairo/FontPlatformDataFreeType.h @@ -57,6 +57,7 @@ public: FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool italic); FontPlatformData(float size, bool bold, bool italic); FontPlatformData(const FontPlatformData&); + FontPlatformData(const FontPlatformData&, float size); ~FontPlatformData(); @@ -89,7 +90,11 @@ public: float m_size; bool m_syntheticBold; bool m_syntheticOblique; + bool m_fixedWidth; PlatformRefPtr<cairo_scaled_font_t> m_scaledFont; + +private: + void initializeWithFontFace(cairo_font_face_t*); }; } diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 05096a9..0847da1 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -36,20 +36,18 @@ #include "AffineTransform.h" #include "CairoPath.h" #include "CairoUtilities.h" -#include "FEGaussianBlur.h" +#include "ContextShadow.h" #include "FloatRect.h" #include "Font.h" +#include "GraphicsContextPlatformPrivateCairo.h" +#include "GraphicsContextPrivate.h" #include "OwnPtrCairo.h" -#include "ImageBuffer.h" -#include "ImageBufferFilter.h" #include "IntRect.h" #include "NotImplemented.h" #include "Path.h" #include "Pattern.h" #include "PlatformRefPtrCairo.h" #include "SimpleFontData.h" -#include "SourceGraphic.h" - #include <cairo.h> #include <math.h> #include <stdio.h> @@ -61,8 +59,6 @@ #elif PLATFORM(WIN) #include <cairo-win32.h> #endif -#include "GraphicsContextPlatformPrivateCairo.h" -#include "GraphicsContextPrivate.h" using namespace std; @@ -132,26 +128,6 @@ static inline void fillRectSourceOver(cairo_t* cr, const FloatRect& rect, const cairo_fill(cr); } -static void appendPathToCairoContext(cairo_t* to, cairo_t* from) -{ - OwnPtr<cairo_path_t> cairoPath(cairo_copy_path(from)); - cairo_append_path(to, cairoPath.get()); -} - -// We apply the pending path built via addPath to the Cairo context -// lazily. This prevents interaction between the path and other routines -// such as fillRect. -static void setPathOnCairoContext(cairo_t* to, cairo_t* from) -{ - cairo_new_path(to); - appendPathToCairoContext(to, from); -} - -static void appendWebCorePathToCairoContext(cairo_t* context, const Path& path) -{ - appendPathToCairoContext(context, path.platformPath()->context()); -} - static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const FloatPoint* points) { cairo_move_to(context, points[0].x(), points[0].y()); @@ -160,83 +136,59 @@ static void addConvexPolygonToContext(cairo_t* context, size_t numPoints, const cairo_close_path(context); } -void GraphicsContext::calculateShadowBufferDimensions(IntSize& shadowBufferSize, FloatRect& shadowRect, float& radius, const FloatRect& sourceRect, const FloatSize& shadowOffset, float shadowBlur) -{ -#if ENABLE(FILTERS) - // limit radius to 128 - radius = min(128.f, max(shadowBlur, 0.f)); - - shadowBufferSize = IntSize(sourceRect.width() + radius * 2, sourceRect.height() + radius * 2); +enum PathDrawingStyle { + Fill = 1, + Stroke = 2, + FillAndStroke = Fill + Stroke +}; - // determine dimensions of shadow rect - shadowRect = FloatRect(sourceRect.location(), shadowBufferSize); - shadowRect.move(shadowOffset.width() - radius, shadowOffset.height() - radius); -#endif -} - -static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* gcp, bool fillShadow, bool strokeShadow) +static inline void drawPathShadow(GraphicsContext* context, GraphicsContextPrivate* contextPrivate, PathDrawingStyle drawingStyle) { -#if ENABLE(FILTERS) - FloatSize shadowOffset; - float shadowBlur; - Color shadowColor; - if (!context->getShadow(shadowOffset, shadowBlur, shadowColor)) + ContextShadow* shadow = context->contextShadow(); + ASSERT(shadow); + if (shadow->m_type == ContextShadow::NoShadow) return; - - // Calculate filter values to create appropriate shadow. - cairo_t* cr = context->platformContext(); - 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 radius = 0; - GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur); - - cairo_clip_extents(cr, &x0, &y0, &x1, &y1); - FloatRect clipRect(x0, y0, x1 - x0, y1 - y0); - - FloatPoint rectLocation = shadowRect.location(); - - // Reduce the shadow rect using the clip area. - if (!clipRect.contains(shadowRect)) { - shadowRect.intersect(clipRect); - if (shadowRect.isEmpty()) - return; - shadowRect.inflate(radius); - shadowBufferSize = IntSize(shadowRect.width(), shadowRect.height()); - } - shadowOffset = rectLocation - shadowRect.location(); + // Calculate the extents of the rendered solid paths. + cairo_t* cairoContext = context->platformContext(); + cairo_path_t* path = cairo_copy_path(cairoContext); + + FloatRect solidFigureExtents; + double x0 = 0; + double x1 = 0; + double y0 = 0; + double y1 = 0; + if (drawingStyle & Stroke) { + cairo_stroke_extents(cairoContext, &x0, &y0, &x1, &y1); + solidFigureExtents = FloatRect(x0, y0, x1 - x0, y1 - y0); + } + if (drawingStyle & Fill) { + cairo_fill_extents(cairoContext, &x0, &y0, &x1, &y1); + FloatRect fillExtents(x0, y0, x1 - x0, y1 - y0); + solidFigureExtents.unite(fillExtents); + } - // Create suitably-sized ImageBuffer to hold the shadow. - OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); + cairo_t* shadowContext = shadow->beginShadowLayer(cairoContext, solidFigureExtents); + if (!shadowContext) + return; - // Draw shadow into a new ImageBuffer. - cairo_t* shadowContext = shadowBuffer->context()->platformContext(); - copyContextProperties(cr, shadowContext); - cairo_translate(shadowContext, -rect.x() + radius + shadowOffset.width(), -rect.y() + radius + shadowOffset.height()); - cairo_new_path(shadowContext); - OwnPtr<cairo_path_t> path(cairo_copy_path(cr)); - cairo_append_path(shadowContext, path.get()); + // It's important to copy the context properties to the new shadow + // context to preserve things such as the fill rule and stroke width. + copyContextProperties(cairoContext, shadowContext); + cairo_append_path(shadowContext, path); - if (fillShadow) - setPlatformFill(context, shadowContext, gcp); - if (strokeShadow) - setPlatformStroke(context, shadowContext, gcp); + if (drawingStyle & Fill) + setPlatformFill(context, shadowContext, contextPrivate); + if (drawingStyle & Stroke) + setPlatformStroke(context, shadowContext, contextPrivate); - context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); -#endif + shadow->endShadowLayer(cairoContext); } static void fillCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivate* gcp, cairo_t* cairoContext) { cairo_set_fill_rule(cairoContext, context->fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - drawPathShadow(context, gcp, true, false); + drawPathShadow(context, gcp, Fill); setPlatformFill(context, cairoContext, gcp); cairo_new_path(cairoContext); @@ -244,7 +196,7 @@ static void fillCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivat static void strokeCurrentCairoPath(GraphicsContext* context, GraphicsContextPrivate* gcp, cairo_t* cairoContext) { - drawPathShadow(context, gcp, false, true); + drawPathShadow(context, gcp, Stroke); setPlatformStroke(context, cairoContext, gcp); cairo_new_path(cairoContext); } @@ -281,12 +233,20 @@ void GraphicsContext::savePlatformState() { cairo_save(m_data->cr); m_data->save(); + m_data->shadowStack.append(m_data->shadow); } void GraphicsContext::restorePlatformState() { cairo_restore(m_data->cr); m_data->restore(); + + if (m_data->shadowStack.isEmpty()) + m_data->shadow = ContextShadow(); + else { + m_data->shadow = m_data->shadowStack.last(); + m_data->shadowStack.removeLast(); + } } // Draws a filled rectangle with a stroked border. @@ -602,7 +562,7 @@ void GraphicsContext::drawPath() setPathOnCairoContext(cr, m_data->m_pendingPath.context()); cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); - drawPathShadow(this, m_common, true, true); + drawPathShadow(this, m_common, FillAndStroke); setPlatformFill(this, cr, m_common); setPlatformStroke(this, cr, m_common); @@ -621,49 +581,14 @@ void GraphicsContext::fillRect(const FloatRect& rect) cairo_restore(cr); } -static void drawBorderlessRectShadow(GraphicsContext* context, const FloatRect& rect, const Color& rectColor) -{ -#if ENABLE(FILTERS) - FloatSize shadowOffset; - float shadowBlur; - Color shadowColor; - if (!context->getShadow(shadowOffset, shadowBlur, shadowColor)) - return; - - AffineTransform transform = context->getCTM(); - // drawTiledShadow still does not work with rotations. - if ((transform.isIdentityOrTranslationOrFlipped())) { - cairo_t* cr = context->platformContext(); - cairo_save(cr); - appendWebCorePathToCairoContext(cr, Path::createRectangle(rect)); - FloatSize corner; - IntRect shadowRect(rect); - context->drawTiledShadow(shadowRect, corner, corner, corner, corner, DeviceColorSpace); - cairo_restore(cr); - - return; - } - - IntSize shadowBufferSize; - FloatRect shadowRect; - float radius = 0; - GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, rect, shadowOffset, shadowBlur); - - // Draw shadow into a new ImageBuffer - OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); - GraphicsContext* shadowContext = shadowBuffer->context(); - shadowContext->fillRect(FloatRect(FloatPoint(radius, radius), rect.size()), rectColor, DeviceColorSpace); - - context->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); -#endif -} - -void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace) +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace) { if (paintingDisabled()) return; - drawBorderlessRectShadow(this, rect, color); + if (m_data->hasShadow()) + m_data->shadow.drawRectShadow(this, enclosingIntRect(rect)); + if (color.alpha()) fillRectSourceOver(m_data->cr, rect, color); } @@ -737,8 +662,13 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int setPlatformStrokeStyle(DottedStroke); #else int radius = (width - 1) / 2; - for (unsigned i = 0; i < rectCount; i++) - appendWebCorePathToCairoContext(cr, Path::createRoundedRectangle(rects[i], FloatSize(radius, radius))); + Path path; + for (unsigned i = 0; i < rectCount; ++i) { + if (i > 0) + path.clear(); + path.addRoundedRect(rects[i], FloatSize(radius, radius)); + appendWebCorePathToCairoContext(cr, path); + } // Force the alpha to 50%. This matches what the Mac does with outline rings. Color ringColor(color.red(), color.green(), color.blue(), 127); @@ -928,57 +858,26 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness cairo_set_fill_rule(cr, savedFillRule); } -void GraphicsContext::setPlatformShadow(FloatSize const& size, float, Color const&, ColorSpace) +void GraphicsContext::setPlatformShadow(FloatSize const& size, float blur, Color const& color, ColorSpace) { - // Cairo doesn't support shadows natively, they are drawn manually in the draw* - // functions - + // 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.shadowOffset = FloatSize(size.width(), -size.height()); - } + m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height())); + } else + m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height())); } -void GraphicsContext::applyPlatformShadow(PassOwnPtr<ImageBuffer> buffer, const Color& shadowColor, const FloatRect& shadowRect, float radius) +ContextShadow* GraphicsContext::contextShadow() { -#if ENABLE(FILTERS) - setColor(m_data->cr, shadowColor); - PlatformRefPtr<cairo_surface_t> shadowMask(createShadowMask(buffer, shadowRect, radius)); - cairo_mask_surface(m_data->cr, shadowMask.get(), shadowRect.x(), shadowRect.y()); -#endif -} - -PlatformRefPtr<cairo_surface_t> GraphicsContext::createShadowMask(PassOwnPtr<ImageBuffer> buffer, const FloatRect& shadowRect, float radius) -{ -#if ENABLE(FILTERS) - if (!radius) - return buffer->m_data.m_surface; - - FloatPoint blurRadius = FloatPoint(radius, radius); - float stdDeviation = FEGaussianBlur::calculateStdDeviation(radius); - if (!stdDeviation) - return buffer->m_data.m_surface; - - // create filter - RefPtr<Filter> filter = ImageBufferFilter::create(); - filter->setSourceImage(buffer); - RefPtr<FilterEffect> source = SourceGraphic::create(); - source->setRepaintRectInLocalCoordinates(FloatRect(FloatPoint(), shadowRect.size())); - source->setIsAlphaImage(true); - RefPtr<FilterEffect> blur = FEGaussianBlur::create(stdDeviation, stdDeviation); - FilterEffectVector& inputEffects = blur->inputEffects(); - inputEffects.append(source.get()); - blur->setRepaintRectInLocalCoordinates(FloatRect(FloatPoint(), shadowRect.size())); - blur->apply(filter.get()); - return blur->resultImage()->m_data.m_surface; -#endif + return &m_data->shadow; } - void GraphicsContext::clearPlatformShadow() { - notImplemented(); + m_data->shadow.clear(); } void GraphicsContext::beginTransparencyLayer(float opacity) @@ -1095,43 +994,6 @@ float GraphicsContext::getAlpha() return m_common->state.globalAlpha; } -static inline cairo_operator_t toCairoOperator(CompositeOperator op) -{ - switch (op) { - case CompositeClear: - return CAIRO_OPERATOR_CLEAR; - case CompositeCopy: - return CAIRO_OPERATOR_SOURCE; - case CompositeSourceOver: - return CAIRO_OPERATOR_OVER; - case CompositeSourceIn: - return CAIRO_OPERATOR_IN; - case CompositeSourceOut: - return CAIRO_OPERATOR_OUT; - case CompositeSourceAtop: - return CAIRO_OPERATOR_ATOP; - case CompositeDestinationOver: - return CAIRO_OPERATOR_DEST_OVER; - case CompositeDestinationIn: - return CAIRO_OPERATOR_DEST_IN; - case CompositeDestinationOut: - return CAIRO_OPERATOR_DEST_OUT; - case CompositeDestinationAtop: - return CAIRO_OPERATOR_DEST_ATOP; - case CompositeXOR: - return CAIRO_OPERATOR_XOR; - case CompositePlusDarker: - return CAIRO_OPERATOR_SATURATE; - case CompositeHighlight: - // There is no Cairo equivalent for CompositeHighlight. - return CAIRO_OPERATOR_OVER; - case CompositePlusLighter: - return CAIRO_OPERATOR_ADD; - default: - return CAIRO_OPERATOR_SOURCE; - } -} - void GraphicsContext::setCompositeOperation(CompositeOperator op) { if (paintingDisabled()) @@ -1248,206 +1110,20 @@ static inline FloatPoint getPhase(const FloatRect& dest, const FloatRect& tile) return phase; } -/* - This function uses tiling to improve the performance of the shadow - drawing of rounded rectangles. The code basically does the following - steps: - - 1. Calculate the minimum rectangle size required to create the - tiles - - 2. If that size is smaller than the real rectangle render the new - small rectangle and its shadow in a new surface, in other case - render the shadow of the real rectangle in the destination - surface. - - 3. Calculate the sizes and positions of the tiles and their - destinations and use drawPattern to render the final shadow. The - code divides the rendering in 8 tiles: - - 1 | 2 | 3 - ----------- - 4 | | 5 - ----------- - 6 | 7 | 8 - - The corners are directly copied from the small rectangle to the - real one and the side tiles are 1 pixel width, we use them as - - tiles to cover the destination side. The corner tiles are bigger - than just the side of the rounded corner, we need to increase it - because the modifications caused by the corner over the blur - effect. We fill the central part with solid color to complete the - shadow. - */ -void GraphicsContext::drawTiledShadow(const IntRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const FloatSize& bottomRightRadius, ColorSpace colorSpace) -{ -#if ENABLE(FILTERS) - FloatSize shadowSize; - float shadowBlur; - Color shadowColor; - if (!getShadow(shadowSize, shadowBlur, shadowColor)) - return; - - // Calculate filter values to create appropriate shadow. - cairo_t* cr = m_data->cr; - - IntSize shadowBufferSize; - FloatRect shadowRect; - float blurRadius = 0; - GraphicsContext::calculateShadowBufferDimensions(shadowBufferSize, shadowRect, blurRadius, rect, shadowSize, shadowBlur); - - // Size of the tiling side. - int sideTileWidth = 1; - float radiusTwice = blurRadius * 2; - - // Find the extra space needed from the curve of the corners. - int extraWidthFromCornerRadii = radiusTwice + max(topLeftRadius.width(), bottomLeftRadius.width()) + - radiusTwice + max(topRightRadius.width(), bottomRightRadius.width()); - int extraHeightFromCornerRadii = radiusTwice + max(topLeftRadius.height(), topRightRadius.height()) + - radiusTwice + max(bottomLeftRadius.height(), bottomRightRadius.height()); - - // The length of a side of the buffer is the enough space for four blur radii, - // the radii of the corners, and then 1 pixel to draw the side tiles. - IntSize smallBufferSize = IntSize(sideTileWidth + extraWidthFromCornerRadii, - sideTileWidth + extraHeightFromCornerRadii); - - if ((smallBufferSize.width() > shadowBufferSize.width()) || (smallBufferSize.height() > shadowBufferSize.height()) || (blurRadius <= 0)) { - // Create suitably-sized ImageBuffer to hold the shadow. - OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(shadowBufferSize); - if (!shadowBuffer) - return; - - // Draw shadow into a new ImageBuffer. - cairo_t* shadowContext = shadowBuffer->context()->platformContext(); - copyContextProperties(cr, shadowContext); - cairo_translate(shadowContext, -rect.x() + blurRadius, -rect.y() + blurRadius); - cairo_new_path(shadowContext); - OwnPtr<cairo_path_t> path(cairo_copy_path(cr)); - cairo_append_path(shadowContext, path.get()); - - setPlatformFill(this, shadowContext, m_common); - - applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, blurRadius); - - return; - } - - OwnPtr<ImageBuffer> smallBuffer = ImageBuffer::create(smallBufferSize); - if (!smallBuffer) - return; - - IntRect smallRect = IntRect(blurRadius, blurRadius, smallBufferSize.width() - radiusTwice, smallBufferSize.height() - radiusTwice); - - // Draw shadow into a new ImageBuffer. - cairo_t* smallBufferContext = smallBuffer->context()->platformContext(); - copyContextProperties(cr, smallBufferContext); - appendWebCorePathToCairoContext(smallBuffer->context()->platformContext(), Path::createRoundedRectangle(smallRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius)); - setPlatformFill(this, smallBufferContext, m_common); - - OwnPtr<ImageBuffer> shadowBuffer = ImageBuffer::create(smallBufferSize); - if (!shadowBuffer) - return; - - smallRect.setSize(smallBufferSize); - - PlatformRefPtr<cairo_surface_t> shadowMask(createShadowMask(smallBuffer.release(), smallRect, blurRadius)); - - cairo_t* shadowContext = shadowBuffer->context()->platformContext(); - setColor(shadowContext, shadowColor); - cairo_mask_surface(shadowContext, shadowMask.get(), 0, 0); - - // Fill the internal part of the shadow. - shadowRect.inflate(-radiusTwice); - if (!shadowRect.isEmpty()) { - cairo_save(cr); - appendWebCorePathToCairoContext(cr, Path::createRoundedRectangle(shadowRect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius)); - setColor(cr, shadowColor); - cairo_fill(cr); - cairo_restore(cr); - } - shadowRect.inflate(radiusTwice); - - // Draw top side. - FloatRect tileRect = FloatRect(radiusTwice + topLeftRadius.width(), 0, sideTileWidth, radiusTwice); - FloatRect destRect = tileRect; - destRect.move(shadowRect.x(), shadowRect.y()); - destRect.setWidth(shadowRect.width() - topLeftRadius.width() - topRightRadius.width() - blurRadius * 4); - FloatPoint phase = getPhase(destRect, tileRect); - AffineTransform patternTransform; - patternTransform.makeIdentity(); - shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect); - - // Draw the bottom side. - tileRect = FloatRect(radiusTwice + bottomLeftRadius.width(), smallBufferSize.height() - radiusTwice, sideTileWidth, radiusTwice); - destRect = tileRect; - destRect.move(shadowRect.x(), shadowRect.y() + radiusTwice + rect.height() - smallBufferSize.height()); - destRect.setWidth(shadowRect.width() - bottomLeftRadius.width() - bottomRightRadius.width() - blurRadius * 4); - phase = getPhase(destRect, tileRect); - shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect); - - // Draw the right side. - tileRect = FloatRect(smallBufferSize.width() - radiusTwice, radiusTwice + topRightRadius.height(), radiusTwice, sideTileWidth); - destRect = tileRect; - destRect.move(shadowRect.x() + radiusTwice + rect.width() - smallBufferSize.width(), shadowRect.y()); - destRect.setHeight(shadowRect.height() - topRightRadius.height() - bottomRightRadius.height() - blurRadius * 4); - phase = getPhase(destRect, tileRect); - shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect); - - // Draw the left side. - tileRect = FloatRect(0, radiusTwice + topLeftRadius.height(), radiusTwice, sideTileWidth); - destRect = tileRect; - destRect.move(shadowRect.x(), shadowRect.y()); - destRect.setHeight(shadowRect.height() - topLeftRadius.height() - bottomLeftRadius.height() - blurRadius * 4); - phase = FloatPoint(destRect.x() - tileRect.x(), destRect.y() - tileRect.y()); - shadowBuffer->drawPattern(this, tileRect, patternTransform, - phase, colorSpace, CompositeSourceOver, destRect); - - // Draw the top left corner. - tileRect = FloatRect(0, 0, radiusTwice + topLeftRadius.width(), radiusTwice + topLeftRadius.height()); - destRect = tileRect; - destRect.move(shadowRect.x(), shadowRect.y()); - phase = getPhase(destRect, tileRect); - shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect); - - // Draw the top right corner. - tileRect = FloatRect(smallBufferSize.width() - radiusTwice - topRightRadius.width(), 0, radiusTwice + topRightRadius.width(), radiusTwice + topRightRadius.height()); - destRect = tileRect; - destRect.move(shadowRect.x() + rect.width() - smallBufferSize.width() + radiusTwice, shadowRect.y()); - phase = getPhase(destRect, tileRect); - shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect); - - // Draw the bottom right corner. - tileRect = FloatRect(smallBufferSize.width() - radiusTwice - bottomRightRadius.width(), smallBufferSize.height() - radiusTwice - bottomRightRadius.height(), radiusTwice + bottomRightRadius.width(), radiusTwice + bottomRightRadius.height()); - destRect = tileRect; - destRect.move(shadowRect.x() + rect.width() - smallBufferSize.width() + radiusTwice, shadowRect.y() + rect.height() - smallBufferSize.height() + radiusTwice); - phase = getPhase(destRect, tileRect); - shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect); - - // Draw the bottom left corner. - tileRect = FloatRect(0, smallBufferSize.height() - radiusTwice - bottomLeftRadius.height(), radiusTwice + bottomLeftRadius.width(), radiusTwice + bottomLeftRadius.height()); - destRect = tileRect; - destRect.move(shadowRect.x(), shadowRect.y() + rect.height() - smallBufferSize.height() + radiusTwice); - phase = getPhase(destRect, tileRect); - shadowBuffer->drawPattern(this, tileRect, patternTransform, phase, colorSpace, CompositeSourceOver, destRect); -#endif -} - 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; + if (m_data->hasShadow()) + m_data->shadow.drawRectShadow(this, r, topLeft, topRight, bottomLeft, bottomRight); + cairo_t* cr = m_data->cr; cairo_save(cr); - appendWebCorePathToCairoContext(cr, Path::createRoundedRectangle(r, topLeft, topRight, bottomLeft, bottomRight)); + Path path; + path.addRoundedRect(r, topLeft, topRight, bottomLeft, bottomRight); + appendWebCorePathToCairoContext(cr, path); setColor(cr, color); - AffineTransform transform = this->getCTM(); - // drawTiledShadow still does not work with rotations. - if (transform.isIdentityOrTranslationOrFlipped()) - drawTiledShadow(r, topLeft, topRight, bottomLeft, bottomRight, colorSpace); - else - drawPathShadow(this, m_common, true, false); cairo_fill(cr); cairo_restore(cr); } diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 81987ef..527cb72 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -28,6 +28,7 @@ #include "GraphicsContext.h" #include "CairoPath.h" +#include "ContextShadow.h" #include <cairo.h> #include <math.h> #include <stdio.h> @@ -98,6 +99,10 @@ public: Vector<float> layers; CairoPath m_pendingPath; + ContextShadow shadow; + Vector<ContextShadow> shadowStack; + bool hasShadow() const { return shadow.m_type != ContextShadow::NoShadow; } + #if PLATFORM(GTK) GdkEventExpose* expose; #elif PLATFORM(WIN) diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 976dcb4..d452c3a 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -69,7 +69,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) { } -ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success) : m_data(size) , m_size(size) { diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index 904e819..8f7a194 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -31,7 +31,9 @@ #if PLATFORM(CAIRO) #include "AffineTransform.h" +#include "CairoUtilities.h" #include "Color.h" +#include "ContextShadow.h" #include "FloatRect.h" #include "PlatformRefPtrCairo.h" #include "GraphicsContext.h" @@ -133,29 +135,18 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() }; cairo_pattern_set_matrix(pattern, &matrix); - // Draw the shadow -#if ENABLE(FILTERS) - FloatSize shadowOffset; - float shadowBlur; - Color shadowColor; - if (context->getShadow(shadowOffset, shadowBlur, shadowColor)) { - IntSize shadowBufferSize; - FloatRect shadowRect; - float radius = 0; - context->calculateShadowBufferDimensions(shadowBufferSize, shadowRect, radius, dstRect, shadowOffset, 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->applyPlatformShadow(shadowBuffer.release(), shadowColor, shadowRect, radius); + ContextShadow* shadow = context->contextShadow(); + ASSERT(shadow); + if (shadow->m_type != ContextShadow::NoShadow) { + cairo_t* shadowContext = shadow->beginShadowLayer(cr, dstRect); + if (shadowContext) { + cairo_translate(shadowContext, dstRect.x(), dstRect.y()); + cairo_set_source(shadowContext, pattern); + cairo_rectangle(shadowContext, 0, 0, dstRect.width(), dstRect.height()); + cairo_fill(shadowContext); + shadow->endShadowLayer(cr); + } } -#endif // Draw the image. cairo_translate(cr, dstRect.x(), dstRect.y()); @@ -172,46 +163,15 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo } void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform, - const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect) + const FloatPoint& phase, ColorSpace 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. return; - // Avoid NaN - if (!isfinite(phase.x()) || !isfinite(phase.y())) - return; - cairo_t* cr = context->platformContext(); - context->save(); - - PlatformRefPtr<cairo_surface_t> clippedImageSurface = 0; - if (tileRect.size() != size()) { - IntRect imageSize = enclosingIntRect(tileRect); - clippedImageSurface = adoptPlatformRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageSize.width(), imageSize.height())); - PlatformRefPtr<cairo_t> clippedImageContext(cairo_create(clippedImageSurface.get())); - cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y()); - cairo_paint(clippedImageContext.get()); - image = clippedImageSurface.get(); - } - - cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image); - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - 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; - cairo_matrix_multiply(&combined, &pattern_matrix, &phase_matrix); - cairo_matrix_invert(&combined); - cairo_pattern_set_matrix(pattern, &combined); - - context->setCompositeOperation(op); - cairo_set_source(cr, pattern); - cairo_pattern_destroy(pattern); - cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height()); - cairo_fill(cr); - - context->restore(); + drawPatternToCairoContext(cr, image, size(), tileRect, patternTransform, phase, toCairoOperator(op), destRect); if (imageObserver()) imageObserver()->didDraw(this); diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 776bceb..d5045be 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -337,40 +337,4 @@ void Path::transform(const AffineTransform& trans) cairo_transform(cr, &c_matrix); } -String Path::debugString() const -{ - if (isEmpty()) - return String(); - - String pathString; - OwnPtr<cairo_path_t> path(cairo_copy_path(platformPath()->context())); - cairo_path_data_t* data; - - for (int i = 0; i < path->num_data; i += path->data[i].header.length) { - data = &path->data[i]; - switch (data->header.type) { - case CAIRO_PATH_MOVE_TO: - if (i < (path->num_data - path->data[i].header.length)) - pathString += String::format("M%.2f,%.2f ", - data[1].point.x, data[1].point.y); - break; - case CAIRO_PATH_LINE_TO: - pathString += String::format("L%.2f,%.2f ", - data[1].point.x, data[1].point.y); - break; - case CAIRO_PATH_CURVE_TO: - pathString += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ", - data[1].point.x, data[1].point.y, - data[2].point.x, data[2].point.y, - data[3].point.x, data[3].point.y); - break; - case CAIRO_PATH_CLOSE_PATH: - pathString += "Z "; - break; - } - } - - return pathString.simplifyWhiteSpace(); -} - } // namespace WebCore diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp index 6f05c38..c9b05da 100644 --- a/WebCore/platform/graphics/cg/ColorCG.cpp +++ b/WebCore/platform/graphics/cg/ColorCG.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +28,7 @@ #if PLATFORM(CG) +#include "GraphicsContextCG.h" #include <wtf/Assertions.h> #include <wtf/RetainPtr.h> #include <ApplicationServices/ApplicationServices.h> @@ -69,37 +70,79 @@ Color::Color(CGColorRef color) m_valid = true; } -#if OS(WINDOWS) +static inline CGColorSpaceRef cachedCGColorSpace(ColorSpace colorSpace) +{ + switch (colorSpace) { + case ColorSpaceDeviceRGB: + return deviceRGBColorSpaceRef(); + case ColorSpaceSRGB: + return sRGBColorSpaceRef(); + case ColorSpaceLinearRGB: + return linearRGBColorSpaceRef(); + } + ASSERT_NOT_REACHED(); + return deviceRGBColorSpaceRef(); +} -CGColorRef createCGColor(const Color& c) +static CGColorRef leakCGColor(const Color& color, ColorSpace colorSpace) { - CGColorRef color = NULL; -#ifdef OBSOLETE_COLORSYNC_API - CMProfileRef prof = NULL; - CMGetSystemProfile(&prof); - RetainPtr<CGColorSpaceRef> rgbSpace(AdoptCF, CGColorSpaceCreateWithPlatformColorSpace(prof)); -#else - ColorSyncProfileRef prof = ColorSyncProfileCreateWithDisplayID(0); - RetainPtr<CGColorSpaceRef> rgbSpace(AdoptCF, CGColorSpaceCreateWithPlatformColorSpace(const_cast<void*>(reinterpret_cast<const void*>(prof)))); -#endif - - if (rgbSpace) { - CGFloat components[4] = { static_cast<CGFloat>(c.red()) / 255, static_cast<CGFloat>(c.green()) / 255, - static_cast<CGFloat>(c.blue()) / 255, static_cast<CGFloat>(c.alpha()) / 255 }; - color = CGColorCreate(rgbSpace.get(), components); + CGFloat components[4]; + color.getRGBA(components[0], components[1], components[2], components[3]); + return CGColorCreate(cachedCGColorSpace(colorSpace), components); +} + +template<ColorSpace colorSpace> static CGColorRef cachedCGColor(const Color& color) +{ + switch (color.rgb()) { + case Color::transparent: { + static CGColorRef transparentCGColor = leakCGColor(color, colorSpace); + return transparentCGColor; + } + case Color::black: { + static CGColorRef blackCGColor = leakCGColor(color, colorSpace); + return blackCGColor; + } + case Color::white: { + static CGColorRef whiteCGColor = leakCGColor(color, colorSpace); + return whiteCGColor; + } } -#ifdef OBSOLETE_COLORSYNC_API - CMCloseProfile(prof); -#else - if (prof) - CFRelease(prof); -#endif + ASSERT(color.rgb()); - return color; + const size_t cacheSize = 32; + static RGBA32 cachedRGBAValues[cacheSize]; + static RetainPtr<CGColorRef>* cachedCGColors = new RetainPtr<CGColorRef>[cacheSize]; + + for (size_t i = 0; i < cacheSize; ++i) { + if (cachedRGBAValues[i] == color.rgb()) + return cachedCGColors[i].get(); + } + + CGColorRef newCGColor = leakCGColor(color, colorSpace); + + static size_t cursor; + cachedRGBAValues[cursor] = color.rgb(); + cachedCGColors[cursor].adoptCF(newCGColor); + if (++cursor == cacheSize) + cursor = 0; + + return newCGColor; } -#endif // OS(WINDOWS) +CGColorRef cachedCGColor(const Color& color, ColorSpace colorSpace) +{ + switch (colorSpace) { + case ColorSpaceDeviceRGB: + return cachedCGColor<ColorSpaceDeviceRGB>(color); + case ColorSpaceSRGB: + return cachedCGColor<ColorSpaceSRGB>(color); + case ColorSpaceLinearRGB: + return cachedCGColor<ColorSpaceLinearRGB>(color); + } + ASSERT_NOT_REACHED(); + return cachedCGColor(color, ColorSpaceDeviceRGB); +} } diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index 2a81fd2..fe4fc7f 100644 --- a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -64,9 +64,35 @@ bool GraphicsContext3D::getImageData(Image* image, return false; size_t width = CGImageGetWidth(cgImage); size_t height = CGImageGetHeight(cgImage); - if (!width || !height || CGImageGetBitsPerComponent(cgImage) != 8) + if (!width || !height) return false; - size_t componentsPerPixel = CGImageGetBitsPerPixel(cgImage) / 8; + size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage); + size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage); + if (bitsPerComponent != 8 && bitsPerComponent != 16) + return false; + if (bitsPerPixel % bitsPerComponent) + return false; + size_t componentsPerPixel = bitsPerPixel / bitsPerComponent; + bool srcByteOrder16Big = false; + if (bitsPerComponent == 16) { + CGBitmapInfo bitInfo = CGImageGetBitmapInfo(cgImage); + switch (bitInfo & kCGBitmapByteOrderMask) { + case kCGBitmapByteOrder16Big: + srcByteOrder16Big = true; + break; + case kCGBitmapByteOrder16Little: + srcByteOrder16Big = false; + break; + case kCGBitmapByteOrderDefault: + // This is a bug in earlier version of cg where the default endian + // is little whereas the decoded 16-bit png image data is actually + // Big. Later version (10.6.4) no longer returns ByteOrderDefault. + srcByteOrder16Big = true; + break; + default: + return false; + } + } SourceDataFormat srcDataFormat = kSourceFormatRGBA8; AlphaOp neededAlphaOp = kAlphaDoNothing; switch (CGImageGetAlphaInfo(cgImage)) { @@ -79,10 +105,16 @@ bool GraphicsContext3D::getImageData(Image* image, neededAlphaOp = kAlphaDoUnmultiply; switch (componentsPerPixel) { case 2: - srcDataFormat = kSourceFormatAR8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatAR8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatAR16Big : kSourceFormatAR16Little; break; case 4: - srcDataFormat = kSourceFormatARGB8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatARGB8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatARGB16Big : kSourceFormatARGB16Little; break; default: return false; @@ -94,13 +126,22 @@ bool GraphicsContext3D::getImageData(Image* image, neededAlphaOp = kAlphaDoPremultiply; switch (componentsPerPixel) { case 1: - srcDataFormat = kSourceFormatA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatA16Big : kSourceFormatA16Little; break; case 2: - srcDataFormat = kSourceFormatAR8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatAR8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatAR16Big : kSourceFormatAR16Little; break; case 4: - srcDataFormat = kSourceFormatARGB8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatARGB8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatARGB16Big : kSourceFormatARGB16Little; break; default: return false; @@ -110,10 +151,16 @@ bool GraphicsContext3D::getImageData(Image* image, // This path is only accessible for MacOS earlier than 10.6.4. switch (componentsPerPixel) { case 2: - srcDataFormat = kSourceFormatAR8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatAR8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatAR16Big : kSourceFormatAR16Little; break; case 4: - srcDataFormat = kSourceFormatARGB8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatARGB8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatARGB16Big : kSourceFormatARGB16Little; break; default: return false; @@ -127,10 +174,16 @@ bool GraphicsContext3D::getImageData(Image* image, neededAlphaOp = kAlphaDoUnmultiply; switch (componentsPerPixel) { case 2: - srcDataFormat = kSourceFormatRA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatRA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatRA16Big : kSourceFormatRA16Little; break; case 4: - srcDataFormat = kSourceFormatRGBA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatRGBA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatRGBA16Big : kSourceFormatRGBA16Little; break; default: return false; @@ -141,13 +194,22 @@ bool GraphicsContext3D::getImageData(Image* image, neededAlphaOp = kAlphaDoPremultiply; switch (componentsPerPixel) { case 1: - srcDataFormat = kSourceFormatA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatA16Big : kSourceFormatA16Little; break; case 2: - srcDataFormat = kSourceFormatRA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatRA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatRA16Big : kSourceFormatRA16Little; break; case 4: - srcDataFormat = kSourceFormatRGBA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatRGBA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatRGBA16Big : kSourceFormatRGBA16Little; break; default: return false; @@ -156,10 +218,16 @@ bool GraphicsContext3D::getImageData(Image* image, case kCGImageAlphaNoneSkipLast: switch (componentsPerPixel) { case 2: - srcDataFormat = kSourceFormatRA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatRA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatRA16Big : kSourceFormatRA16Little; break; case 4: - srcDataFormat = kSourceFormatRGBA8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatRGBA8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatRGBA16Big : kSourceFormatRGBA16Little; break; default: return false; @@ -168,10 +236,16 @@ bool GraphicsContext3D::getImageData(Image* image, case kCGImageAlphaNone: switch (componentsPerPixel) { case 1: - srcDataFormat = kSourceFormatR8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatR8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatR16Big : kSourceFormatR16Little; break; case 3: - srcDataFormat = kSourceFormatRGB8; + if (bitsPerComponent == 8) + srcDataFormat = kSourceFormatRGB8; + else + srcDataFormat = srcByteOrder16Big ? kSourceFormatRGB16Big : kSourceFormatRGB16Little; break; default: return false; @@ -188,7 +262,7 @@ bool GraphicsContext3D::getImageData(Image* image, outputVector.resize(width * height * 4); unsigned int srcUnpackAlignment = 0; size_t bytesPerRow = CGImageGetBytesPerRow(cgImage); - unsigned int padding = bytesPerRow - componentsPerPixel * width; + unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment) diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index e5079dc..9e0a2f5 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -26,7 +26,7 @@ #define _USE_MATH_DEFINES 1 #include "config.h" -#include "GraphicsContext.h" +#include "GraphicsContextCG.h" #include "AffineTransform.h" #include "FloatConversion.h" @@ -69,60 +69,14 @@ using namespace std; namespace WebCore { -static CGColorRef createCGColorWithColorSpace(const Color& color, ColorSpace colorSpace) -{ - 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 setCGFillColor(CGContextRef context, const Color& color, ColorSpace colorSpace) { - CGColorRef cgColor = createCGColorWithColorSpace(color, colorSpace); - CGContextSetFillColorWithColor(context, cgColor); - CFRelease(cgColor); + CGContextSetFillColorWithColor(context, cachedCGColor(color, colorSpace)); } 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; - } + CGContextSetStrokeColorWithColor(context, cachedCGColor(color, colorSpace)); } CGColorSpaceRef deviceRGBColorSpaceRef() @@ -142,6 +96,17 @@ CGColorSpaceRef sRGBColorSpaceRef() #endif } +CGColorSpaceRef linearRGBColorSpaceRef() +{ + // FIXME: Windows should be able to use kCGColorSpaceGenericRGBLinear, this is tracked by http://webkit.org/b/31363. +#if PLATFORM(WIN) || defined(BUILDING_ON_TIGER) + return deviceRGBColorSpaceRef(); +#else + static CGColorSpaceRef linearRGBSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); + return linearRGBSpace; +#endif +} + GraphicsContext::GraphicsContext(CGContextRef cgContext) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate(cgContext)) @@ -586,9 +551,6 @@ void GraphicsContext::fillPath() CGContextRef context = platformContext(); - // 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) @@ -613,9 +575,6 @@ void GraphicsContext::strokePath() CGContextRef context = platformContext(); - // 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); @@ -638,9 +597,6 @@ void GraphicsContext::fillRect(const FloatRect& rect) CGContextRef context = platformContext(); - // 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); @@ -659,17 +615,18 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorS { if (paintingDisabled()) return; + CGContextRef context = platformContext(); Color oldFillColor = fillColor(); ColorSpace oldColorSpace = fillColorSpace(); if (oldFillColor != color || oldColorSpace != colorSpace) - setCGFillColor(context, color, colorSpace); + setCGFillColor(context, color, colorSpace); CGContextFillRect(context, rect); if (oldFillColor != color || oldColorSpace != colorSpace) - setCGFillColor(context, oldFillColor, oldColorSpace); + 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, ColorSpace colorSpace) @@ -684,7 +641,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef if (oldFillColor != color || oldColorSpace != colorSpace) setCGFillColor(context, color, colorSpace); - addPath(Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight)); + Path path; + path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); + addPath(path); fillPath(); if (oldFillColor != color || oldColorSpace != colorSpace) @@ -821,13 +780,8 @@ void GraphicsContext::setPlatformShadow(const FloatSize& offset, float blur, con // and we should therefore just use the default shadow color. if (!color.isValid()) CGContextSetShadow(context, CGSizeMake(xOffset, yOffset), blurRadius); - else { - RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColorWithColorSpace(color, colorSpace)); - CGContextSetShadowWithColor(context, - CGSizeMake(xOffset, yOffset), - blurRadius, - colorCG.get()); - } + else + CGContextSetShadowWithColor(context, CGSizeMake(xOffset, yOffset), blurRadius, cachedCGColor(color, colorSpace)); } void GraphicsContext::clearPlatformShadow() @@ -865,9 +819,6 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) CGContextRef context = platformContext(); - // 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); diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.h b/WebCore/platform/graphics/cg/GraphicsContextCG.h new file mode 100644 index 0000000..5de95ef --- /dev/null +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GraphicsContextCG_h +#define GraphicsContextCG_h + +#include "GraphicsContext.h" + +typedef struct CGColorSpace *CGColorSpaceRef; + +namespace WebCore { + +CGColorSpaceRef deviceRGBColorSpaceRef(); +CGColorSpaceRef sRGBColorSpaceRef(); +CGColorSpaceRef linearRGBColorSpaceRef(); + +} + +#endif diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index aac4f45..1d0a99f 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -28,12 +28,6 @@ namespace WebCore { -// FIXME: This would be in GraphicsContextCG.h if that existed. -CGColorSpaceRef deviceRGBColorSpaceRef(); - -// FIXME: This would be in GraphicsContextCG.h if that existed. -CGColorSpaceRef sRGBColorSpaceRef(); - class GraphicsContextPlatformPrivate { public: GraphicsContextPlatformPrivate(CGContextRef cgContext) diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp index ecbcf60..640692a 100644 --- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -31,12 +31,12 @@ #include "Base64.h" #include "BitmapImage.h" #include "GraphicsContext.h" +#include "GraphicsContextCG.h" #include "ImageData.h" #include "MIMETypeRegistry.h" -#include "PlatformString.h" #include <ApplicationServices/ApplicationServices.h> #include <wtf/Assertions.h> -#include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> #include <wtf/OwnArrayPtr.h> #include <wtf/RetainPtr.h> #include <wtf/Threading.h> @@ -56,7 +56,7 @@ ImageBufferData::ImageBufferData(const IntSize&) { } -ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, bool& success) : m_data(size) , m_size(size) { @@ -65,12 +65,11 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b return; unsigned bytesPerRow = size.width(); - if (imageColorSpace != GrayScale) { - // Protect against overflow - if (bytesPerRow > 0x3FFFFFFF) - return; - bytesPerRow *= 4; - } + + // Protect against overflow + if (bytesPerRow > 0x3FFFFFFF) + return; + bytesPerRow *= 4; m_data.m_bytesPerRow = bytesPerRow; size_t dataSize = size.height() * bytesPerRow; @@ -80,27 +79,20 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0); switch(imageColorSpace) { - case DeviceRGB: - m_data.m_colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); - break; - case GrayScale: - m_data.m_colorSpace.adoptCF(CGColorSpaceCreateDeviceGray()); - break; -#if ((PLATFORM(MAC) || PLATFORM(CHROMIUM)) && !defined(BUILDING_ON_TIGER)) - case LinearRGB: - m_data.m_colorSpace.adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear)); - break; - -#endif - default: - m_data.m_colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); - break; + case ColorSpaceDeviceRGB: + m_data.m_colorSpace = deviceRGBColorSpaceRef(); + break; + case ColorSpaceSRGB: + m_data.m_colorSpace = sRGBColorSpaceRef(); + break; + case ColorSpaceLinearRGB: + m_data.m_colorSpace = linearRGBColorSpaceRef(); + break; } - m_data.m_grayScale = imageColorSpace == GrayScale; - m_data.m_bitmapInfo = m_data.m_grayScale ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast; + m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; RetainPtr<CGContextRef> cgContext(AdoptCF, CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, - m_data.m_colorSpace.get(), m_data.m_bitmapInfo)); + m_data.m_colorSpace, m_data.m_bitmapInfo)); if (!cgContext) return; @@ -135,8 +127,8 @@ PassRefPtr<Image> ImageBuffer::copyImage() const static CGImageRef cgImage(const IntSize& size, const ImageBufferData& data) { - return CGImageCreate(size.width(), size.height(), 8, data.m_grayScale ? 8 : 32, data.m_bytesPerRow, - data.m_colorSpace.get(), data.m_bitmapInfo, data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault); + return CGImageCreate(size.width(), size.height(), 8, 32, data.m_bytesPerRow, + data.m_colorSpace, data.m_bitmapInfo, data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault); } void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect, @@ -145,7 +137,7 @@ void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, if (destContext == context()) { // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. RefPtr<Image> copy = copyImage(); - destContext->drawImage(copy.get(), DeviceColorSpace, destRect, srcRect, op, useLowQualityScale); + destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale); } else { RefPtr<Image> imageForRendering = BitmapImage::create(cgImage(m_size, m_data)); destContext->drawImage(imageForRendering.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); @@ -371,7 +363,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con base64Encode(reinterpret_cast<const char*>(CFDataGetBytePtr(data.get())), CFDataGetLength(data.get()), out); out.append('\0'); - return String::format("data:%s;base64,%s", mimeType.utf8().data(), out.data()); + return makeString("data:", mimeType, ";base64,", out.data()); } } // namespace WebCore diff --git a/WebCore/platform/graphics/cg/ImageBufferData.h b/WebCore/platform/graphics/cg/ImageBufferData.h index 2f9d854..456c934 100644 --- a/WebCore/platform/graphics/cg/ImageBufferData.h +++ b/WebCore/platform/graphics/cg/ImageBufferData.h @@ -46,9 +46,8 @@ public: RetainPtr<CGDataProviderRef> m_dataProvider; CGBitmapInfo m_bitmapInfo; - bool m_grayScale; unsigned m_bytesPerRow; - RetainPtr<CGColorSpaceRef> m_colorSpace; + CGColorSpaceRef m_colorSpace; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp index 70a80a0..c7ed0c8 100644 --- a/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,12 +31,12 @@ #include "AffineTransform.h" #include "FloatConversion.h" #include "FloatRect.h" -#include "GraphicsContext.h" -#include "GraphicsContextPlatformPrivateCG.h" +#include "GraphicsContextCG.h" #include "ImageObserver.h" #include "PDFDocumentImage.h" #include "PlatformString.h" #include <ApplicationServices/ApplicationServices.h> +#include <wtf/RetainPtr.h> #if PLATFORM(MAC) || PLATFORM(CHROMIUM) #include "WebCoreSystemInterface.h" @@ -138,11 +138,12 @@ static RetainPtr<CGImageRef> imageWithColorSpace(CGImageRef originalImage, Color return originalImage; switch (colorSpace) { - case DeviceColorSpace: + case ColorSpaceDeviceRGB: return originalImage; - case sRGBColorSpace: - return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, - sRGBColorSpaceRef())); + case ColorSpaceSRGB: + return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, sRGBColorSpaceRef())); + case ColorSpaceLinearRGB: + return RetainPtr<CGImageRef>(AdoptCF, CGImageCreateCopyWithColorSpace(originalImage, linearRGBColorSpaceRef())); } ASSERT_NOT_REACHED(); @@ -186,7 +187,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& destRect, const F // containing only the portion we want to display. We need to do this because high-quality // interpolation smoothes sharp edges, causing pixels from outside the source rect to bleed // into the destination rect. See <rdar://problem/6112909>. - shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && srcRect.size() != destRect.size(); + shouldUseSubimage = (interpolationQuality == kCGInterpolationHigh || interpolationQuality == kCGInterpolationDefault) && (srcRect.size() != destRect.size() || !ctxt->getCTM().isIdentityOrTranslationOrFlipped()); float xScale = srcRect.width() / destRect.width(); float yScale = srcRect.height() / destRect.height(); if (shouldUseSubimage) { diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp index 90d4b8a..b47ed02 100644 --- a/WebCore/platform/graphics/cg/PathCG.cpp +++ b/WebCore/platform/graphics/cg/PathCG.cpp @@ -254,61 +254,9 @@ FloatPoint Path::currentPoint() const return CGPathGetCurrentPoint(m_path); } -static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *element) -{ - CFMutableStringRef string = static_cast<CFMutableStringRef>(info); - - CGPoint* points = element->points; - switch (element->type) { - case kCGPathElementMoveToPoint: - CFStringAppendFormat(string, 0, CFSTR("M%.2f,%.2f "), points[0].x, points[0].y); - break; - case kCGPathElementAddLineToPoint: - CFStringAppendFormat(string, 0, CFSTR("L%.2f,%.2f "), points[0].x, points[0].y); - break; - case kCGPathElementAddQuadCurveToPoint: - CFStringAppendFormat(string, 0, CFSTR("Q%.2f,%.2f,%.2f,%.2f "), - points[0].x, points[0].y, points[1].x, points[1].y); - break; - case kCGPathElementAddCurveToPoint: - CFStringAppendFormat(string, 0, CFSTR("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f "), - points[0].x, points[0].y, points[1].x, points[1].y, - points[2].x, points[2].y); - break; - case kCGPathElementCloseSubpath: - CFStringAppendFormat(string, 0, CFSTR("Z ")); - break; - } -} - -static CFStringRef CFStringFromCGPath(CGPathRef path) -{ - if (!path) - return 0; - - CFMutableStringRef string = CFStringCreateMutable(NULL, 0); - CGPathApply(path, string, CGPathToCFStringApplierFunction); - CFStringTrimWhitespace(string); - - - return string; -} - - #pragma mark - #pragma mark Path Management -String Path::debugString() const -{ - String result; - if (!isEmpty()) { - CFStringRef pathString = CFStringFromCGPath(m_path); - result = String(pathString); - CFRelease(pathString); - } - return result; -} - struct PathApplierInfo { void* info; PathApplierFunction function; diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp index 8dda4d6..eba5349 100644 --- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp @@ -43,8 +43,6 @@ #include "PlatformContextSkia.h" #include "skia/ext/platform_canvas.h" #elif PLATFORM(CG) -#include "LocalCurrentGraphicsContext.h" - #include <CoreGraphics/CGBitmapContext.h> #endif @@ -121,6 +119,7 @@ PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChrom ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner) : LayerChromium(owner) , m_contentsTexture(0) + , m_skipsDraw(false) { } @@ -129,16 +128,6 @@ ContentLayerChromium::~ContentLayerChromium() cleanupResources(); } -void ContentLayerChromium::setLayerRenderer(LayerRendererChromium* renderer) -{ - // If we're changing layer renderers then we need to free up any resources - // allocated by the old renderer. - if (layerRenderer() && layerRenderer() != renderer) - cleanupResources(); - - LayerChromium::setLayerRenderer(renderer); -} - void ContentLayerChromium::cleanupResources() { if (layerRenderer()) { @@ -149,6 +138,42 @@ void ContentLayerChromium::cleanupResources() } } +bool ContentLayerChromium::requiresClippedUpdateRect() const +{ + // To avoid allocating excessively large textures, switch into "large layer mode" if + // one of the layer's dimensions is larger than 2000 pixels or the current size + // of the visible rect. This is a temporary measure until layer tiling is implemented. + static const int maxLayerSize = 2000; + return (m_bounds.width() > max(maxLayerSize, layerRenderer()->rootLayerContentRect().width()) + || m_bounds.height() > max(maxLayerSize, layerRenderer()->rootLayerContentRect().height()) + || !layerRenderer()->checkTextureSize(m_bounds)); +} + +void ContentLayerChromium::calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const +{ + // For the given layer size and content rect, calculate: + // 1) The minimal texture space rectangle to be uploaded, returned in dirtyRect. + // 2) The content rect-relative rectangle to draw this texture in, returned in drawRect. + + const IntRect clipRect = layerRenderer()->currentScissorRect(); + const TransformationMatrix& transform = drawTransform(); + // The layer's draw transform points to the center of the layer, relative to + // the content rect. layerPos is the distance from the top left of the + // layer to the top left of the content rect. + const IntPoint layerPos(m_bounds.width() / 2 - transform.m41(), + m_bounds.height() / 2 - transform.m42()); + // Transform the contentRect into the space of the layer. + IntRect contentRectInLayerSpace(layerPos, clipRect.size()); + + // Clip the entire layer against the visible region in the content rect + // and use that as the drawable texture, instead of the entire layer. + dirtyRect = IntRect(IntPoint(0, 0), m_bounds); + dirtyRect.intersect(contentRectInLayerSpace); + + // The draw position is relative to the content rect. + drawRect = IntRect(toPoint(dirtyRect.location() - layerPos), dirtyRect.size()); +} + void ContentLayerChromium::updateContents() { RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client()); @@ -159,29 +184,47 @@ void ContentLayerChromium::updateContents() ASSERT(layerRenderer()); - // FIXME: Remove this test when tiled layers are implemented. - m_skipsDraw = false; - if (!layerRenderer()->checkTextureSize(m_bounds)) { - m_skipsDraw = true; - return; - } - void* pixels = 0; - IntRect dirtyRect(m_dirtyRect); + IntRect dirtyRect; + IntRect updateRect; IntSize requiredTextureSize; IntSize bitmapSize; - requiredTextureSize = m_bounds; - IntRect boundsRect(IntPoint(0, 0), m_bounds); - - // If the texture needs to be reallocated then we must redraw the entire - // contents of the layer. - if (requiredTextureSize != m_allocatedTextureSize) - dirtyRect = boundsRect; - else { - // Clip the dirtyRect to the size of the layer to avoid drawing outside - // the bounds of the backing texture. - dirtyRect.intersect(boundsRect); + // FIXME: Remove this test when tiled layers are implemented. + if (requiresClippedUpdateRect()) { + // A layer with 3D transforms could require an arbitrarily large number + // of texels to be repainted, so ignore these layers until tiling is + // implemented. + if (!drawTransform().isIdentityOrTranslation()) { + m_skipsDraw = true; + return; + } + + calculateClippedUpdateRect(dirtyRect, m_largeLayerDrawRect); + if (!layerRenderer()->checkTextureSize(m_largeLayerDrawRect.size())) { + m_skipsDraw = true; + return; + } + if (m_largeLayerDirtyRect == dirtyRect) + return; + + m_largeLayerDirtyRect = dirtyRect; + requiredTextureSize = dirtyRect.size(); + updateRect = IntRect(IntPoint(0, 0), dirtyRect.size()); + } else { + dirtyRect = IntRect(m_dirtyRect); + IntRect boundsRect(IntPoint(0, 0), m_bounds); + requiredTextureSize = m_bounds; + // If the texture needs to be reallocated then we must redraw the entire + // contents of the layer. + if (requiredTextureSize != m_allocatedTextureSize) + dirtyRect = boundsRect; + else { + // Clip the dirtyRect to the size of the layer to avoid drawing + // outside the bounds of the backing texture. + dirtyRect.intersect(boundsRect); + } + updateRect = dirtyRect; } #if PLATFORM(SKIA) @@ -228,7 +271,6 @@ void ContentLayerChromium::updateContents() CGContextScaleCTM(contextCG.get(), 1, -1); GraphicsContext graphicsContext(contextCG.get()); - LocalCurrentGraphicsContext scopedNSGraphicsContext(&graphicsContext); // Translate the graphics context into the coordinate system of the dirty rect. graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y()); @@ -246,7 +288,7 @@ void ContentLayerChromium::updateContents() textureId = layerRenderer()->createLayerTexture(); if (pixels) - updateTextureRect(pixels, bitmapSize, requiredTextureSize, dirtyRect, textureId); + updateTextureRect(pixels, bitmapSize, requiredTextureSize, updateRect, textureId); } void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId) @@ -272,7 +314,8 @@ void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmap } m_dirtyRect.setSize(FloatSize()); - m_contentsDirty = false; + // Large layers always stay dirty, because they need to update when the content rect changes. + m_contentsDirty = requiresClippedUpdateRect(); } void ContentLayerChromium::draw() @@ -288,9 +331,21 @@ void ContentLayerChromium::draw() GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_contentsTexture)); layerRenderer()->useShader(sv->contentShaderProgram()); GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0)); - drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(), - bounds().width(), bounds().height(), drawOpacity(), - sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); + + if (requiresClippedUpdateRect()) { + float m43 = drawTransform().m43(); + TransformationMatrix transform; + transform.translate3d(m_largeLayerDrawRect.center().x(), m_largeLayerDrawRect.center().y(), m43); + drawTexturedQuad(context, layerRenderer()->projectionMatrix(), + transform, m_largeLayerDrawRect.width(), + m_largeLayerDrawRect.height(), drawOpacity(), + sv->shaderMatrixLocation(), sv->shaderAlphaLocation()); + } else { + drawTexturedQuad(context, layerRenderer()->projectionMatrix(), + drawTransform(), m_bounds.width(), m_bounds.height(), + drawOpacity(), sv->shaderMatrixLocation(), + sv->shaderAlphaLocation()); + } } } diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.h b/WebCore/platform/graphics/chromium/ContentLayerChromium.h index 412ba06..32c2c49 100644 --- a/WebCore/platform/graphics/chromium/ContentLayerChromium.h +++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.h @@ -49,7 +49,6 @@ public: virtual void updateContents(); virtual void draw(); virtual bool drawsContent() { return m_owner && m_owner->drawsContent(); } - virtual void setLayerRenderer(LayerRendererChromium*); // Stores values that are shared between instances of this class that are // associated with the same LayerRendererChromium (and hence the same GL @@ -80,12 +79,17 @@ protected: void updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId); - void cleanupResources(); + virtual void cleanupResources(); + bool requiresClippedUpdateRect() const; unsigned m_contentsTexture; IntSize m_allocatedTextureSize; bool m_skipsDraw; +private: + void calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const; + IntRect m_largeLayerDrawRect; + IntRect m_largeLayerDirtyRect; }; } diff --git a/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp index 9ce0efe..b54a427 100644 --- a/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp +++ b/WebCore/platform/graphics/chromium/DrawingBufferChromium.cpp @@ -48,7 +48,7 @@ struct DrawingBufferInternal { #endif }; -static unsigned generateColorTexture(SharedGraphicsContext3D* context, const IntSize& size) +static unsigned generateColorTexture(GraphicsContext3D* context, const IntSize& size) { unsigned offscreenColorTexture = context->createTexture(); if (!offscreenColorTexture) @@ -66,13 +66,13 @@ static unsigned generateColorTexture(SharedGraphicsContext3D* context, const Int } -DrawingBuffer::DrawingBuffer(SharedGraphicsContext3D* context, const IntSize& size, unsigned framebuffer) +DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, const IntSize& size) : m_context(context) , m_size(size) - , m_framebuffer(framebuffer) + , m_fbo(context->createFramebuffer()) , m_internal(new DrawingBufferInternal) { - context->bindFramebuffer(framebuffer); + context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); m_internal->offscreenColorTexture = generateColorTexture(context, size); } @@ -82,14 +82,22 @@ DrawingBuffer::~DrawingBuffer() if (m_internal->platformLayer) m_internal->platformLayer->setDrawingBuffer(0); #endif - m_context->bindFramebuffer(m_framebuffer); + + if (!m_context) + return; + + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); m_context->deleteTexture(m_internal->offscreenColorTexture); - m_context->deleteFramebuffer(m_framebuffer); + + clear(); } #if USE(ACCELERATED_COMPOSITING) void DrawingBuffer::publishToPlatformLayer() { + if (!m_context) + return; + if (m_callback) m_callback->willPublish(); unsigned parentTexture = m_internal->platformLayer->textureId(); @@ -106,6 +114,9 @@ void DrawingBuffer::publishToPlatformLayer() void DrawingBuffer::reset(const IntSize& newSize) { + if (!m_context) + return; + if (m_size == newSize) return; m_size = newSize; diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index a242523..f38273c 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -161,62 +161,23 @@ static int truncateFixedPointToInteger(HB_Fixed value) // can call |reset| to start over again. class TextRunWalker { public: - TextRunWalker(const TextRun& run, unsigned startingX, const Font* font) - : m_font(font) - , m_startingX(startingX) - , m_offsetX(m_startingX) - , m_run(getTextRun(run)) - , m_iterateBackwards(m_run.rtl()) - , m_wordSpacingAdjustment(0) - , m_padding(0) - , m_padError(0) - { - // Do not use |run| inside this constructor. Use |m_run| instead. - - memset(&m_item, 0, sizeof(m_item)); - // We cannot know, ahead of time, how many glyphs a given script run - // will produce. We take a guess that script runs will not produce more - // than twice as many glyphs as there are code points plus a bit of - // padding and fallback if we find that we are wrong. - createGlyphArrays((m_run.length() + 2) * 2); - - m_item.log_clusters = new unsigned short[m_run.length()]; - - m_item.face = 0; - m_item.font = allocHarfbuzzFont(); - - m_item.item.bidiLevel = m_run.rtl(); - - int length = m_run.length(); - m_item.stringLength = length; - - if (!m_item.item.bidiLevel) - m_item.string = m_run.characters(); - else { - // Assume mirrored character is in the same Unicode multilingual plane as the original one. - UChar* string = new UChar[length]; - mirrorCharacters(string, m_run.characters(), length); - m_item.string = string; - } - - reset(); - } + TextRunWalker(const TextRun&, unsigned, const Font*); + ~TextRunWalker(); - ~TextRunWalker() - { - fastFree(m_item.font); - deleteGlyphArrays(); - delete[] m_item.log_clusters; - if (m_item.item.bidiLevel) - delete[] m_item.string; - } + bool isWordBreak(unsigned, bool); + // setPadding sets a number of pixels to be distributed across the TextRun. + // WebKit uses this to justify text. + void setPadding(int); + void reset(); + void setBackwardsIteration(bool); + // Advance to the next script run, returning false when the end of the + // TextRun has been reached. + bool nextScriptRun(); + float widthOfFullRun(); // setWordSpacingAdjustment sets a delta (in pixels) which is applied at // each word break in the TextRun. - void setWordSpacingAdjustment(int wordSpacingAdjustment) - { - m_wordSpacingAdjustment = wordSpacingAdjustment; - } + void setWordSpacingAdjustment(int wordSpacingAdjustment) { m_wordSpacingAdjustment = wordSpacingAdjustment; } // setLetterSpacingAdjustment sets an additional number of pixels that is // added to the advance after each output cluster. This matches the behaviour @@ -224,393 +185,431 @@ public: // // (NOTE: currently does nothing because I don't know how to get the // cluster information from Harfbuzz.) - void setLetterSpacingAdjustment(int letterSpacingAdjustment) - { - m_letterSpacing = letterSpacingAdjustment; - } - - bool isWordBreak(unsigned i, bool isRTL) - { - if (!isRTL) - return i && isCodepointSpace(m_item.string[i]) && !isCodepointSpace(m_item.string[i - 1]); - return i != m_item.stringLength - 1 && isCodepointSpace(m_item.string[i]) && !isCodepointSpace(m_item.string[i + 1]); - } - - // setPadding sets a number of pixels to be distributed across the TextRun. - // WebKit uses this to justify text. - void setPadding(int padding) - { - m_padding = padding; - if (!m_padding) - return; - - // If we have padding to distribute, then we try to give an equal - // amount to each space. The last space gets the smaller amount, if - // any. - unsigned numWordBreaks = 0; - bool isRTL = m_iterateBackwards; - - for (unsigned i = 0; i < m_item.stringLength; i++) { - if (isWordBreak(i, isRTL)) - numWordBreaks++; - } - - if (numWordBreaks) - m_padPerWordBreak = m_padding / numWordBreaks; - else - m_padPerWordBreak = 0; - } - - void reset() - { - if (m_iterateBackwards) - m_indexOfNextScriptRun = m_run.length() - 1; - else - m_indexOfNextScriptRun = 0; - m_offsetX = m_startingX; - } + void setLetterSpacingAdjustment(int letterSpacingAdjustment) { m_letterSpacing = letterSpacingAdjustment; } // Set the x offset for the next script run. This affects the values in // |xPositions| - void setXOffsetToZero() - { - m_offsetX = 0; - } - - bool rtl() const - { - return m_run.rtl(); - } - - void setBackwardsIteration(bool isBackwards) - { - m_iterateBackwards = isBackwards; - reset(); - } - - // Advance to the next script run, returning false when the end of the - // TextRun has been reached. - bool nextScriptRun() - { - if (m_iterateBackwards) { - // In right-to-left mode we need to render the shaped glyph backwards and - // also render the script runs themselves backwards. So given a TextRun: - // AAAAAAACTTTTTTT (A = Arabic, C = Common, T = Thai) - // we render: - // TTTTTTCAAAAAAA - // (and the glyphs in each A, C and T section are backwards too) - if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) - return false; - } else { - if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) - return false; - - // It is actually wrong to consider script runs at all in this code. - // Other WebKit code (e.g. Mac) segments complex text just by finding - // the longest span of text covered by a single font. - // But we currently need to call hb_utf16_script_run_next anyway to fill - // in the harfbuzz data structures to e.g. pick the correct script's shaper. - // So we allow that to run first, then do a second pass over the range it - // found and take the largest subregion that stays within a single font. - const FontData* glyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; - unsigned endOfRun; - for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) { - const FontData* nextGlyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData; - if (nextGlyphData != glyphData) - break; - } - m_item.item.length = endOfRun; - m_indexOfNextScriptRun = m_item.item.pos + endOfRun; - } - - setupFontForScriptRun(); - shapeGlyphs(); - setGlyphXPositions(rtl()); - - return true; - } - - const uint16_t* glyphs() const - { - return m_glyphs16; - } + void setXOffsetToZero() { m_offsetX = 0; } + bool rtl() const { return m_run.rtl(); } + const uint16_t* glyphs() const { return m_glyphs16; } // Return the length of the array returned by |glyphs| - const unsigned length() const - { - return m_item.num_glyphs; - } + const unsigned length() const { return m_item.num_glyphs; } // Return the x offset for each of the glyphs. Note that this is translated // by the current x offset and that the x offset is updated for each script // run. - const SkScalar* xPositions() const - { - return m_xPositions; - } + const SkScalar* xPositions() const { return m_xPositions; } // Get the advances (widths) for each glyph. - const HB_Fixed* advances() const - { - return m_item.advances; - } + const HB_Fixed* advances() const { return m_item.advances; } // Return the width (in px) of the current script run. - const unsigned width() const - { - return m_pixelWidth; - } + const unsigned width() const { return m_pixelWidth; } // Return the cluster log for the current script run. For example: // script run: f i a n c é (fi gets ligatured) // log clutrs: 0 0 1 2 3 4 // So, for each input code point, the log tells you which output glyph was // generated for it. - const unsigned short* logClusters() const - { - return m_item.log_clusters; - } + const unsigned short* logClusters() const { return m_item.log_clusters; } // return the number of code points in the current script run - const unsigned numCodePoints() const - { - return m_numCodePoints; - } + const unsigned numCodePoints() const { return m_numCodePoints; } - const FontPlatformData* fontPlatformDataForScriptRun() - { - return reinterpret_cast<FontPlatformData*>(m_item.font->userData); - } + const FontPlatformData* fontPlatformDataForScriptRun() { return reinterpret_cast<FontPlatformData*>(m_item.font->userData); } - float widthOfFullRun() - { - float widthSum = 0; - while (nextScriptRun()) - widthSum += width(); +private: + const TextRun& getTextRun(const TextRun&); + const TextRun& getNormalizedTextRun(const TextRun&); + void setupFontForScriptRun(); + HB_FontRec* allocHarfbuzzFont(); + void deleteGlyphArrays(); + void createGlyphArrays(int); + void resetGlyphArrays(); + void shapeGlyphs(); + void setGlyphXPositions(bool); + void mirrorCharacters(UChar*, const UChar*, int) const; + + // This matches the logic in RenderBlock::findNextLineBreak + static bool isCodepointSpace(HB_UChar16 c) { return c == ' ' || c == '\t'; } - return widthSum; - } + const Font* const m_font; + HB_ShaperItem m_item; + uint16_t* m_glyphs16; // A vector of 16-bit glyph ids. + SkScalar* m_xPositions; // A vector of x positions for each glyph. + ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|. + const unsigned m_startingX; // Offset in pixels of the first script run. + unsigned m_offsetX; // Offset in pixels to the start of the next script run. + unsigned m_pixelWidth; // Width (in px) of the current script run. + unsigned m_numCodePoints; // Code points in current script run. + unsigned m_glyphsArrayCapacity; // Current size of all the Harfbuzz arrays. -private: - const TextRun& getTextRun(const TextRun& originalRun) - { - // Normalize the text run in two ways: - // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks - // (U+0300..) are used in the run. This conversion is necessary since most OpenType - // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in - // their GSUB tables. - // - // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since - // the API returns FALSE (= not normalized) for complex runs that don't require NFC - // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, - // Harfbuzz will do the same thing for us using the GSUB table. - // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs - // for characters like '\n' otherwise. - for (int i = 0; i < originalRun.length(); ++i) { - UChar ch = originalRun[i]; - UBlockCode block = ::ublock_getCode(ch); - if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' ')) { - return getNormalizedTextRun(originalRun); - } - } - return originalRun; - } + OwnPtr<TextRun> m_normalizedRun; + OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run. + const TextRun& m_run; + bool m_iterateBackwards; + int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break. + float m_padding; // pixels to be distributed over the line at word breaks. + float m_padPerWordBreak; // pixels to be added to each word break. + float m_padError; // |m_padPerWordBreak| might have a fractional component. + // Since we only add a whole number of padding pixels at + // each word break we accumulate error. This is the + // number of pixels that we are behind so far. + unsigned m_letterSpacing; // pixels to be added after each glyph. +}; - const TextRun& getNormalizedTextRun(const TextRun& originalRun) - { - icu::UnicodeString normalizedString; - UErrorCode error = U_ZERO_ERROR; - icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error); - if (U_FAILURE(error)) - return originalRun; - - m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]); - normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error); - ASSERT(U_SUCCESS(error)); - - for (int i = 0; i < normalizedString.length(); ++i) { - if (Font::treatAsSpace(m_normalizedBuffer[i])) - m_normalizedBuffer[i] = ' '; - } - m_normalizedRun.set(new TextRun(originalRun)); - m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length()); - return *m_normalizedRun; - } +TextRunWalker::TextRunWalker(const TextRun& run, unsigned startingX, const Font* font) + : m_font(font) + , m_startingX(startingX) + , m_offsetX(m_startingX) + , m_run(getTextRun(run)) + , m_iterateBackwards(m_run.rtl()) + , m_wordSpacingAdjustment(0) + , m_padding(0) + , m_padError(0) +{ + // Do not use |run| inside this constructor. Use |m_run| instead. - void setupFontForScriptRun() - { - const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; - const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData(); - m_item.face = platformData.harfbuzzFace(); - void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData); - m_item.font->userData = opaquePlatformData; - } + memset(&m_item, 0, sizeof(m_item)); + // We cannot know, ahead of time, how many glyphs a given script run + // will produce. We take a guess that script runs will not produce more + // than twice as many glyphs as there are code points plus a bit of + // padding and fallback if we find that we are wrong. + createGlyphArrays((m_run.length() + 2) * 2); - HB_FontRec* allocHarfbuzzFont() - { - HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec))); - memset(font, 0, sizeof(HB_FontRec)); - font->klass = &harfbuzzSkiaClass; - font->userData = 0; - // The values which harfbuzzSkiaClass returns are already scaled to - // pixel units, so we just set all these to one to disable further - // scaling. - font->x_ppem = 1; - font->y_ppem = 1; - font->x_scale = 1; - font->y_scale = 1; - - return font; - } + m_item.log_clusters = new unsigned short[m_run.length()]; + + m_item.face = 0; + m_item.font = allocHarfbuzzFont(); + + m_item.item.bidiLevel = m_run.rtl(); - void deleteGlyphArrays() - { - delete[] m_item.glyphs; - delete[] m_item.attributes; - delete[] m_item.advances; - delete[] m_item.offsets; - delete[] m_glyphs16; - delete[] m_xPositions; + int length = m_run.length(); + m_item.stringLength = length; + + if (!m_item.item.bidiLevel) + m_item.string = m_run.characters(); + else { + // Assume mirrored character is in the same Unicode multilingual plane as the original one. + UChar* string = new UChar[length]; + mirrorCharacters(string, m_run.characters(), length); + m_item.string = string; } - void createGlyphArrays(int size) - { - m_item.glyphs = new HB_Glyph[size]; - memset(m_item.glyphs, 0, size * sizeof(HB_Glyph)); - m_item.attributes = new HB_GlyphAttributes[size]; - memset(m_item.attributes, 0, size * sizeof(HB_GlyphAttributes)); - m_item.advances = new HB_Fixed[size]; - memset(m_item.advances, 0, size * sizeof(HB_Fixed)); - m_item.offsets = new HB_FixedPoint[size]; - memset(m_item.offsets, 0, size * sizeof(HB_FixedPoint)); - - m_glyphs16 = new uint16_t[size]; - m_xPositions = new SkScalar[size]; - - m_item.num_glyphs = size; + reset(); +} + +TextRunWalker::~TextRunWalker() +{ + fastFree(m_item.font); + deleteGlyphArrays(); + delete[] m_item.log_clusters; + if (m_item.item.bidiLevel) + delete[] m_item.string; +} + +bool TextRunWalker::isWordBreak(unsigned index, bool isRTL) +{ + if (!isRTL) + return index && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index - 1]); + return index != m_item.stringLength - 1 && isCodepointSpace(m_item.string[index]) && !isCodepointSpace(m_item.string[index + 1]); +} + +// setPadding sets a number of pixels to be distributed across the TextRun. +// WebKit uses this to justify text. +void TextRunWalker::setPadding(int padding) +{ + m_padding = padding; + if (!m_padding) + return; + + // If we have padding to distribute, then we try to give an equal + // amount to each space. The last space gets the smaller amount, if + // any. + unsigned numWordBreaks = 0; + bool isRTL = m_iterateBackwards; + + for (unsigned i = 0; i < m_item.stringLength; i++) { + if (isWordBreak(i, isRTL)) + numWordBreaks++; } - void shapeGlyphs() - { - for (;;) { - if (HB_ShapeItem(&m_item)) - break; + if (numWordBreaks) + m_padPerWordBreak = m_padding / numWordBreaks; + else + m_padPerWordBreak = 0; +} + +void TextRunWalker::reset() +{ + if (m_iterateBackwards) + m_indexOfNextScriptRun = m_run.length() - 1; + else + m_indexOfNextScriptRun = 0; + m_offsetX = m_startingX; +} - // We overflowed our arrays. Resize and retry. - // HB_ShapeItem fills in m_item.num_glyphs with the needed size. - deleteGlyphArrays(); - // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer - // shaper (at least) can fail because of insufficient glyph buffers - // and request 0 additional glyphs: throwing us into an infinite - // loop. - createGlyphArrays(m_item.num_glyphs + 1); +void TextRunWalker::setBackwardsIteration(bool isBackwards) +{ + m_iterateBackwards = isBackwards; + reset(); +} + +// Advance to the next script run, returning false when the end of the +// TextRun has been reached. +bool TextRunWalker::nextScriptRun() +{ + if (m_iterateBackwards) { + // In right-to-left mode we need to render the shaped glyph backwards and + // also render the script runs themselves backwards. So given a TextRun: + // AAAAAAACTTTTTTT (A = Arabic, C = Common, T = Thai) + // we render: + // TTTTTTCAAAAAAA + // (and the glyphs in each A, C and T section are backwards too) + if (!hb_utf16_script_run_prev(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) + return false; + } else { + if (!hb_utf16_script_run_next(&m_numCodePoints, &m_item.item, m_run.characters(), m_run.length(), &m_indexOfNextScriptRun)) + return false; + + // It is actually wrong to consider script runs at all in this code. + // Other WebKit code (e.g. Mac) segments complex text just by finding + // the longest span of text covered by a single font. + // But we currently need to call hb_utf16_script_run_next anyway to fill + // in the harfbuzz data structures to e.g. pick the correct script's shaper. + // So we allow that to run first, then do a second pass over the range it + // found and take the largest subregion that stays within a single font. + const FontData* glyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; + unsigned endOfRun; + for (endOfRun = 1; endOfRun < m_item.item.length; ++endOfRun) { + const FontData* nextGlyphData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos + endOfRun], false, false).fontData; + if (nextGlyphData != glyphData) + break; } + m_item.item.length = endOfRun; + m_indexOfNextScriptRun = m_item.item.pos + endOfRun; } - void setGlyphXPositions(bool isRTL) - { - double position = 0; - // logClustersIndex indexes logClusters for the first (or last when - // RTL) codepoint of the current glyph. Each time we advance a glyph, - // we skip over all the codepoints that contributed to the current - // glyph. - unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0; - - for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) { - // Glyphs are stored in logical order, but for layout purposes we - // always go left to right. - int i = isRTL ? m_item.num_glyphs - iter - 1 : iter; - - m_glyphs16[i] = m_item.glyphs[i]; - double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x); - m_xPositions[i] = m_offsetX + position + offsetX; - - double advance = truncateFixedPointToInteger(m_item.advances[i]); - // The first half of the conjuction works around the case where - // output glyphs aren't associated with any codepoints by the - // clusters log. - if (logClustersIndex < m_item.item.length - && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) { - advance += m_wordSpacingAdjustment; - - if (m_padding > 0) { - unsigned toPad = roundf(m_padPerWordBreak + m_padError); - m_padError += m_padPerWordBreak - toPad; - - if (m_padding < toPad) - toPad = m_padding; - m_padding -= toPad; - advance += toPad; - } - } + setupFontForScriptRun(); + shapeGlyphs(); + setGlyphXPositions(rtl()); - // We would like to add m_letterSpacing after each cluster, but I - // don't know where the cluster information is. This is typically - // fine for Roman languages, but breaks more complex languages - // terribly. - // advance += m_letterSpacing; - - if (isRTL) { - while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i) - logClustersIndex--; - } else { - while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i) - logClustersIndex++; - } + return true; +} - position += advance; - } +float TextRunWalker::widthOfFullRun() +{ + float widthSum = 0; + while (nextScriptRun()) + widthSum += width(); - m_pixelWidth = position; - m_offsetX += m_pixelWidth; + return widthSum; +} + +const TextRun& TextRunWalker::getTextRun(const TextRun& originalRun) +{ + // Normalize the text run in two ways: + // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks + // (U+0300..) are used in the run. This conversion is necessary since most OpenType + // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in + // their GSUB tables. + // + // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since + // the API returns FALSE (= not normalized) for complex runs that don't require NFC + // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, + // Harfbuzz will do the same thing for us using the GSUB table. + // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs + // for characters like '\n' otherwise. + for (int i = 0; i < originalRun.length(); ++i) { + UChar ch = originalRun[i]; + UBlockCode block = ::ublock_getCode(ch); + if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS || (Font::treatAsSpace(ch) && ch != ' ')) + return getNormalizedTextRun(originalRun); + } + return originalRun; +} + +const TextRun& TextRunWalker::getNormalizedTextRun(const TextRun& originalRun) +{ + icu::UnicodeString normalizedString; + UErrorCode error = U_ZERO_ERROR; + icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error); + if (U_FAILURE(error)) + return originalRun; + + m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]); + normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error); + ASSERT(U_SUCCESS(error)); + + for (int i = 0; i < normalizedString.length(); ++i) { + if (Font::treatAsSpace(m_normalizedBuffer[i])) + m_normalizedBuffer[i] = ' '; } - static bool isCodepointSpace(HB_UChar16 c) - { - // This matches the logic in RenderBlock::findNextLineBreak - return c == ' ' || c == '\t'; + m_normalizedRun.set(new TextRun(originalRun)); + m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length()); + return *m_normalizedRun; +} + +void TextRunWalker::setupFontForScriptRun() +{ + const FontData* fontData = m_font->glyphDataForCharacter(m_item.string[m_item.item.pos], false, false).fontData; + const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData(); + m_item.face = platformData.harfbuzzFace(); + void* opaquePlatformData = const_cast<FontPlatformData*>(&platformData); + m_item.font->userData = opaquePlatformData; +} + +HB_FontRec* TextRunWalker::allocHarfbuzzFont() +{ + HB_FontRec* font = reinterpret_cast<HB_FontRec*>(fastMalloc(sizeof(HB_FontRec))); + memset(font, 0, sizeof(HB_FontRec)); + font->klass = &harfbuzzSkiaClass; + font->userData = 0; + // The values which harfbuzzSkiaClass returns are already scaled to + // pixel units, so we just set all these to one to disable further + // scaling. + font->x_ppem = 1; + font->y_ppem = 1; + font->x_scale = 1; + font->y_scale = 1; + + return font; +} + +void TextRunWalker::deleteGlyphArrays() +{ + delete[] m_item.glyphs; + delete[] m_item.attributes; + delete[] m_item.advances; + delete[] m_item.offsets; + delete[] m_glyphs16; + delete[] m_xPositions; +} + +void TextRunWalker::createGlyphArrays(int size) +{ + m_item.glyphs = new HB_Glyph[size]; + m_item.attributes = new HB_GlyphAttributes[size]; + m_item.advances = new HB_Fixed[size]; + m_item.offsets = new HB_FixedPoint[size]; + + m_glyphs16 = new uint16_t[size]; + m_xPositions = new SkScalar[size]; + + m_item.num_glyphs = size; + m_glyphsArrayCapacity = size; // Save the GlyphArrays size. + resetGlyphArrays(); +} + +void TextRunWalker::resetGlyphArrays() +{ + int size = m_item.num_glyphs; + // All the types here don't have pointers. It is safe to reset to + // zero unless Harfbuzz breaks the compatibility in the future. + memset(m_item.glyphs, 0, size * sizeof(HB_Glyph)); + memset(m_item.attributes, 0, size * sizeof(HB_GlyphAttributes)); + memset(m_item.advances, 0, size * sizeof(HB_Fixed)); + memset(m_item.offsets, 0, size * sizeof(HB_FixedPoint)); + memset(m_glyphs16, 0, size * sizeof(uint16_t)); + memset(m_xPositions, 0, size * sizeof(SkScalar)); +} + +void TextRunWalker::shapeGlyphs() +{ + // HB_ShapeItem() resets m_item.num_glyphs. If the previous call to + // HB_ShapeItem() used less space than was available, the capacity of + // the array may be larger than the current value of m_item.num_glyphs. + // So, we need to reset the num_glyphs to the capacity of the array. + m_item.num_glyphs = m_glyphsArrayCapacity; + resetGlyphArrays(); + while (!HB_ShapeItem(&m_item)) { + // We overflowed our arrays. Resize and retry. + // HB_ShapeItem fills in m_item.num_glyphs with the needed size. + deleteGlyphArrays(); + // The |+ 1| here is a workaround for a bug in Harfbuzz: the Khmer + // shaper (at least) can fail because of insufficient glyph buffers + // and request 0 additional glyphs: throwing us into an infinite + // loop. + createGlyphArrays(m_item.num_glyphs + 1); } +} + +void TextRunWalker::setGlyphXPositions(bool isRTL) +{ + double position = 0; + // logClustersIndex indexes logClusters for the first (or last when + // RTL) codepoint of the current glyph. Each time we advance a glyph, + // we skip over all the codepoints that contributed to the current + // glyph. + unsigned logClustersIndex = isRTL ? m_item.num_glyphs - 1 : 0; + + for (unsigned iter = 0; iter < m_item.num_glyphs; ++iter) { + // Glyphs are stored in logical order, but for layout purposes we + // always go left to right. + int i = isRTL ? m_item.num_glyphs - iter - 1 : iter; + + m_glyphs16[i] = m_item.glyphs[i]; + double offsetX = truncateFixedPointToInteger(m_item.offsets[i].x); + m_xPositions[i] = m_offsetX + position + offsetX; + + double advance = truncateFixedPointToInteger(m_item.advances[i]); + // The first half of the conjuction works around the case where + // output glyphs aren't associated with any codepoints by the + // clusters log. + if (logClustersIndex < m_item.item.length + && isWordBreak(m_item.item.pos + logClustersIndex, isRTL)) { + advance += m_wordSpacingAdjustment; + + if (m_padding > 0) { + unsigned toPad = roundf(m_padPerWordBreak + m_padError); + m_padError += m_padPerWordBreak - toPad; + + if (m_padding < toPad) + toPad = m_padding; + m_padding -= toPad; + advance += toPad; + } + } - void mirrorCharacters(UChar* destination, const UChar* source, int length) const - { - int position = 0; - bool error = false; - // Iterate characters in source and mirror character if needed. - while (position < length) { - UChar32 character; - int nextPosition = position; - U16_NEXT(source, nextPosition, length, character); - character = u_charMirror(character); - U16_APPEND(destination, position, length, character, error); - ASSERT(!error); - position = nextPosition; + // We would like to add m_letterSpacing after each cluster, but I + // don't know where the cluster information is. This is typically + // fine for Roman languages, but breaks more complex languages + // terribly. + // advance += m_letterSpacing; + + if (isRTL) { + while (logClustersIndex > 0 && logClusters()[logClustersIndex] == i) + logClustersIndex--; + } else { + while (logClustersIndex < m_item.item.length && logClusters()[logClustersIndex] == i) + logClustersIndex++; } + + position += advance; } - const Font* const m_font; - HB_ShaperItem m_item; - uint16_t* m_glyphs16; // A vector of 16-bit glyph ids. - SkScalar* m_xPositions; // A vector of x positions for each glyph. - ssize_t m_indexOfNextScriptRun; // Indexes the script run in |m_run|. - const unsigned m_startingX; // Offset in pixels of the first script run. - unsigned m_offsetX; // Offset in pixels to the start of the next script run. - unsigned m_pixelWidth; // Width (in px) of the current script run. - unsigned m_numCodePoints; // Code points in current script run. + m_pixelWidth = position; + m_offsetX += m_pixelWidth; +} - OwnPtr<TextRun> m_normalizedRun; - OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run. - const TextRun& m_run; - bool m_iterateBackwards; - int m_wordSpacingAdjustment; // delta adjustment (pixels) for each word break. - float m_padding; // pixels to be distributed over the line at word breaks. - float m_padPerWordBreak; // pixels to be added to each word break. - float m_padError; // |m_padPerWordBreak| might have a fractional component. - // Since we only add a whole number of padding pixels at - // each word break we accumulate error. This is the - // number of pixels that we are behind so far. - unsigned m_letterSpacing; // pixels to be added after each glyph. -}; +void TextRunWalker::mirrorCharacters(UChar* destination, const UChar* source, int length) const +{ + int position = 0; + bool error = false; + // Iterate characters in source and mirror character if needed. + while (position < length) { + UChar32 character; + int nextPosition = position; + U16_NEXT(source, nextPosition, length, character); + character = u_charMirror(character); + U16_APPEND(destination, position, length, character, error); + ASSERT(!error); + position = nextPosition; + } +} static void setupForTextPainting(SkPaint* paint, SkColor color) { diff --git a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp index 46aecf4..697cf5e 100644 --- a/WebCore/platform/graphics/chromium/GLES2Canvas.cpp +++ b/WebCore/platform/graphics/chromium/GLES2Canvas.cpp @@ -97,7 +97,7 @@ void GLES2Canvas::clearRect(const FloatRect& rect) } else { save(); setCompositeOperation(CompositeClear); - fillRect(rect, Color(RGBA32(0)), DeviceColorSpace); + fillRect(rect, Color(RGBA32(0)), ColorSpaceDeviceRGB); restore(); } } @@ -120,7 +120,7 @@ void GLES2Canvas::fillRect(const FloatRect& rect, const Color& color, ColorSpace void GLES2Canvas::fillRect(const FloatRect& rect) { - fillRect(rect, m_state->m_fillColor, DeviceColorSpace); + fillRect(rect, m_state->m_fillColor, ColorSpaceDeviceRGB); } void GLES2Canvas::setFillColor(const Color& color, ColorSpace colorSpace) diff --git a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp index c97be82..afcc98c 100644 --- a/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/ImageLayerChromium.cpp @@ -75,6 +75,14 @@ void ImageLayerChromium::updateContents() { ASSERT(layerRenderer()); + // FIXME: Remove this test when tiled layers are implemented. + if (requiresClippedUpdateRect()) { + // Use the base version of updateContents which draws a subset of the + // image to a bitmap, as the pixel contents can't be uploaded directly. + ContentLayerChromium::updateContents(); + return; + } + void* pixels = 0; IntSize requiredTextureSize; IntSize bitmapSize; @@ -136,12 +144,6 @@ void ImageLayerChromium::updateContents() #else #error "Need to implement for your platform." #endif - // FIXME: Remove this test when tiled layers are implemented. - m_skipsDraw = false; - if (!layerRenderer()->checkTextureSize(requiredTextureSize)) { - m_skipsDraw = true; - return; - } unsigned textureId = m_contentsTexture; if (!textureId) diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp index 5dba58d..79f18f0 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp @@ -174,6 +174,11 @@ LayerChromium::~LayerChromium() void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer) { + // If we're changing layer renderers then we need to free up any resources + // allocated by the old renderer. + if (layerRenderer() && layerRenderer() != renderer) + cleanupResources(); + m_layerRenderer = renderer; } @@ -446,15 +451,12 @@ void LayerChromium::drawDebugBorder() GLC(context, context->drawElements(GraphicsContext3D::LINE_LOOP, 4, GraphicsContext3D::UNSIGNED_SHORT, 6 * sizeof(unsigned short))); } -const FloatRect LayerChromium::getDrawRect() const +const IntRect LayerChromium::getDrawRect() const { // Form the matrix used by the shader to map the corners of the layer's // bounds into the view space. - TransformationMatrix renderMatrix = drawTransform(); - renderMatrix.scale3d(bounds().width(), bounds().height(), 1); - - FloatRect layerRect(-0.5, -0.5, 1, 1); - FloatRect mappedRect = renderMatrix.mapRect(layerRect); + FloatRect layerRect(-0.5 * bounds().width(), -0.5 * bounds().height(), bounds().width(), bounds().height()); + IntRect mappedRect = enclosingIntRect(drawTransform().mapRect(layerRect)); return mappedRect; } diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h index 0a66318..3956e28 100644 --- a/WebCore/platform/graphics/chromium/LayerChromium.h +++ b/WebCore/platform/graphics/chromium/LayerChromium.h @@ -156,7 +156,7 @@ public: bool contentsDirty() { return m_contentsDirty; } // Returns the rect containtaining this layer in the current view's coordinate system. - const FloatRect getDrawRect() const; + const IntRect getDrawRect() const; // These methods typically need to be overwritten by derived classes. virtual bool drawsContent() { return false; } @@ -202,6 +202,11 @@ protected: GraphicsLayerChromium* m_owner; LayerChromium(GraphicsLayerChromium* owner); + // This is called to clean up resources being held in the same context as + // layerRendererContext(). Subclasses should override this method if they + // hold context-dependent resources such as textures. + virtual void cleanupResources() { } + LayerRendererChromium* layerRenderer() const { return m_layerRenderer.get(); } GraphicsContext3D* layerRendererContext() const; diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp index c4031e5..e93e296 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp @@ -73,7 +73,7 @@ static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b) return transformA.m43() < transformB.m43(); } -PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<GraphicsContext3D> context) +PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context) { if (!context) return 0; @@ -85,7 +85,7 @@ PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassOwnPtr<Graph return layerRenderer.release(); } -LayerRendererChromium::LayerRendererChromium(PassOwnPtr<GraphicsContext3D> context) +LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> context) : m_rootLayerTextureId(0) , m_rootLayerTextureWidth(0) , m_rootLayerTextureHeight(0) @@ -127,7 +127,6 @@ void LayerRendererChromium::setRootLayerCanvasSize(const IntSize& size) // the old ones. m_rootLayerCanvas = new skia::PlatformCanvas(size.width(), size.height(), false); m_rootLayerSkiaContext = new PlatformContextSkia(m_rootLayerCanvas.get()); - m_rootLayerSkiaContext->setDrawingToImageBuffer(true); m_rootLayerGraphicsContext = new GraphicsContext(reinterpret_cast<PlatformGraphicsContext*>(m_rootLayerSkiaContext.get())); #elif PLATFORM(CG) // Release the previous CGBitmapContext before reallocating the backing store as a precaution. @@ -204,6 +203,8 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons GLC(m_context, m_context->disable(GraphicsContext3D::CULL_FACE)); GLC(m_context, m_context->depthFunc(GraphicsContext3D::LEQUAL)); GLC(m_context, m_context->clearStencil(0)); + // Blending disabled by default. Root layer alpha channel on Windows is incorrect when Skia uses ClearType. + GLC(m_context, m_context->disable(GraphicsContext3D::BLEND)); if (m_scrollPosition == IntPoint(-1, -1)) { m_scrollPosition = scrollPosition; @@ -284,11 +285,15 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect const ContentLayerChromium::SharedValues* contentLayerValues = contentLayerSharedValues(); useShader(contentLayerValues->contentShaderProgram()); GLC(m_context, m_context->uniform1i(contentLayerValues->shaderSamplerLocation(), 0)); + // Mask out writes to alpha channel: ClearType via Skia results in invalid + // zero alpha values on text glyphs. The root layer is always opaque. + GLC(m_context, m_context->colorMask(true, true, true, false)); TransformationMatrix layerMatrix; layerMatrix.translate3d(visibleRect.width() * 0.5f, visibleRect.height() * 0.5f, 0); LayerChromium::drawTexturedQuad(m_context.get(), m_projectionMatrix, layerMatrix, visibleRect.width(), visibleRect.height(), 1, contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation()); + GLC(m_context, m_context->colorMask(true, true, true, true)); // If culling is enabled then we will cull the backface. GLC(m_context, m_context->cullFace(GraphicsContext3D::BACK)); @@ -302,8 +307,9 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect GLC(m_context, m_context->enable(GraphicsContext3D::BLEND)); GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA)); - // Set the rootVisibleRect --- used by subsequent drawLayers calls + // Set the root visible/content rects --- used by subsequent drawLayers calls. m_rootVisibleRect = visibleRect; + m_rootContentRect = contentRect; // Traverse the layer tree and update the layer transforms. float opacity = 1; @@ -315,7 +321,7 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect // Enable scissoring to avoid rendering composited layers over the scrollbars. GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST)); - FloatRect scissorRect(contentRect); + IntRect scissorRect(contentRect); // The scissorRect should not include the scroll offset. scissorRect.move(-m_scrollPosition.x(), -m_scrollPosition.y()); @@ -328,9 +334,10 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect // Traverse the layer tree one more time to draw the layers. for (size_t i = 0; i < sublayers.size(); i++) - drawLayersRecursive(sublayers[i].get(), scissorRect); + drawLayersRecursive(sublayers[i].get()); GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST)); + GLC(m_context, m_context->disable(GraphicsContext3D::BLEND)); } void LayerRendererChromium::finish() @@ -494,14 +501,14 @@ void LayerRendererChromium::drawLayerIntoStencilBuffer(LayerChromium* layer, boo } // Recursively walk the layer tree and draw the layers. -void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const FloatRect& scissorRect) +void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer) { static bool depthTestEnabledForSubtree = false; static int currentStencilValue = 0; // Check if the layer falls within the visible bounds of the page. - FloatRect layerRect = layer->getDrawRect(); - bool isLayerVisible = scissorRect.intersects(layerRect); + IntRect layerRect = layer->getDrawRect(); + bool isLayerVisible = m_currentScissorRect.intersects(layerRect); // Enable depth testing for this layer and all its descendants if preserves3D is set. bool mustClearDepth = false; @@ -520,15 +527,16 @@ void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const Floa // FIXME: We should check here if the layer has descendants that draw content // before we setup for clipping. - FloatRect currentScissorRect = scissorRect; + IntRect previousScissorRect = m_currentScissorRect; bool mustResetScissorRect = false; bool didStencilDraw = false; if (layer->masksToBounds()) { // If the layer isn't rotated then we can use scissoring otherwise we need // to clip using the stencil buffer. if (layer->drawTransform().isIdentityOrTranslation()) { + IntRect currentScissorRect = previousScissorRect; currentScissorRect.intersect(layerRect); - if (currentScissorRect != scissorRect) { + if (currentScissorRect != previousScissorRect) { scissorToRect(currentScissorRect); mustResetScissorRect = true; } @@ -573,11 +581,11 @@ void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const Floa std::stable_sort(sublayerList.begin(), sublayerList.end(), compareLayerZ); for (i = 0; i < sublayerList.size(); i++) - drawLayersRecursive(sublayerList[i], currentScissorRect); + drawLayersRecursive(sublayerList[i]); } else { const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers(); for (size_t i = 0; i < sublayers.size(); i++) - drawLayersRecursive(sublayers[i].get(), currentScissorRect); + drawLayersRecursive(sublayers[i].get()); } if (didStencilDraw) { @@ -593,7 +601,7 @@ void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer, const Floa } if (mustResetScissorRect) { - scissorToRect(scissorRect); + scissorToRect(previousScissorRect); } if (mustClearDepth) { @@ -629,11 +637,12 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer) // Sets the scissor region to the given rectangle. The coordinate system for the // scissorRect has its origin at the top left corner of the current visible rect. -void LayerRendererChromium::scissorToRect(const FloatRect& scissorRect) +void LayerRendererChromium::scissorToRect(const IntRect& scissorRect) { // Compute the lower left corner of the scissor rect. - float bottom = std::max((float)m_rootVisibleRect.height() - scissorRect.bottom(), 0.f); + int bottom = std::max(m_rootVisibleRect.height() - scissorRect.bottom(), 0); GLC(m_context, m_context->scissor(scissorRect.x(), bottom, scissorRect.width(), scissorRect.height())); + m_currentScissorRect = scissorRect; } bool LayerRendererChromium::makeContextCurrent() diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/WebCore/platform/graphics/chromium/LayerRendererChromium.h index b714584..6a06105 100644 --- a/WebCore/platform/graphics/chromium/LayerRendererChromium.h +++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.h @@ -59,9 +59,8 @@ class GraphicsContext3D; // Class that handles drawing of composited render layers using GL. class LayerRendererChromium : public RefCounted<LayerRendererChromium> { public: - static PassRefPtr<LayerRendererChromium> create(PassOwnPtr<GraphicsContext3D> graphicsContext3D); + static PassRefPtr<LayerRendererChromium> create(PassRefPtr<GraphicsContext3D> graphicsContext3D); - LayerRendererChromium(PassOwnPtr<GraphicsContext3D> graphicsContext3D); ~LayerRendererChromium(); GraphicsContext3D* context(); @@ -93,6 +92,8 @@ public: unsigned createLayerTexture(); void deleteLayerTexture(unsigned); + IntRect currentScissorRect() const { return m_currentScissorRect; } + static void debugGLCall(GraphicsContext3D*, const char* command, const char* file, int line); const TransformationMatrix& projectionMatrix() const { return m_projectionMatrix; } @@ -109,12 +110,15 @@ public: void resizeOnscreenContent(const IntSize&); IntSize rootLayerTextureSize() const { return IntSize(m_rootLayerTextureWidth, m_rootLayerTextureHeight); } + IntRect rootLayerContentRect() const { return m_rootContentRect; } void getFramebufferPixels(void *pixels, const IntRect& rect); private: + explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D> graphicsContext3D); + void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity); - void drawLayersRecursive(LayerChromium*, const FloatRect& scissorRect); + void drawLayersRecursive(LayerChromium*); void drawLayer(LayerChromium*); @@ -122,7 +126,7 @@ private: void drawLayerIntoStencilBuffer(LayerChromium*, bool decrement); - void scissorToRect(const FloatRect&); + void scissorToRect(const IntRect&); bool makeContextCurrent(); @@ -160,6 +164,8 @@ private: IntSize m_rootLayerCanvasSize; IntRect m_rootVisibleRect; + IntRect m_rootContentRect; + IntRect m_currentScissorRect; int m_maxTextureSize; @@ -174,7 +180,7 @@ private: OwnPtr<CanvasLayerChromium::SharedValues> m_canvasLayerSharedValues; OwnPtr<VideoLayerChromium::SharedValues> m_videoLayerSharedValues; - OwnPtr<GraphicsContext3D> m_context; + RefPtr<GraphicsContext3D> m_context; }; // Setting DEBUG_GL_CALLS to 1 will call glGetError() after almost every GL diff --git a/WebCore/platform/graphics/chromium/TransparencyWin.cpp b/WebCore/platform/graphics/chromium/TransparencyWin.cpp index 47cc894..4dc2157 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, DeviceColorSpace); + m_drawContext->fillRect(IntRect(IntPoint(0, 0), m_layerSize), Color::white, ColorSpaceDeviceRGB); // Layer rect represents the part of the original layer. } diff --git a/WebCore/platform/graphics/chromium/VideoFrameChromium.h b/WebCore/platform/graphics/chromium/VideoFrameChromium.h index 34e922b..e176b0c 100644 --- a/WebCore/platform/graphics/chromium/VideoFrameChromium.h +++ b/WebCore/platform/graphics/chromium/VideoFrameChromium.h @@ -63,10 +63,7 @@ public: enum SurfaceType { TypeSystemMemory, - TypeOMXBufferHead, - TypeEGLImage, - TypeMFBuffer, - TypeDirect3DSurface + TypeTexture, }; virtual SurfaceType surfaceType() const = 0; @@ -76,6 +73,7 @@ public: virtual unsigned planes() const = 0; virtual int stride(unsigned plane) const = 0; virtual const void* data(unsigned plane) const = 0; + virtual unsigned texture(unsigned plane) const = 0; virtual const IntSize requiredTextureSize(unsigned plane) const = 0; }; diff --git a/WebCore/platform/graphics/chromium/VideoFrameProvider.h b/WebCore/platform/graphics/chromium/VideoFrameProvider.h index f0bad08..c596f87 100644 --- a/WebCore/platform/graphics/chromium/VideoFrameProvider.h +++ b/WebCore/platform/graphics/chromium/VideoFrameProvider.h @@ -37,6 +37,8 @@ namespace WebCore { class VideoFrameProvider { public: + virtual ~VideoFrameProvider() { } + // This function returns a pointer to a VideoFrameChromium, which is // the WebCore wrapper for a video frame in Chromium. getCurrentFrame() // places a lock on the frame in Chromium. Calls to this method should diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp index 26641a9..46c73a1 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp @@ -175,16 +175,22 @@ VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameP , m_skipsDraw(true) , m_frameFormat(VideoFrameChromium::Invalid) , m_provider(provider) + , m_currentFrame(0) { - for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { - m_textures[plane] = 0; - m_textureSizes[plane] = IntSize(); - m_frameSizes[plane] = IntSize(); - } + resetFrameParameters(); } VideoLayerChromium::~VideoLayerChromium() { + cleanupResources(); +} + +void VideoLayerChromium::cleanupResources() +{ + releaseCurrentFrame(); + if (!layerRenderer()) + return; + GraphicsContext3D* context = layerRendererContext(); for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { if (m_textures[plane]) @@ -218,6 +224,14 @@ void VideoLayerChromium::updateContents() return; } + if (frame->surfaceType() == VideoFrameChromium::TypeTexture) { + releaseCurrentFrame(); + saveCurrentFrame(frame); + m_dirtyRect.setSize(FloatSize()); + m_contentsDirty = false; + return; + } + // Allocate textures for planes if they are not allocated already, or // reallocate textures that are the wrong size for the frame. GraphicsContext3D* context = layerRendererContext(); @@ -236,6 +250,7 @@ void VideoLayerChromium::updateContents() m_dirtyRect.setSize(FloatSize()); m_contentsDirty = false; + m_provider->putCurrentFrame(frame); } @@ -319,6 +334,17 @@ void VideoLayerChromium::draw() notImplemented(); break; } + releaseCurrentFrame(); +} + +void VideoLayerChromium::releaseCurrentFrame() +{ + if (!m_currentFrame) + return; + + m_provider->putCurrentFrame(m_currentFrame); + m_currentFrame = 0; + resetFrameParameters(); } void VideoLayerChromium::drawYUV(const SharedValues* sv) @@ -370,6 +396,26 @@ void VideoLayerChromium::drawRGBA(const SharedValues* sv) sv->rgbaShaderMatrixLocation(), sv->rgbaAlphaLocation()); } +void VideoLayerChromium::resetFrameParameters() +{ + for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) { + m_textures[plane] = 0; + m_textureSizes[plane] = IntSize(); + m_frameSizes[plane] = IntSize(); + } +} + +void VideoLayerChromium::saveCurrentFrame(VideoFrameChromium* frame) +{ + ASSERT(!m_currentFrame); + m_currentFrame = frame; + for (unsigned plane = 0; plane < frame->planes(); plane++) { + m_textures[plane] = frame->texture(plane); + m_textureSizes[plane] = frame->requiredTextureSize(plane); + m_frameSizes[plane] = m_textureSizes[plane]; + } +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.h b/WebCore/platform/graphics/chromium/VideoLayerChromium.h index 620d1a7..05b6578 100644 --- a/WebCore/platform/graphics/chromium/VideoLayerChromium.h +++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.h @@ -49,6 +49,10 @@ public: virtual bool drawsContent() { return true; } virtual void draw(); + // This function is called by VideoFrameProvider. When this method is called + // putCurrentFrame() must be called to return the frame currently held. + void releaseCurrentFrame(); + class SharedValues { public: explicit SharedValues(GraphicsContext3D*); @@ -66,7 +70,7 @@ public: int rgbaAlphaLocation() const { return m_rgbaAlphaLocation; } int rgbaTextureLocation() const { return m_rgbaTextureLocation; } int ccMatrixLocation() const { return m_ccMatrixLocation; } - bool initialized() const { return m_initialized; }; + bool initialized() const { return m_initialized; } private: GraphicsContext3D* m_context; unsigned m_yuvShaderProgram; @@ -85,8 +89,12 @@ public: bool m_initialized; }; +protected: + virtual void cleanupResources(); + private: VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider*); + static unsigned determineTextureFormat(VideoFrameChromium*); bool allocateTexturesIfNeeded(GraphicsContext3D*, VideoFrameChromium*, unsigned textureFormat); void updateYUVContents(GraphicsContext3D*, const VideoFrameChromium*); @@ -95,12 +103,16 @@ private: void updateTexture(GraphicsContext3D*, unsigned textureId, const IntSize& dimensions, unsigned textureFormat, const void* data); void drawYUV(const SharedValues*); void drawRGBA(const SharedValues*); + void resetFrameParameters(); + void saveCurrentFrame(VideoFrameChromium*); static const float yuv2RGB[9]; bool m_skipsDraw; VideoFrameChromium::Format m_frameFormat; - OwnPtr<VideoFrameProvider> m_provider; + VideoFrameProvider* m_provider; + VideoFrameChromium* m_currentFrame; + unsigned m_textures[3]; IntSize m_textureSizes[3]; IntSize m_frameSizes[3]; diff --git a/WebCore/platform/graphics/efl/ImageEfl.cpp b/WebCore/platform/graphics/efl/ImageEfl.cpp index 112770f..a86ba4e 100644 --- a/WebCore/platform/graphics/efl/ImageEfl.cpp +++ b/WebCore/platform/graphics/efl/ImageEfl.cpp @@ -32,6 +32,7 @@ #include "BitmapImage.h" #include "SharedBuffer.h" +#include <wtf/text/StringConcatenate.h> #include <cairo.h> namespace WebCore { @@ -51,7 +52,7 @@ static PassRefPtr<SharedBuffer> loadResourceSharedBufferFallback() static PassRefPtr<SharedBuffer> loadResourceSharedBuffer(const char* name) { - RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(String::format(DATA_DIR "/webkit-1.0/images/%s.png", name)); + RefPtr<SharedBuffer> buffer = SharedBuffer::createWithContentsOfFile(makeString(DATA_DIR "/webkit-1.0/images/", name, ".png")); if (buffer) return buffer.release(); return loadResourceSharedBufferFallback(); diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp b/WebCore/platform/graphics/efl/IntRectEfl.cpp index 12407f8..0c92f63 100644 --- a/WebCore/platform/graphics/filters/ImageBufferFilter.cpp +++ b/WebCore/platform/graphics/efl/IntRectEfl.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> - * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2010 Samsung Electronics * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -19,25 +19,22 @@ */ #include "config.h" +#include "IntRect.h" -#if ENABLE(FILTERS) -#include "ImageBufferFilter.h" - -#include "FloatSize.h" +#include <Eina.h> namespace WebCore { -ImageBufferFilter::ImageBufferFilter() - : Filter() +IntRect::IntRect(const Eina_Rectangle& r) + : m_location(IntPoint(r.x, r.y)) + , m_size(r.w, r.h) { - setFilterResolution(FloatSize(1.f, 1.f)); } -PassRefPtr<ImageBufferFilter> ImageBufferFilter::create() +IntRect::operator Eina_Rectangle() const { - return adoptRef(new ImageBufferFilter()); + Eina_Rectangle r = {x(), y(), width(), height()}; + return r; } -} // namespace WebCore - -#endif // ENABLE(FILTERS) +} diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 4185f61..1a40027 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -98,13 +98,13 @@ void FEBlend::apply(Filter* filter) if (m_mode == FEBLEND_MODE_UNKNOWN) return; - if (!effectContext()) + if (!effectContext(filter)) return; - IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates()); + IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArrayB(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 86c37c2..b41d5ad 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -160,11 +160,11 @@ void FEColorMatrix::apply(Filter* filter) if (!in->resultImage()) return; - GraphicsContext* filterContext = effectContext(); + GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); 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 6fe38e4..08d0b1f 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -154,7 +154,7 @@ void FEComponentTransfer::apply(Filter* filter) if (!in->resultImage()) return; - if (!effectContext()) + if (!effectContext(filter)) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; @@ -167,7 +167,7 @@ void FEComponentTransfer::apply(Filter* filter) for (unsigned channel = 0; channel < 4; channel++) (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); - IntRect drawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ImageData> imageData(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 94e2524..2326966 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> * Copyright (C) 2005 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. 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 @@ -112,6 +113,27 @@ inline void arithmetic(const RefPtr<CanvasPixelArray>& srcPixelArrayA, CanvasPix } } } + +void FEComposite::determineAbsolutePaintRect(Filter* filter) +{ + switch (m_type) { + case FECOMPOSITE_OPERATOR_IN: + case FECOMPOSITE_OPERATOR_ATOP: + // For In and Atop the first effect just influences the result of + // the second effect. So just use the absolute paint rect of the second effect here. + setAbsolutePaintRect(inputEffect(1)->absolutePaintRect()); + return; + case FECOMPOSITE_OPERATOR_ARITHMETIC: + // Arithmetic may influnce the compele filter primitive region. So we can't + // optimize the paint region here. + setAbsolutePaintRect(maxEffectRect()); + return; + default: + // Take the union of both input effects. + FilterEffect::determineAbsolutePaintRect(filter); + return; + } +} void FEComposite::apply(Filter* filter) { @@ -122,39 +144,39 @@ void FEComposite::apply(Filter* filter) if (!in->resultImage() || !in2->resultImage()) return; - GraphicsContext* filterContext = effectContext(); + GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; FloatRect srcRect = FloatRect(0, 0, -1, -1); switch (m_type) { case FECOMPOSITE_OPERATOR_OVER: - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); break; case FECOMPOSITE_OPERATOR_IN: filterContext->save(); - filterContext->clipToImageBuffer(in2->resultImage(), drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); + filterContext->clipToImageBuffer(in2->resultImage(), drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); filterContext->restore(); break; case FECOMPOSITE_OPERATOR_OUT: - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates()), srcRect, CompositeDestinationOut); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); + filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect()), srcRect, CompositeDestinationOut); break; case FECOMPOSITE_OPERATOR_ATOP: - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()), srcRect, CompositeSourceAtop); + filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeSourceAtop); break; case FECOMPOSITE_OPERATOR_XOR: - filterContext->drawImageBuffer(in2->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in2->repaintRectInLocalCoordinates())); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates()), srcRect, CompositeXOR); + filterContext->drawImageBuffer(in2->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in2->absolutePaintRect())); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect()), srcRect, CompositeXOR); break; case FECOMPOSITE_OPERATOR_ARITHMETIC: { - IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates()); + IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<ImageData> imageData(in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)); CanvasPixelArray* srcPixelArrayB(imageData->data()); diff --git a/WebCore/platform/graphics/filters/FEComposite.h b/WebCore/platform/graphics/filters/FEComposite.h index 82a3b06..ecdb037 100644 --- a/WebCore/platform/graphics/filters/FEComposite.h +++ b/WebCore/platform/graphics/filters/FEComposite.h @@ -61,6 +61,8 @@ public: virtual void apply(Filter*); virtual void dump(); + + virtual void determineAbsolutePaintRect(Filter*); virtual TextStream& externalRepresentation(TextStream&, int indention) const; diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp index dd66c6a..d487a47 100644 --- a/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.cpp @@ -377,11 +377,11 @@ void FEConvolveMatrix::apply(Filter* filter) if (!in->resultImage()) return; - if (!effectContext()) + if (!effectContext(filter)) return; IntRect imageRect(IntPoint(), resultImage()->size()); - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->filterPrimitiveSubregion()); + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArray; if (m_preserveAlpha) diff --git a/WebCore/platform/graphics/filters/FEConvolveMatrix.h b/WebCore/platform/graphics/filters/FEConvolveMatrix.h index 2fe634f..8d3439e 100644 --- a/WebCore/platform/graphics/filters/FEConvolveMatrix.h +++ b/WebCore/platform/graphics/filters/FEConvolveMatrix.h @@ -75,6 +75,8 @@ public: virtual void apply(Filter*); virtual void dump(); + virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); } + virtual TextStream& externalRepresentation(TextStream&, int indention) const; private: diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp index 6b5dbaa..0c53241 100644 --- a/WebCore/platform/graphics/filters/FEDisplacementMap.cpp +++ b/WebCore/platform/graphics/filters/FEDisplacementMap.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> * Copyright (C) 2005 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. 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 @@ -88,13 +89,13 @@ void FEDisplacementMap::apply(Filter* filter) if (m_xChannelSelector == CHANNEL_UNKNOWN || m_yChannelSelector == CHANNEL_UNKNOWN) return; - if (!effectContext()) + if (!effectContext(filter)) return; - IntRect effectADrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArrayA(in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); - IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->repaintRectInLocalCoordinates()); + IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArrayB(in2->resultImage()->getUnmultipliedImageData(effectBDrawingRect)->data()); IntRect imageRect(IntPoint(), resultImage()->size()); @@ -102,10 +103,10 @@ void FEDisplacementMap::apply(Filter* filter) ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); - float scaleX = m_scale / 255.f * filter->filterResolution().width(); - float scaleY = m_scale / 255.f * filter->filterResolution().height(); - float scaleAdjustmentX = (0.5f - 0.5f * m_scale) * filter->filterResolution().width(); - float scaleAdjustmentY = (0.5f - 0.5f * m_scale) * filter->filterResolution().height(); + float scaleX = filter->applyHorizontalScale(m_scale / 255); + float scaleY = filter->applyVerticalScale(m_scale / 255); + float scaleAdjustmentX = filter->applyHorizontalScale(0.5f - 0.5f * m_scale); + float scaleAdjustmentY = filter->applyVerticalScale(0.5f - 0.5f * m_scale); int stride = imageRect.width() * 4; for (int y = 0; y < imageRect.height(); ++y) { int line = y * stride; diff --git a/WebCore/platform/graphics/filters/FEDisplacementMap.h b/WebCore/platform/graphics/filters/FEDisplacementMap.h index dc87b90..c5b97a7 100644 --- a/WebCore/platform/graphics/filters/FEDisplacementMap.h +++ b/WebCore/platform/graphics/filters/FEDisplacementMap.h @@ -53,6 +53,8 @@ public: virtual void apply(Filter*); virtual void dump(); + virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); } + virtual TextStream& externalRepresentation(TextStream&, int indention) const; private: diff --git a/WebCore/platform/graphics/filters/FEFlood.cpp b/WebCore/platform/graphics/filters/FEFlood.cpp index 7804d89..b51a422 100644 --- a/WebCore/platform/graphics/filters/FEFlood.cpp +++ b/WebCore/platform/graphics/filters/FEFlood.cpp @@ -62,14 +62,14 @@ void FEFlood::setFloodOpacity(float floodOpacity) m_floodOpacity = floodOpacity; } -void FEFlood::apply(Filter*) +void FEFlood::apply(Filter* filter) { - GraphicsContext* filterContext = effectContext(); + GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; Color color = colorWithOverrideAlpha(floodColor().rgb(), floodOpacity()); - filterContext->fillRect(FloatRect(FloatPoint(), repaintRectInLocalCoordinates().size()), color, DeviceColorSpace); + filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size()), color, ColorSpaceDeviceRGB); } void FEFlood::dump() diff --git a/WebCore/platform/graphics/filters/FEFlood.h b/WebCore/platform/graphics/filters/FEFlood.h index b615531..e6a9574 100644 --- a/WebCore/platform/graphics/filters/FEFlood.h +++ b/WebCore/platform/graphics/filters/FEFlood.h @@ -42,6 +42,8 @@ public: virtual void apply(Filter*); virtual void dump(); + virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); } + virtual TextStream& externalRepresentation(TextStream&, int indention) const; private: diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp index fd9a3d8..1f36ba7 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp @@ -4,6 +4,7 @@ * Copyright (C) 2005 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> * Copyright (C) 2010 Igalia, S.L. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -34,7 +35,8 @@ using std::max; -static const float gGaussianKernelFactor = (3 * sqrtf(2 * piFloat) / 4.f); +static const float gGaussianKernelFactor = 3 / 4.f * sqrtf(2 * piFloat); +static const unsigned gMaxKernelSize = 1000; namespace WebCore { @@ -97,7 +99,7 @@ static void boxBlur(CanvasPixelArray*& srcPixelArray, CanvasPixelArray*& dstPixe } } -void FEGaussianBlur::kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight) +inline void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight) { // check http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement for details switch (boxBlur) { @@ -125,6 +127,41 @@ void FEGaussianBlur::kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& } } +inline void calculateKernelSize(Filter* filter, unsigned& kernelSizeX, unsigned& kernelSizeY, float stdX, float stdY) +{ + stdX = filter->applyHorizontalScale(stdX); + stdY = filter->applyVerticalScale(stdY); + + kernelSizeX = 0; + if (stdX) + kernelSizeX = max<unsigned>(2, static_cast<unsigned>(floorf(stdX * gGaussianKernelFactor + 0.5f))); + kernelSizeY = 0; + if (stdY) + kernelSizeY = max<unsigned>(2, static_cast<unsigned>(floorf(stdY * gGaussianKernelFactor + 0.5f))); + + // Limit the kernel size to 1000. A bigger radius won't make a big difference for the result image but + // inflates the absolute paint rect to much. This is compatible with Firefox' behavior. + if (kernelSizeX > gMaxKernelSize) + kernelSizeX = gMaxKernelSize; + if (kernelSizeY > gMaxKernelSize) + kernelSizeY = gMaxKernelSize; +} + +void FEGaussianBlur::determineAbsolutePaintRect(Filter* filter) +{ + FloatRect absolutePaintRect = inputEffect(0)->absolutePaintRect(); + absolutePaintRect.intersect(maxEffectRect()); + + unsigned kernelSizeX = 0; + unsigned kernelSizeY = 0; + calculateKernelSize(filter, kernelSizeX, kernelSizeY, m_stdX, m_stdY); + + // We take the half kernel size and multiply it with three, because we run box blur three times. + absolutePaintRect.inflateX(3 * kernelSizeX * 0.5f); + absolutePaintRect.inflateY(3 * kernelSizeY * 0.5f); + setAbsolutePaintRect(enclosingIntRect(absolutePaintRect)); +} + void FEGaussianBlur::apply(Filter* filter) { FilterEffect* in = inputEffect(0); @@ -132,12 +169,12 @@ void FEGaussianBlur::apply(Filter* filter) if (!in->resultImage()) return; - if (!effectContext()) + if (!effectContext(filter)) return; setIsAlphaImage(in->isAlphaImage()); - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ImageData> srcImageData(in->resultImage()->getPremultipliedImageData(effectDrawingRect)); IntRect imageRect(IntPoint(), resultImage()->size()); @@ -147,12 +184,8 @@ void FEGaussianBlur::apply(Filter* filter) } unsigned kernelSizeX = 0; - if (m_stdX) - kernelSizeX = max(2U, static_cast<unsigned>(floor(m_stdX * filter->filterResolution().width() * gGaussianKernelFactor + 0.5f))); - unsigned kernelSizeY = 0; - if (m_stdY) - kernelSizeY = max(2U, static_cast<unsigned>(floor(m_stdY * filter->filterResolution().height() * gGaussianKernelFactor + 0.5f))); + calculateKernelSize(filter, kernelSizeX, kernelSizeY, m_stdX, m_stdY); CanvasPixelArray* srcPixelArray(srcImageData->data()); RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height()); diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h index 745bcc8..50fc610 100644 --- a/WebCore/platform/graphics/filters/FEGaussianBlur.h +++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h @@ -42,12 +42,13 @@ public: virtual void apply(Filter*); virtual void dump(); + + virtual void determineAbsolutePaintRect(Filter*); virtual TextStream& externalRepresentation(TextStream&, int indention) const; private: FEGaussianBlur(float, float); - static void kernelPosition(int boxBlur, unsigned& std, int& dLeft, int& dRight); float m_stdX; float m_stdY; diff --git a/WebCore/platform/graphics/filters/FELighting.cpp b/WebCore/platform/graphics/filters/FELighting.cpp index f49b67d..e1df580 100644 --- a/WebCore/platform/graphics/filters/FELighting.cpp +++ b/WebCore/platform/graphics/filters/FELighting.cpp @@ -247,12 +247,12 @@ void FELighting::apply(Filter* filter) if (!in->resultImage()) return; - if (!effectContext()) + if (!effectContext(filter)) return; setIsAlphaImage(false); - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<ImageData> srcImageData(in->resultImage()->getUnmultipliedImageData(effectDrawingRect)); CanvasPixelArray* srcPixelArray(srcImageData->data()); @@ -261,8 +261,9 @@ void FELighting::apply(Filter* filter) // output for various kernelUnitLengths, and I am not sure they are reliable. // Anyway, feConvolveMatrix should also use the implementation - if (drawLighting(srcPixelArray, effectDrawingRect.width(), effectDrawingRect.height())) - resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); + IntSize absolutePaintSize = absolutePaintRect().size(); + if (drawLighting(srcPixelArray, absolutePaintSize.width(), absolutePaintSize.height())) + resultImage()->putUnmultipliedImageData(srcImageData.get(), IntRect(IntPoint(), absolutePaintSize), IntPoint()); } } // namespace WebCore diff --git a/WebCore/platform/graphics/filters/FELighting.h b/WebCore/platform/graphics/filters/FELighting.h index 28c00c4..bd56cee 100644 --- a/WebCore/platform/graphics/filters/FELighting.h +++ b/WebCore/platform/graphics/filters/FELighting.h @@ -44,6 +44,8 @@ class FELighting : public FilterEffect { public: virtual void apply(Filter*); + virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); } + protected: enum LightingType { DiffuseLighting, diff --git a/WebCore/platform/graphics/filters/FEMerge.cpp b/WebCore/platform/graphics/filters/FEMerge.cpp index 19c832a..b136af3 100644 --- a/WebCore/platform/graphics/filters/FEMerge.cpp +++ b/WebCore/platform/graphics/filters/FEMerge.cpp @@ -50,13 +50,13 @@ void FEMerge::apply(Filter* filter) return; } - GraphicsContext* filterContext = effectContext(); + GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; for (unsigned i = 0; i < size; ++i) { FilterEffect* in = inputEffect(i); - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, drawingRegionOfInputImage(in->repaintRectInLocalCoordinates())); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegionOfInputImage(in->absolutePaintRect())); } } diff --git a/WebCore/platform/graphics/filters/FEMorphology.cpp b/WebCore/platform/graphics/filters/FEMorphology.cpp index 7329e1e..ac26441 100644 --- a/WebCore/platform/graphics/filters/FEMorphology.cpp +++ b/WebCore/platform/graphics/filters/FEMorphology.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> * Copyright (C) 2005 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. 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 @@ -74,6 +75,15 @@ float FEMorphology::radiusY() const return m_radiusY; } +void FEMorphology::determineAbsolutePaintRect(Filter* filter) +{ + FloatRect paintRect = inputEffect(0)->absolutePaintRect(); + paintRect.inflateX(filter->applyHorizontalScale(m_radiusX)); + paintRect.inflateY(filter->applyVerticalScale(m_radiusY)); + paintRect.intersect(maxEffectRect()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); +} + void FEMorphology::setRadiusY(float radiusY) { m_radiusY = radiusY; @@ -86,18 +96,18 @@ void FEMorphology::apply(Filter* filter) if (!in->resultImage()) return; - if (!effectContext()) + if (!effectContext(filter)) return; setIsAlphaImage(in->isAlphaImage()); - - int radiusX = static_cast<int>(m_radiusX * filter->filterResolution().width()); - int radiusY = static_cast<int>(m_radiusY * filter->filterResolution().height()); - if (radiusX <= 0 || radiusY <= 0) + if (m_radiusX <= 0 || m_radiusY <= 0) return; + int radiusX = static_cast<int>(floorf(filter->applyHorizontalScale(m_radiusX))); + int radiusY = static_cast<int>(floorf(filter->applyVerticalScale(m_radiusY))); + IntRect imageRect(IntPoint(), resultImage()->size()); - IntRect effectDrawingRect = requestedRegionOfInputImageData(in->repaintRectInLocalCoordinates()); + IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<CanvasPixelArray> srcPixelArray(in->resultImage()->getPremultipliedImageData(effectDrawingRect)->data()); RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); diff --git a/WebCore/platform/graphics/filters/FEMorphology.h b/WebCore/platform/graphics/filters/FEMorphology.h index c8ce058..913671d 100644 --- a/WebCore/platform/graphics/filters/FEMorphology.h +++ b/WebCore/platform/graphics/filters/FEMorphology.h @@ -49,6 +49,8 @@ public: virtual void apply(Filter*); virtual void dump(); + virtual void determineAbsolutePaintRect(Filter*); + virtual TextStream& externalRepresentation(TextStream&, int indention) const; private: diff --git a/WebCore/platform/graphics/filters/FEOffset.cpp b/WebCore/platform/graphics/filters/FEOffset.cpp index ea84cf0..6ca56aa 100644 --- a/WebCore/platform/graphics/filters/FEOffset.cpp +++ b/WebCore/platform/graphics/filters/FEOffset.cpp @@ -3,6 +3,7 @@ * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> * Copyright (C) 2005 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Dirk Schulze <krit@webkit.org> + * Copyright (C) Research In Motion Limited 2010. 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 @@ -62,6 +63,14 @@ void FEOffset::setDy(float dy) m_dy = dy; } +void FEOffset::determineAbsolutePaintRect(Filter* filter) +{ + FloatRect paintRect = inputEffect(0)->absolutePaintRect(); + paintRect.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); + paintRect.intersect(maxEffectRect()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); +} + void FEOffset::apply(Filter* filter) { FilterEffect* in = inputEffect(0); @@ -69,28 +78,15 @@ void FEOffset::apply(Filter* filter) if (!in->resultImage()) return; - GraphicsContext* filterContext = effectContext(); + GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; setIsAlphaImage(in->isAlphaImage()); - FloatRect sourceImageRect = filter->sourceImageRect(); - sourceImageRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); - - if (filter->effectBoundingBoxMode()) { - m_dx *= sourceImageRect.width(); - m_dy *= sourceImageRect.height(); - } - m_dx *= filter->filterResolution().width(); - m_dy *= filter->filterResolution().height(); - - FloatRect dstRect = FloatRect(m_dx + in->repaintRectInLocalCoordinates().x() - repaintRectInLocalCoordinates().x(), - m_dy + in->repaintRectInLocalCoordinates().y() - repaintRectInLocalCoordinates().y(), - in->repaintRectInLocalCoordinates().width(), - in->repaintRectInLocalCoordinates().height()); - - filterContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, dstRect); + FloatRect drawingRegion = drawingRegionOfInputImage(in->absolutePaintRect()); + drawingRegion.move(filter->applyHorizontalScale(m_dx), filter->applyVerticalScale(m_dy)); + filterContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, drawingRegion); } void FEOffset::dump() diff --git a/WebCore/platform/graphics/filters/FEOffset.h b/WebCore/platform/graphics/filters/FEOffset.h index 052ba74..36575c5 100644 --- a/WebCore/platform/graphics/filters/FEOffset.h +++ b/WebCore/platform/graphics/filters/FEOffset.h @@ -40,6 +40,8 @@ public: virtual void apply(Filter*); virtual void dump(); + + virtual void determineAbsolutePaintRect(Filter*); virtual TextStream& externalRepresentation(TextStream&, int indention) const; diff --git a/WebCore/platform/graphics/filters/FETile.cpp b/WebCore/platform/graphics/filters/FETile.cpp index 41abd34..a695d3b 100644 --- a/WebCore/platform/graphics/filters/FETile.cpp +++ b/WebCore/platform/graphics/filters/FETile.cpp @@ -27,6 +27,7 @@ #include "Filter.h" #include "GraphicsContext.h" #include "Pattern.h" +#include "SVGImageBufferTools.h" namespace WebCore { @@ -44,45 +45,51 @@ FloatRect FETile::determineFilterPrimitiveSubregion(Filter* filter) { inputEffect(0)->determineFilterPrimitiveSubregion(filter); - filter->determineFilterPrimitiveSubregion(this, filter->filterRegion()); + filter->determineFilterPrimitiveSubregion(this, filter->filterRegionInUserSpace()); return filterPrimitiveSubregion(); } void FETile::apply(Filter* filter) { +// FIXME: See bug 47315. This is a hack to work around a compile failure, but is incorrect behavior otherwise. +#if ENABLE(SVG) FilterEffect* in = inputEffect(0); in->apply(filter); if (!in->resultImage()) return; - GraphicsContext* filterContext = effectContext(); + GraphicsContext* filterContext = effectContext(filter); if (!filterContext) return; setIsAlphaImage(in->isAlphaImage()); - IntRect tileRect = enclosingIntRect(in->repaintRectInLocalCoordinates()); - // Source input needs more attention. It has the size of the filterRegion but gives the // size of the cutted sourceImage back. This is part of the specification and optimization. - if (in->isSourceInput()) { - FloatRect filterRegion = filter->filterRegion(); - filterRegion.scale(filter->filterResolution().width(), filter->filterResolution().height()); - tileRect = enclosingIntRect(filterRegion); + FloatRect tileRect = in->maxEffectRect(); + FloatPoint inMaxEffectLocation = tileRect.location(); + FloatPoint maxEffectLocation = maxEffectRect().location(); + if (in->filterEffectType() == FilterEffectTypeSourceInput) { + tileRect = filter->filterRegion(); + tileRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); } - OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(tileRect.size()); + OwnPtr<ImageBuffer> tileImage; + if (!SVGImageBufferTools::createImageBuffer(tileRect, tileRect, tileImage, ColorSpaceDeviceRGB)) + return; + GraphicsContext* tileImageContext = tileImage->context(); - tileImageContext->drawImageBuffer(in->resultImage(), DeviceColorSpace, IntPoint()); - RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true); + tileImageContext->translate(-inMaxEffectLocation.x(), -inMaxEffectLocation.y()); + tileImageContext->drawImageBuffer(in->resultImage(), ColorSpaceDeviceRGB, in->absolutePaintRect().location()); - AffineTransform matrix; - matrix.translate(in->repaintRectInLocalCoordinates().x() - repaintRectInLocalCoordinates().x(), - in->repaintRectInLocalCoordinates().y() - repaintRectInLocalCoordinates().y()); - pattern.get()->setPatternSpaceTransform(matrix); + RefPtr<Pattern> pattern = Pattern::create(tileImage->copyImage(), true, true); + AffineTransform patternTransform; + patternTransform.translate(inMaxEffectLocation.x() - maxEffectLocation.x(), inMaxEffectLocation.y() - maxEffectLocation.y()); + pattern->setPatternSpaceTransform(patternTransform); filterContext->setFillPattern(pattern); - filterContext->fillRect(FloatRect(FloatPoint(), repaintRectInLocalCoordinates().size())); + filterContext->fillRect(FloatRect(FloatPoint(), absolutePaintRect().size())); +#endif } void FETile::dump() @@ -103,4 +110,3 @@ TextStream& FETile::externalRepresentation(TextStream& ts, int indent) const } // namespace WebCore #endif // ENABLE(FILTERS) - diff --git a/WebCore/platform/graphics/filters/FETile.h b/WebCore/platform/graphics/filters/FETile.h index 20efbcd..8562c90 100644 --- a/WebCore/platform/graphics/filters/FETile.h +++ b/WebCore/platform/graphics/filters/FETile.h @@ -35,6 +35,8 @@ public: virtual void apply(Filter*); virtual void dump(); + virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); } + virtual TextStream& externalRepresentation(TextStream&, int indention) const; virtual FloatRect determineFilterPrimitiveSubregion(Filter*); diff --git a/WebCore/platform/graphics/filters/FETurbulence.cpp b/WebCore/platform/graphics/filters/FETurbulence.cpp index bb24362..b1494a5 100644 --- a/WebCore/platform/graphics/filters/FETurbulence.cpp +++ b/WebCore/platform/graphics/filters/FETurbulence.cpp @@ -321,7 +321,7 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paint void FETurbulence::apply(Filter* filter) { - if (!effectContext()) + if (!effectContext(filter)) return; IntRect imageRect(IntPoint(), resultImage()->size()); @@ -329,10 +329,10 @@ void FETurbulence::apply(Filter* filter) return; RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); - PaintingData paintingData(m_seed, imageRect.size()); + PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size())); initPaint(paintingData); - FloatRect filterRegion = filter->filterRegion(); + FloatRect filterRegion = absolutePaintRect(); FloatPoint point; point.setY(filterRegion.y()); int indexOfPixelChannel = 0; @@ -342,7 +342,7 @@ void FETurbulence::apply(Filter* filter) for (int x = 0; x < imageRect.width(); ++x) { point.setX(point.x() + 1); for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel) - imageData->data()->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, point)); + imageData->data()->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, filter->mapAbsolutePointToLocalPoint(point))); } } resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); diff --git a/WebCore/platform/graphics/filters/FETurbulence.h b/WebCore/platform/graphics/filters/FETurbulence.h index 1a5a28a..c15d7d1 100644 --- a/WebCore/platform/graphics/filters/FETurbulence.h +++ b/WebCore/platform/graphics/filters/FETurbulence.h @@ -60,6 +60,8 @@ public: virtual void apply(Filter*); virtual void dump(); + + virtual void determineAbsolutePaintRect(Filter*) { setAbsolutePaintRect(maxEffectRect()); } virtual TextStream& externalRepresentation(TextStream&, int indention) const; diff --git a/WebCore/platform/graphics/filters/Filter.h b/WebCore/platform/graphics/filters/Filter.h index bce4be3..121e389 100644 --- a/WebCore/platform/graphics/filters/Filter.h +++ b/WebCore/platform/graphics/filters/Filter.h @@ -44,11 +44,18 @@ namespace WebCore { FloatSize filterResolution() const { return m_filterResolution; } void setFilterResolution(const FloatSize& filterResolution) { m_filterResolution = filterResolution; } + virtual float applyHorizontalScale(float value) const { return value * m_filterResolution.width(); } + virtual float applyVerticalScale(float value) const { return value * m_filterResolution.height(); } + virtual FloatRect sourceImageRect() const = 0; virtual FloatRect filterRegion() const = 0; + + virtual FloatPoint mapAbsolutePointToLocalPoint(const FloatPoint&) const { return FloatPoint(); } // SVG specific virtual void determineFilterPrimitiveSubregion(FilterEffect*, const FloatRect&) { } + + virtual FloatRect filterRegionInUserSpace() const { return FloatRect(); } virtual FloatSize maxImageSize() const = 0; virtual bool effectBoundingBoxMode() const = 0; diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 461b22a..121b921 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -46,7 +46,7 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(Filter* filter) // FETurbulence, FEImage and FEFlood don't have input effects, take the filter region as unite rect. if (!size) - uniteRect = filter->filterRegion(); + uniteRect = filter->filterRegionInUserSpace(); else { for (unsigned i = 0; i < size; ++i) uniteRect.unite(m_inputEffects.at(i)->determineFilterPrimitiveSubregion(filter)); @@ -56,18 +56,29 @@ FloatRect FilterEffect::determineFilterPrimitiveSubregion(Filter* filter) return m_filterPrimitiveSubregion; } -IntRect FilterEffect::requestedRegionOfInputImageData(const FloatRect& effectRect) const +void FilterEffect::determineAbsolutePaintRect(Filter*) +{ + m_absolutePaintRect = IntRect(); + unsigned size = m_inputEffects.size(); + for (unsigned i = 0; i < size; ++i) + m_absolutePaintRect.unite(m_inputEffects.at(i)->absolutePaintRect()); + + // SVG specification wants us to clip to primitive subregion. + m_absolutePaintRect.intersect(m_maxEffectRect); +} + +IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const { ASSERT(m_effectBuffer); - FloatPoint location = m_repaintRectInLocalCoordinates.location(); + IntPoint location = m_absolutePaintRect.location(); location.move(-effectRect.x(), -effectRect.y()); - return IntRect(roundedIntPoint(location), m_effectBuffer->size()); + return IntRect(location, m_effectBuffer->size()); } -FloatRect FilterEffect::drawingRegionOfInputImage(const FloatRect& srcRect) const +IntRect FilterEffect::drawingRegionOfInputImage(const IntRect& srcRect) const { - return FloatRect(FloatPoint(srcRect.x() - m_repaintRectInLocalCoordinates.x(), - srcRect.y() - m_repaintRectInLocalCoordinates.y()), srcRect.size()); + return IntRect(IntPoint(srcRect.x() - m_absolutePaintRect.x(), + srcRect.y() - m_absolutePaintRect.y()), srcRect.size()); } FilterEffect* FilterEffect::inputEffect(unsigned number) const @@ -76,10 +87,12 @@ FilterEffect* FilterEffect::inputEffect(unsigned number) const return m_inputEffects.at(number).get(); } -GraphicsContext* FilterEffect::effectContext() +GraphicsContext* FilterEffect::effectContext(Filter* filter) { - IntRect bufferRect = enclosingIntRect(m_repaintRectInLocalCoordinates); - m_effectBuffer = ImageBuffer::create(bufferRect.size(), LinearRGB); + determineAbsolutePaintRect(filter); + if (m_absolutePaintRect.isEmpty()) + return 0; + m_effectBuffer = ImageBuffer::create(m_absolutePaintRect.size(), ColorSpaceLinearRGB); if (!m_effectBuffer) return 0; return m_effectBuffer->context(); diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index ebe1880..a614b59 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -39,6 +39,13 @@ namespace WebCore { typedef Vector<RefPtr<FilterEffect> > FilterEffectVector; +enum FilterEffectType { + FilterEffectTypeUnknown, + FilterEffectTypeImage, + FilterEffectTypeTile, + FilterEffectTypeSourceInput +}; + class FilterEffect : public RefCounted<FilterEffect> { public: virtual ~FilterEffect(); @@ -49,26 +56,31 @@ public: // Creates the ImageBuffer for the current filter primitive result in the size of the // repaintRect. Gives back the GraphicsContext of the own ImageBuffer. - GraphicsContext* effectContext(); + GraphicsContext* effectContext(Filter*); FilterEffectVector& inputEffects() { return m_inputEffects; } FilterEffect* inputEffect(unsigned) const; unsigned numberOfEffectInputs() const { return m_inputEffects.size(); } - FloatRect drawingRegionOfInputImage(const FloatRect&) const; - IntRect requestedRegionOfInputImageData(const FloatRect&) const; + IntRect drawingRegionOfInputImage(const IntRect&) const; + IntRect requestedRegionOfInputImageData(const IntRect&) const; // Solid black image with different alpha values. bool isAlphaImage() const { return m_alphaImage; } void setIsAlphaImage(bool alphaImage) { m_alphaImage = alphaImage; } - FloatRect repaintRectInLocalCoordinates() const { return m_repaintRectInLocalCoordinates; } - void setRepaintRectInLocalCoordinates(const FloatRect& repaintRectInLocalCoordinates) { m_repaintRectInLocalCoordinates = repaintRectInLocalCoordinates; } + IntRect absolutePaintRect() const { return m_absolutePaintRect; } + void setAbsolutePaintRect(const IntRect& absolutePaintRect) { m_absolutePaintRect = absolutePaintRect; } + + IntRect maxEffectRect() const { return m_maxEffectRect; } + void setMaxEffectRect(const IntRect& maxEffectRect) { m_maxEffectRect = maxEffectRect; } virtual void apply(Filter*) = 0; virtual void dump() = 0; - virtual bool isSourceInput() const { return false; } + virtual void determineAbsolutePaintRect(Filter*); + + virtual FilterEffectType filterEffectType() const { return FilterEffectTypeUnknown; } virtual TextStream& externalRepresentation(TextStream&, int indention = 0) const; @@ -87,7 +99,7 @@ public: bool hasHeight() const { return m_hasHeight; } void setHasHeight(bool value) { m_hasHeight = value; } - // FIXME: Pseudo primitives like SourceGraphic and SourceAlpha as well as FETile still need special handling. + // FIXME: FETile still needs special handling. virtual FloatRect determineFilterPrimitiveSubregion(Filter*); FloatRect filterPrimitiveSubregion() const { return m_filterPrimitiveSubregion; } @@ -105,8 +117,11 @@ private: bool m_alphaImage; - // FIXME: Should be the paint region of the filter primitive, instead of the scaled subregion on use of filterRes. - FloatRect m_repaintRectInLocalCoordinates; + IntRect m_absolutePaintRect; + + // The maximum size of a filter primitive. In SVG this is the primitive subregion in absolute coordinate space. + // The absolute paint rect should never be bigger than m_maxEffectRect. + IntRect m_maxEffectRect; private: // The following member variables are SVG specific and will move to RenderSVGResourceFilterPrimitive. diff --git a/WebCore/platform/graphics/filters/ImageBufferFilter.h b/WebCore/platform/graphics/filters/ImageBufferFilter.h deleted file mode 100644 index cd4bc2f..0000000 --- a/WebCore/platform/graphics/filters/ImageBufferFilter.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef 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 beaf2e7..7dc56d9 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -42,31 +42,25 @@ const AtomicString& SourceAlpha::effectName() return s_effectName; } -FloatRect SourceAlpha::determineFilterPrimitiveSubregion(Filter* filter) +void SourceAlpha::determineAbsolutePaintRect(Filter* filter) { - FloatRect clippedSourceRect = filter->sourceImageRect(); - if (filter->sourceImageRect().x() < filter->filterRegion().x()) - clippedSourceRect.setX(filter->filterRegion().x()); - if (filter->sourceImageRect().y() < filter->filterRegion().y()) - clippedSourceRect.setY(filter->filterRegion().y()); - setFilterPrimitiveSubregion(clippedSourceRect); - clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); - setRepaintRectInLocalCoordinates(clippedSourceRect); - return filter->filterRegion(); + FloatRect paintRect = filter->sourceImageRect(); + paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); } void SourceAlpha::apply(Filter* filter) { - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + GraphicsContext* filterContext = effectContext(filter); + if (!filterContext || !filter->sourceImage()) return; setIsAlphaImage(true); - FloatRect imageRect(FloatPoint(), filter->sourceImage()->size()); + FloatRect imageRect(FloatPoint(), absolutePaintRect().size()); filterContext->save(); filterContext->clipToImageBuffer(filter->sourceImage(), imageRect); - filterContext->fillRect(imageRect, Color::black, DeviceColorSpace); + filterContext->fillRect(imageRect, Color::black, ColorSpaceDeviceRGB); filterContext->restore(); } diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h index f0fa319..83704e5 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.h +++ b/WebCore/platform/graphics/filters/SourceAlpha.h @@ -34,12 +34,12 @@ public: static const AtomicString& effectName(); - virtual FloatRect determineFilterPrimitiveSubregion(Filter*); - virtual void apply(Filter*); virtual void dump(); - virtual bool isSourceInput() const { return true; } + virtual void determineAbsolutePaintRect(Filter*); + + virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; } virtual TextStream& externalRepresentation(TextStream&, int indention) const; diff --git a/WebCore/platform/graphics/filters/SourceGraphic.cpp b/WebCore/platform/graphics/filters/SourceGraphic.cpp index c014e68..fbb711a 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.cpp +++ b/WebCore/platform/graphics/filters/SourceGraphic.cpp @@ -41,26 +41,20 @@ const AtomicString& SourceGraphic::effectName() return s_effectName; } -FloatRect SourceGraphic::determineFilterPrimitiveSubregion(Filter* filter) +void SourceGraphic::determineAbsolutePaintRect(Filter* filter) { - FloatRect clippedSourceRect = filter->sourceImageRect(); - if (filter->sourceImageRect().x() < filter->filterRegion().x()) - clippedSourceRect.setX(filter->filterRegion().x()); - if (filter->sourceImageRect().y() < filter->filterRegion().y()) - clippedSourceRect.setY(filter->filterRegion().y()); - setFilterPrimitiveSubregion(clippedSourceRect); - clippedSourceRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); - setRepaintRectInLocalCoordinates(clippedSourceRect); - return filter->filterRegion(); + FloatRect paintRect = filter->sourceImageRect(); + paintRect.scale(filter->filterResolution().width(), filter->filterResolution().height()); + setAbsolutePaintRect(enclosingIntRect(paintRect)); } void SourceGraphic::apply(Filter* filter) { - GraphicsContext* filterContext = effectContext(); - if (!filterContext) + GraphicsContext* filterContext = effectContext(filter); + if (!filterContext || !filter->sourceImage()) return; - filterContext->drawImageBuffer(filter->sourceImage(), DeviceColorSpace, IntPoint()); + filterContext->drawImageBuffer(filter->sourceImage(), ColorSpaceDeviceRGB, IntPoint()); } void SourceGraphic::dump() diff --git a/WebCore/platform/graphics/filters/SourceGraphic.h b/WebCore/platform/graphics/filters/SourceGraphic.h index 2378798..a13337d 100644 --- a/WebCore/platform/graphics/filters/SourceGraphic.h +++ b/WebCore/platform/graphics/filters/SourceGraphic.h @@ -35,12 +35,12 @@ public: static const AtomicString& effectName(); - virtual FloatRect determineFilterPrimitiveSubregion(Filter*); - virtual void apply(Filter*); virtual void dump(); - virtual bool isSourceInput() const { return true; } + virtual void determineAbsolutePaintRect(Filter*); + + virtual FilterEffectType filterEffectType() const { return FilterEffectTypeSourceInput; } virtual TextStream& externalRepresentation(TextStream&, int indention) const; diff --git a/WebCore/platform/graphics/gpu/DrawingBuffer.cpp b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp index dc80954..2dc0517 100644 --- a/WebCore/platform/graphics/gpu/DrawingBuffer.cpp +++ b/WebCore/platform/graphics/gpu/DrawingBuffer.cpp @@ -30,31 +30,40 @@ #include "config.h" -#include "DrawingBuffer.h" +#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS) -#include "GraphicsContext3D.h" -#include "SharedGraphicsContext3D.h" +#include "DrawingBuffer.h" namespace WebCore { -PassOwnPtr<DrawingBuffer> DrawingBuffer::create(SharedGraphicsContext3D* context, const IntSize& size) +PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size) { - unsigned framebuffer = context->createFramebuffer(); - ASSERT(framebuffer); - if (!framebuffer) - return 0; - return adoptPtr(new DrawingBuffer(context, size, framebuffer)); + RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size)); + return (drawingBuffer->m_context) ? drawingBuffer.release() : 0; } -void DrawingBuffer::bind() +void DrawingBuffer::clear() { - m_context->bindFramebuffer(m_framebuffer); - m_context->setViewport(m_size); + if (!m_context) + return; + + m_context->makeContextCurrent(); + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); + m_context->deleteFramebuffer(m_fbo); + m_fbo = 0; + + m_context.clear(); } -void DrawingBuffer::setWillPublishCallback(PassOwnPtr<WillPublishCallback> callback) +void DrawingBuffer::bind() { - m_callback = callback; + if (!m_context) + return; + + m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); + m_context->viewport(0, 0, m_size.width(), m_size.height()); } } // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/gpu/DrawingBuffer.h b/WebCore/platform/graphics/gpu/DrawingBuffer.h index 23e6f4a..75c7f99 100644 --- a/WebCore/platform/graphics/gpu/DrawingBuffer.h +++ b/WebCore/platform/graphics/gpu/DrawingBuffer.h @@ -31,30 +31,39 @@ #ifndef DrawingBuffer_h #define DrawingBuffer_h +#include "GraphicsContext3D.h" #include "GraphicsLayer.h" #include "IntSize.h" #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> +#if PLATFORM(MAC) +#include <wtf/RetainPtr.h> +#endif namespace WebCore { -class SharedGraphicsContext3D; - +#if PLATFORM(CHROMIUM) struct DrawingBufferInternal; +#endif // Manages a rendering target (framebuffer + attachment) for a canvas. Can publish its rendering // results to a PlatformLayer for compositing. -class DrawingBuffer : public Noncopyable { +class DrawingBuffer : public RefCounted<DrawingBuffer> { public: - static PassOwnPtr<DrawingBuffer> create(SharedGraphicsContext3D*, const IntSize&); + friend class GraphicsContext3D; + ~DrawingBuffer(); void reset(const IntSize&); void bind(); IntSize size() const { return m_size; } + // Clear all resources from this object, as well as context. Called when context is destroyed + // to prevent invalid accesses to the resources. + void clear(); + #if USE(ACCELERATED_COMPOSITING) PlatformLayer* platformLayer(); void publishToPlatformLayer(); @@ -62,21 +71,36 @@ public: unsigned getRenderingResultsAsTexture(); +#if PLATFORM(CHROMIUM) class WillPublishCallback : public Noncopyable { public: + virtual ~WillPublishCallback() { } + virtual void willPublish() = 0; }; - void setWillPublishCallback(PassOwnPtr<WillPublishCallback>); + void setWillPublishCallback(PassOwnPtr<WillPublishCallback> callback) { m_callback = callback; } +#endif + + PassRefPtr<GraphicsContext3D> graphicsContext3D() const { return m_context; } + private: - DrawingBuffer(SharedGraphicsContext3D*, const IntSize&, unsigned framebuffer); + static PassRefPtr<DrawingBuffer> create(GraphicsContext3D*, const IntSize&); + + DrawingBuffer(GraphicsContext3D*, const IntSize&); - SharedGraphicsContext3D* m_context; + RefPtr<GraphicsContext3D> m_context; IntSize m_size; - unsigned m_framebuffer; + Platform3DObject m_fbo; +#if PLATFORM(CHROMIUM) OwnPtr<WillPublishCallback> m_callback; OwnPtr<DrawingBufferInternal> m_internal; +#endif + +#if PLATFORM(MAC) + RetainPtr<WebGLLayer> m_platformLayer; +#endif }; } // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp index e43dc37..672b4d7 100644 --- a/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp +++ b/WebCore/platform/graphics/gpu/LoopBlinnClassifier.cpp @@ -25,6 +25,8 @@ #include "config.h" +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "LoopBlinnClassifier.h" #include "LoopBlinnMathUtils.h" @@ -120,3 +122,5 @@ LoopBlinnClassifier::Result LoopBlinnClassifier::classify(const FloatPoint& c0, } } // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp index 3b73ff6..1517a67 100644 --- a/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp +++ b/WebCore/platform/graphics/gpu/LoopBlinnLocalTriangulator.cpp @@ -25,6 +25,8 @@ #include "config.h" +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "LoopBlinnLocalTriangulator.h" #include "LoopBlinnMathUtils.h" @@ -273,3 +275,5 @@ bool LoopBlinnLocalTriangulator::isSharedEdge(Vertex* v0, Vertex* v1) } } // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp index 61ebc9b..5b155a5 100644 --- a/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp +++ b/WebCore/platform/graphics/gpu/LoopBlinnMathUtils.cpp @@ -25,12 +25,13 @@ #include "config.h" +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "LoopBlinnMathUtils.h" #include "FloatPoint.h" -#include "MathExtras.h" #include <algorithm> -#include <string.h> // for memcpy +#include <wtf/MathExtras.h> namespace WebCore { namespace LoopBlinnMathUtils { @@ -563,3 +564,5 @@ int numXRayCrossingsForCubic(const XRay& xRay, const FloatPoint cubic[4], bool& } // namespace LoopBlinnMathUtils } // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp index ac82637..d272fe1 100644 --- a/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp +++ b/WebCore/platform/graphics/gpu/LoopBlinnTextureCoords.cpp @@ -25,6 +25,8 @@ #include "config.h" +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "LoopBlinnTextureCoords.h" #include <math.h> @@ -169,3 +171,5 @@ LoopBlinnTextureCoords::Result LoopBlinnTextureCoords::compute(const LoopBlinnCl } } // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/gpu/PODInterval.h b/WebCore/platform/graphics/gpu/PODInterval.h index 9df69ba..5c1dcc2 100644 --- a/WebCore/platform/graphics/gpu/PODInterval.h +++ b/WebCore/platform/graphics/gpu/PODInterval.h @@ -27,7 +27,7 @@ #define PODInterval_h #ifndef NDEBUG -#include "StringBuilder.h" +#include <wtf/text/StringBuilder.h> #endif namespace WebCore { @@ -57,14 +57,24 @@ namespace WebCore { // constructor and assignment operator. // // In debug mode, printing of intervals and the data they contain is -// enabled. This requires the following functions to be available: +// enabled. This requires the following template specializations to be +// available: // -// String valueToString(const T&); -// String valueToString(const UserData&); +// template<> struct WebCore::ValueToString<T> { +// static String string(const T& t); +// }; +// template<> struct WebCore::ValueToString<UserData> { +// static String string(const UserData& t); +// }; // // Note that this class requires a copy constructor and assignment // operator in order to be stored in the red-black tree. +#ifndef NDEBUG +template<class T> +struct ValueToString; +#endif + template<class T, class UserData = void*> class PODInterval { public: @@ -131,13 +141,13 @@ public: { StringBuilder builder; builder.append("[PODInterval ("); - builder.append(valueToString(low())); + builder.append(ValueToString<T>::string(low())); builder.append(", "); - builder.append(valueToString(high())); + builder.append(ValueToString<T>::string(high())); builder.append("), data="); - builder.append(valueToString(data())); + builder.append(ValueToString<UserData>::string(data())); builder.append(", maxHigh="); - builder.append(valueToString(maxHigh())); + builder.append(ValueToString<T>::string(maxHigh())); builder.append("]"); return builder.toString(); } diff --git a/WebCore/platform/graphics/gpu/PODIntervalTree.h b/WebCore/platform/graphics/gpu/PODIntervalTree.h index c0a86aa..320ce60 100644 --- a/WebCore/platform/graphics/gpu/PODIntervalTree.h +++ b/WebCore/platform/graphics/gpu/PODIntervalTree.h @@ -35,6 +35,11 @@ namespace WebCore { +#ifndef NDEBUG +template<class T> +struct ValueToString; +#endif + // An interval tree, which is a form of augmented red-black tree. It // supports efficient (O(lg n)) insertion, removal and querying of // intervals in the tree. @@ -191,7 +196,7 @@ private: localMaxValue = node->data().high(); if (!(localMaxValue == node->data().maxHigh())) { #ifndef NDEBUG - String localMaxValueString = valueToString(localMaxValue); + String localMaxValueString = ValueToString<T>::string(localMaxValue); LOG_ERROR("PODIntervalTree verification failed at node 0x%p: localMaxValue=%s and data=%s", node, localMaxValueString.utf8().data(), node->data().toString().utf8().data()); #endif @@ -206,10 +211,12 @@ private: #ifndef NDEBUG // Support for printing PODIntervals at the PODRedBlackTree level. template<class T, class UserData> -String valueToString(const PODInterval<T, UserData>& interval) -{ - return interval.toString(); -} +struct ValueToString<PODInterval<T, UserData> > { + static String string(const PODInterval<T, UserData>& interval) + { + return interval.toString(); + } +}; #endif } // namespace WebCore diff --git a/WebCore/platform/graphics/gpu/PODRedBlackTree.h b/WebCore/platform/graphics/gpu/PODRedBlackTree.h index 9b02037..6d5954c 100644 --- a/WebCore/platform/graphics/gpu/PODRedBlackTree.h +++ b/WebCore/platform/graphics/gpu/PODRedBlackTree.h @@ -42,9 +42,11 @@ // the "<" and "==" operators. // // In debug mode, printing of the data contained in the tree is -// enabled. This requires the following function to be available: +// enabled. This requires the template specialization to be available: // -// String valueToString(const T&); +// template<> struct WebCore::ValueToString<T> { +// static String string(const T& t); +// }; // // Note that when complex types are stored in this red/black tree, it // is possible that single invocations of the "<" and "==" operators @@ -76,13 +78,18 @@ #include <wtf/RefPtr.h> #ifndef NDEBUG #include "Logging.h" -#include "PlatformString.h" -#include "StringBuilder.h" #include <wtf/text/CString.h> +#include <wtf/text/StringBuilder.h> +#include <wtf/text/WTFString.h> #endif namespace WebCore { +#ifndef NDEBUG +template<class T> +struct ValueToString; +#endif + template<class T> class PODRedBlackTree { public: @@ -723,7 +730,7 @@ private: builder.append("-"); if (node) { builder.append(" "); - builder.append(valueToString(node->data())); + builder.append(ValueToString<T>::string(node->data())); builder.append((node->color() == Black) ? " (black)" : " (red)"); } LOG_ERROR("%s", builder.toString().ascii().data()); diff --git a/WebCore/platform/graphics/gpu/Shader.cpp b/WebCore/platform/graphics/gpu/Shader.cpp index 59c50a7..8983adc 100644 --- a/WebCore/platform/graphics/gpu/Shader.cpp +++ b/WebCore/platform/graphics/gpu/Shader.cpp @@ -29,6 +29,9 @@ */ #include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "Shader.h" #include "AffineTransform.h" @@ -109,3 +112,5 @@ Shader::~Shader() } } + +#endif diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp index 7629735..87a0b69 100644 --- a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp +++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.cpp @@ -30,6 +30,8 @@ #include "config.h" +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "SharedGraphicsContext3D.h" #include "AffineTransform.h" @@ -47,16 +49,26 @@ namespace WebCore { // static -PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(PassOwnPtr<GraphicsContext3D> context) -{ - return adoptRef(new SharedGraphicsContext3D(context)); -} - -SharedGraphicsContext3D::SharedGraphicsContext3D(PassOwnPtr<GraphicsContext3D> context) +PassRefPtr<SharedGraphicsContext3D> SharedGraphicsContext3D::create(HostWindow* hostWindow) +{ + GraphicsContext3D::Attributes attr; + RefPtr<GraphicsContext3D> context = GraphicsContext3D::create(attr, hostWindow); + if (!context) + return 0; + OwnPtr<SolidFillShader> solidFillShader = SolidFillShader::create(context.get()); + if (!solidFillShader) + return 0; + OwnPtr<TexShader> texShader = TexShader::create(context.get()); + if (!texShader) + return 0; + return adoptRef(new SharedGraphicsContext3D(context.release(), solidFillShader.release(), texShader.release())); +} + +SharedGraphicsContext3D::SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D> context, PassOwnPtr<SolidFillShader> solidFillShader, PassOwnPtr<TexShader> texShader) : m_context(context) , m_quadVertices(0) - , m_solidFillShader(SolidFillShader::create(m_context.get())) - , m_texShader(TexShader::create(m_context.get())) + , m_solidFillShader(solidFillShader) + , m_texShader(texShader) { allContexts()->add(this); } @@ -215,8 +227,8 @@ void SharedGraphicsContext3D::removeTexturesFor(NativeImagePtr ptr) // static HashSet<SharedGraphicsContext3D*>* SharedGraphicsContext3D::allContexts() { - static OwnPtr<HashSet<SharedGraphicsContext3D*> > set(new HashSet<SharedGraphicsContext3D*>); - return set.get(); + DEFINE_STATIC_LOCAL(HashSet<SharedGraphicsContext3D*>, allContextsSet, ()); + return &allContextsSet; } @@ -334,3 +346,5 @@ bool SharedGraphicsContext3D::paintsIntoCanvasBuffer() const } } // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h index 3ba3c52..05008c2 100644 --- a/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h +++ b/WebCore/platform/graphics/gpu/SharedGraphicsContext3D.h @@ -47,6 +47,7 @@ class AffineTransform; class Color; class GraphicsContext3D; class FloatRect; +class HostWindow; class IntSize; class SolidFillShader; class TexShader; @@ -55,7 +56,7 @@ typedef HashMap<NativeImagePtr, RefPtr<Texture> > TextureHashMap; class SharedGraphicsContext3D : public RefCounted<SharedGraphicsContext3D> { public: - static PassRefPtr<SharedGraphicsContext3D> create(PassOwnPtr<GraphicsContext3D>); + static PassRefPtr<SharedGraphicsContext3D> create(HostWindow*); ~SharedGraphicsContext3D(); // Functions that delegate directly to GraphicsContext3D, with caching @@ -117,14 +118,16 @@ public: // the texture. PassRefPtr<Texture> createTexture(Texture::Format, int width, int height); + GraphicsContext3D* graphicsContext3D() const { return m_context.get(); } + private: - explicit SharedGraphicsContext3D(PassOwnPtr<GraphicsContext3D> context); + SharedGraphicsContext3D(PassRefPtr<GraphicsContext3D>, PassOwnPtr<SolidFillShader>, PassOwnPtr<TexShader>); // Used to implement removeTexturesFor(), see the comment above. static HashSet<SharedGraphicsContext3D*>* allContexts(); void removeTextureFor(NativeImagePtr); - OwnPtr<GraphicsContext3D> m_context; + RefPtr<GraphicsContext3D> m_context; unsigned m_quadVertices; diff --git a/WebCore/platform/graphics/gpu/SolidFillShader.cpp b/WebCore/platform/graphics/gpu/SolidFillShader.cpp index ff1b1fa..86079be 100644 --- a/WebCore/platform/graphics/gpu/SolidFillShader.cpp +++ b/WebCore/platform/graphics/gpu/SolidFillShader.cpp @@ -29,6 +29,9 @@ */ #include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "SolidFillShader.h" #include "Color.h" @@ -86,3 +89,5 @@ void SolidFillShader::use(const AffineTransform& transform, const Color& color) } } + +#endif diff --git a/WebCore/platform/graphics/gpu/TexShader.cpp b/WebCore/platform/graphics/gpu/TexShader.cpp index 01f4306..d7ffa17 100644 --- a/WebCore/platform/graphics/gpu/TexShader.cpp +++ b/WebCore/platform/graphics/gpu/TexShader.cpp @@ -29,6 +29,9 @@ */ #include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "TexShader.h" #include "GraphicsContext3D.h" @@ -93,3 +96,5 @@ void TexShader::use(const AffineTransform& transform, const AffineTransform& tex } } + +#endif diff --git a/WebCore/platform/graphics/gpu/Texture.cpp b/WebCore/platform/graphics/gpu/Texture.cpp index 6023fe9..74807dc 100644 --- a/WebCore/platform/graphics/gpu/Texture.cpp +++ b/WebCore/platform/graphics/gpu/Texture.cpp @@ -30,6 +30,8 @@ #include "config.h" +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "Texture.h" #include "FloatRect.h" @@ -206,3 +208,5 @@ void Texture::bindTile(int tile) } } + +#endif diff --git a/WebCore/platform/graphics/gpu/Texture.h b/WebCore/platform/graphics/gpu/Texture.h index eda475e..92b6d0a 100644 --- a/WebCore/platform/graphics/gpu/Texture.h +++ b/WebCore/platform/graphics/gpu/Texture.h @@ -31,11 +31,11 @@ #ifndef Texture_h #define Texture_h -#include "RefCounted.h" -#include "RefPtr.h" #include "TilingData.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> #include <wtf/Vector.h> namespace WebCore { diff --git a/WebCore/platform/graphics/gpu/TilingData.cpp b/WebCore/platform/graphics/gpu/TilingData.cpp index 4da242b..a98add7 100644 --- a/WebCore/platform/graphics/gpu/TilingData.cpp +++ b/WebCore/platform/graphics/gpu/TilingData.cpp @@ -29,6 +29,9 @@ */ #include "config.h" + +#if ENABLE(ACCELERATED_2D_CANVAS) + #include "TilingData.h" #include "FloatRect.h" @@ -220,3 +223,5 @@ void TilingData::intersectDrawQuad(const FloatRect& srcRect, const FloatRect& ds } } + +#endif diff --git a/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm b/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm new file mode 100644 index 0000000..7a8c501 --- /dev/null +++ b/WebCore/platform/graphics/gpu/mac/DrawingBufferMac.mm @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010 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 ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS) + +#include "DrawingBuffer.h" + +#include "WebGLLayer.h" + +#import "BlockExceptions.h" + +namespace WebCore { + +DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, const IntSize& size) + : m_context(context) + , m_size(size) + , m_fbo(context->createFramebuffer()) +{ + ASSERT(m_fbo); + if (!m_fbo) { + clear(); + return; + } + + // Create the WebGLLayer + BEGIN_BLOCK_OBJC_EXCEPTIONS + m_platformLayer.adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:m_context.get()]); +#ifndef NDEBUG + [m_platformLayer.get() setName:@"DrawingBuffer Layer"]; +#endif + END_BLOCK_OBJC_EXCEPTIONS +} + +DrawingBuffer::~DrawingBuffer() +{ + clear(); +} + +void DrawingBuffer::reset(const IntSize& newSize) +{ + if (!m_context) + return; + + if (m_size == newSize) + return; + m_size = newSize; + + m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_size.width(), m_size.height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0); +} + +#if USE(ACCELERATED_COMPOSITING) +PlatformLayer* DrawingBuffer::platformLayer() +{ + return m_platformLayer.get(); +} +#endif + +} + +#endif diff --git a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp index 539d92a..1cb561e 100644 --- a/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp +++ b/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp @@ -194,12 +194,14 @@ void GStreamerGWorld::setWindowOverlay(GstMessage* message) if (g_object_class_find_property(G_OBJECT_GET_CLASS(sink), "force-aspect-ratio")) g_object_set(sink, "force-aspect-ratio", TRUE, NULL); - if (m_videoWindow) + if (m_videoWindow) { + m_videoWindow->prepareForOverlay(message); #if GST_CHECK_VERSION(0, 10, 31) || GST_VERSION_NANO gst_x_overlay_set_window_handle(GST_X_OVERLAY(sink), m_videoWindow->videoWindowId()); #else gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sink), m_videoWindow->videoWindowId()); #endif + } } } diff --git a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp index da9255b..7012c9f 100644 --- a/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp @@ -1212,7 +1212,7 @@ void MediaPlayerPrivateGStreamer::paint(GraphicsContext* context, const IntRect& if (!gstImage) return; - context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), sRGBColorSpace, + context->drawImage(reinterpret_cast<Image*>(gstImage->image().get()), ColorSpaceSRGB, rect, CompositeCopy, false); } diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h index f3df207..f2a3ff2 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindow.h @@ -25,6 +25,8 @@ #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +typedef struct _GstMessage GstMessage; + namespace WebCore { class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> { @@ -34,6 +36,8 @@ class PlatformVideoWindow : public RefCounted<PlatformVideoWindow> { PlatformVideoWindow(); ~PlatformVideoWindow(); + + void prepareForOverlay(GstMessage*); PlatformWidget window() const { return m_window; } unsigned long videoWindowId() const { return m_videoWindowId; } diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp index c55b9cc..0097716 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowEfl.cpp @@ -35,4 +35,8 @@ PlatformVideoWindow::~PlatformVideoWindow() notImplemented(); } +void PlatformVideoWindow::prepareForOverlay(GstMessage*) +{ +} + #endif // USE(GSTREAMER) diff --git a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp index 77343ae..c2f76cd 100644 --- a/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp +++ b/WebCore/platform/graphics/gstreamer/PlatformVideoWindowGtk.cpp @@ -61,4 +61,9 @@ PlatformVideoWindow::~PlatformVideoWindow() m_videoWindowId = 0; } + +void PlatformVideoWindow::prepareForOverlay(GstMessage*) +{ +} #endif // USE(GSTREAMER) + diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp index 27f48fc..328ec4a 100644 --- a/WebCore/platform/graphics/gtk/FontGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -181,31 +181,15 @@ bool Font::canReturnFallbackFontsForComplexText() return false; } -#ifndef GTK_API_VERSION_2 -static void cairo_region_shrink(cairo_region_t* region, int dx, int dy) +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { - int nRects = cairo_region_num_rectangles(region); - // Clear region. - cairo_region_subtract(region, region); - - for (int i = 0; i < nRects; i++) { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle(region, i, &rect); - - if (rect.width <= 2 * dx || rect.height <= 2 * dy) - continue; - - rect.x += dx; - rect.y += dy; - rect.width -= 2 * dx; - rect.height -= 2 * dy; - cairo_region_union_rectangle(region, &rect); +#if defined(USE_FREETYPE) + if (!primaryFont()->platformData().m_pattern) { + drawSimpleText(context, run, point, from, to); + return; } -} #endif -void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const -{ cairo_t* cr = context->platformContext(); cairo_save(cr); cairo_translate(cr, point.x(), point.y()); @@ -224,17 +208,13 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F #else cairo_region_t* partialRegion = 0; #endif + if (to - from != run.length()) { // Clip the region of the run to be rendered char* start = g_utf8_offset_to_pointer(utf8, from); char* end = g_utf8_offset_to_pointer(start, to - from); int ranges[] = {start - utf8, end - utf8}; partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1); -#ifdef GTK_API_VERSION_2 - gdk_region_shrink(partialRegion, 0, -pixelSize()); -#else - cairo_region_shrink(partialRegion, 0, -pixelSize()); -#endif } Color fillColor = context->fillColor(); @@ -290,7 +270,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F // Re-enable the platform shadow we disabled earlier if (hasShadow) - context->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace); + context->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB); // Pango sometimes leaves behind paths we don't want cairo_new_path(cr); @@ -323,8 +303,13 @@ static PangoLayout* getDefaultPangoLayout(const TextRun& run) return layout; } -float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* /* fallbackFonts */, GlyphOverflow*) const +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* overflow) const { +#if defined(USE_FREETYPE) + if (!primaryFont()->platformData().m_pattern) + return floatWidthForSimpleText(run, 0, fallbackFonts, overflow); +#endif + if (run.length() == 0) return 0.0f; @@ -345,6 +330,10 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const { +#if defined(USE_FREETYPE) + if (!primaryFont()->platformData().m_pattern) + return offsetForPositionForSimpleText(run, xFloat, includePartialGlyphs); +#endif // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem. int x = static_cast<int>(xFloat); @@ -369,6 +358,11 @@ int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const { +#if defined(USE_FREETYPE) + if (!primaryFont()->platformData().m_pattern) + return selectionRectForSimpleText(run, point, h, from, to); +#endif + PangoLayout* layout = getDefaultPangoLayout(run); setPangoAttributes(this, run, layout); diff --git a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp index edb26f0..486a317 100644 --- a/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageBufferGtk.cpp @@ -28,6 +28,7 @@ #include <cairo.h> #include <gtk/gtk.h> #include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> namespace WebCore { @@ -67,7 +68,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con base64Encode(reinterpret_cast<const char*>(buffer.get()), bufferSize, out); out.append('\0'); - return String::format("data:%s;base64,%s", mimeType.utf8().data(), out.data()); + return makeString("data:", mimeType, ";base64,", out.data()); } } diff --git a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp index c5de485..d1b06f3 100644 --- a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp +++ b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp @@ -33,6 +33,7 @@ #include "MIMETypeRegistry.h" #include "StillImageHaiku.h" #include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> #include <BitmapStream.h> #include <String.h> #include <TranslatorRoster.h> @@ -367,8 +368,7 @@ String ImageBuffer::toDataURL(const String& mimeType, const double*) const base64Encode(reinterpret_cast<const char*>(translatedStream.Buffer()), translatedStream.BufferLength(), encodedBuffer); - return String::format("data:%s;base64,%s", mimeType.utf8().data(), - encodedBuffer.data()); + return makeString("data:", mimeType, ";base64,", encodedBuffer.data()); } } // namespace WebCore diff --git a/WebCore/platform/graphics/haiku/PathHaiku.cpp b/WebCore/platform/graphics/haiku/PathHaiku.cpp index c5b8c98..5377e10 100644 --- a/WebCore/platform/graphics/haiku/PathHaiku.cpp +++ b/WebCore/platform/graphics/haiku/PathHaiku.cpp @@ -144,12 +144,6 @@ bool Path::isEmpty() const return !m_path->Frame().IsValid(); } -String Path::debugString() const -{ - notImplemented(); - return String(); -} - void Path::apply(void* info, PathApplierFunction function) const { notImplemented(); diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm index c8ea9b1..07d6353 100644 --- a/WebCore/platform/graphics/mac/ColorMac.mm +++ b/WebCore/platform/graphics/mac/ColorMac.mm @@ -88,14 +88,15 @@ NSColor *nsColor(const Color& color) static unsigned cachedRGBAValues[cacheSize]; static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize]; - for (int i = 0; i != cacheSize; ++i) + for (int i = 0; i != cacheSize; ++i) { if (cachedRGBAValues[i] == c) return cachedColors[i].get(); + } NSColor *result = [NSColor colorWithDeviceRed:static_cast<CGFloat>(color.red()) / 255 green:static_cast<CGFloat>(color.green()) / 255 blue:static_cast<CGFloat>(color.blue()) / 255 - alpha:static_cast<CGFloat>(color.alpha()) /255]; + alpha:static_cast<CGFloat>(color.alpha()) / 255]; static int cursor; cachedRGBAValues[cursor] = c; @@ -107,24 +108,5 @@ NSColor *nsColor(const Color& color) } } -static CGColorRef CGColorFromNSColor(NSColor *color) -{ - // This needs to always use device colorspace so it can de-calibrate the color for - // CGColor to possibly recalibrate it. - CGFloat components[4]; - NSColor *deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - [deviceColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]]; - static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB(); - CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components); - return cgColor; -} - -CGColorRef createCGColor(const Color& c) -{ - // We could directly create a CGColor here, but that would - // skip any RGB caching the nsColor method does. A direct - // creation could be investigated for a possible performance win. - return CGColorFromNSColor(nsColor(c)); -} } // namespace WebCore diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm index a4919d8..e079b44 100644 --- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.mm @@ -77,12 +77,12 @@ static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBi attribs.append(static_cast<CGLPixelFormatAttribute>(0)); } -PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) +PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) { // This implementation doesn't currently support rendering directly to the HostWindow. if (renderStyle == RenderDirectlyToHostWindow) return 0; - OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs, hostWindow, false)); + RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, false)); return context->m_contextObj ? context.release() : 0; } diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index f3301d8..aa754f2 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,7 @@ #import <AppKit/AppKit.h> #import <wtf/StdLibExtras.h> +#import "LocalCurrentGraphicsContext.h" #import "WebCoreSystemInterface.h" @class NSColor; @@ -43,14 +44,14 @@ namespace WebCore { // calls in this file are all exception-safe, so we don't block // exceptions for those. -static void drawFocusRingToContext(CGContextRef context, RetainPtr<CGPathRef> focusRingPath, RetainPtr<CGColorRef> colorRef, int radius) +static void drawFocusRingToContext(CGContextRef context, CGPathRef focusRingPath, CGColorRef color, int radius) { #ifdef BUILDING_ON_TIGER CGContextBeginTransparencyLayer(context, 0); #endif CGContextBeginPath(context); - CGContextAddPath(context, focusRingPath.get()); - wkDrawFocusRing(context, colorRef.get(), radius); + CGContextAddPath(context, focusRingPath); + wkDrawFocusRing(context, color, radius); #ifdef BUILDING_ON_TIGER CGContextEndTransparencyLayer(context); #endif @@ -63,16 +64,14 @@ void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int of int radius = (width - 1) / 2; offset += radius; - RetainPtr<CGColorRef> colorRef; - if (color.isValid()) - colorRef.adoptCF(createCGColor(color)); - + CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0; + RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable()); unsigned pathCount = paths.size(); for (unsigned i = 0; i < pathCount; i++) CGPathAddPath(focusRingPath.get(), 0, paths[i].platformPath()); - drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius); + drawFocusRingToContext(platformContext(), focusRingPath.get(), colorRef, radius); } void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) @@ -82,16 +81,14 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int int radius = (width - 1) / 2; offset += radius; - RetainPtr<CGColorRef> colorRef; - if (color.isValid()) - colorRef.adoptCF(createCGColor(color)); + CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0; RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable()); unsigned rectCount = rects.size(); for (unsigned i = 0; i < rectCount; i++) CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset)); - drawFocusRingToContext(platformContext(), focusRingPath, colorRef, radius); + drawFocusRingToContext(platformContext(), focusRingPath.get(), colorRef, radius); } #ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp. @@ -182,6 +179,7 @@ void GraphicsContext::drawLineForTextChecking(const IntPoint& point, int width, // for transforms. // Draw underline. + LocalCurrentGraphicsContext localContext(this); NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; CGContextRef context = (CGContextRef)[currentContext graphicsPort]; CGContextSaveGState(context); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index d4cd851..c4128ef 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -38,7 +38,6 @@ #import <QuartzCore/QuartzCore.h> #import "RotateTransformOperation.h" #import "ScaleTransformOperation.h" -#import "StringBuilder.h" #import "SystemTime.h" #import "TranslateTransformOperation.h" #import "WebLayer.h" @@ -48,6 +47,7 @@ #import <wtf/CurrentTime.h> #import <wtf/UnusedParam.h> #import <wtf/RetainPtr.h> +#import <wtf/text/StringConcatenate.h> using namespace std; @@ -248,7 +248,7 @@ static String propertyIdToString(AnimatedPropertyID property) static String animationIdentifier(const String& animationName, AnimatedPropertyID property, int index) { - return animationName + String::format("_%d_%d", property, index); + return makeString(animationName, '_', String::number(property), '_', String::number(index)); } static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* timingFunction) @@ -265,9 +265,7 @@ static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction* tim static void setLayerBorderColor(PlatformLayer* layer, const Color& color) { - CGColorRef borderColor = createCGColor(color); - [layer setBorderColor:borderColor]; - CGColorRelease(borderColor); + [layer setBorderColor:cachedCGColor(color, ColorSpaceDeviceRGB)]; } static void clearBorderColor(PlatformLayer* layer) @@ -277,9 +275,7 @@ static void clearBorderColor(PlatformLayer* layer) static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color) { - CGColorRef bgColor = createCGColor(color); - [layer setBackgroundColor:bgColor]; - CGColorRelease(bgColor); + [layer setBackgroundColor:cachedCGColor(color, ColorSpaceDeviceRGB)]; } static void clearLayerBackgroundColor(PlatformLayer* layer) diff --git a/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp b/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp index 53d9b86..daf3b12 100644 --- a/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp +++ b/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGL.cpp @@ -1161,11 +1161,11 @@ String GraphicsContext3D::getProgramInfoLog(Platform3DObject program) makeContextCurrent(); GLint length; ::glGetProgramiv((GLuint) program, GL_INFO_LOG_LENGTH, &length); - + if (!length) + return ""; + GLsizei size; GLchar* info = (GLchar*) fastMalloc(length); - if (!info) - return ""; ::glGetProgramInfoLog((GLuint) program, length, &size, info); String s(info); @@ -1227,8 +1227,6 @@ String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader) ASSERT(shader); makeContextCurrent(); - GLint length; - ::glGetShaderiv((GLuint) shader, GL_INFO_LOG_LENGTH, &length); HashMap<Platform3DObject, ShaderSourceEntry>::iterator result = m_shaderSourceMap.find(shader); @@ -1240,21 +1238,19 @@ String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader) if (entry.isValid) { GLint length; ::glGetShaderiv((GLuint) shader, GL_INFO_LOG_LENGTH, &length); + if (!length) + return ""; GLsizei size; GLchar* info = (GLchar*) fastMalloc(length); - if (!info) - return ""; ::glGetShaderInfoLog((GLuint) shader, length, &size, info); String s(info); fastFree(info); return s; - } - else { + } else return entry.log; - } } String GraphicsContext3D::getShaderSource(Platform3DObject shader) @@ -1449,6 +1445,11 @@ void GraphicsContext3D::synthesizeGLError(unsigned long error) m_syntheticErrors.add(error); } +int GraphicsContext3D::getGraphicsResetStatusARB() +{ + return NO_ERROR; +} + } #endif // ENABLE(3D_CANVAS) diff --git a/WebCore/platform/graphics/openvg/PathOpenVG.cpp b/WebCore/platform/graphics/openvg/PathOpenVG.cpp index e74ea57..39a4b06 100644 --- a/WebCore/platform/graphics/openvg/PathOpenVG.cpp +++ b/WebCore/platform/graphics/openvg/PathOpenVG.cpp @@ -436,18 +436,6 @@ bool Path::hasCurrentPoint() const return vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS) > 0; } -String Path::debugString() const -{ - String debugString = ""; - - // OpenVG provides no means to retrieve path segment information. - // This is a bit unfortunate, we might need to store the segments in - // memory if we want to implement this function properly. - notImplemented(); - - return debugString; -} - void Path::apply(void* info, PathApplierFunction function) const { // OpenVG provides no means to retrieve path segment information. diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index e7566eb..b049181 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -137,7 +137,7 @@ static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const Float dy1 = -ctxShadow->offset().y(); // expand the clip rect to include the text shadow as well clip.adjust(dx1, dx2, dy1, dy2); - clip.adjust(-ctxShadow->m_blurRadius, -ctxShadow->m_blurRadius, ctxShadow->m_blurRadius, ctxShadow->m_blurRadius); + clip.adjust(-ctxShadow->m_blurDistance, -ctxShadow->m_blurDistance, ctxShadow->m_blurDistance, ctxShadow->m_blurDistance); } p->save(); p->setClipRect(clip.toRect(), Qt::IntersectClip); diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp index 0756aa7..cda8606 100644 --- a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp @@ -286,6 +286,11 @@ bool GraphicsContext3D::isErrorGeneratedOnOutOfBoundsAccesses() const return false; } +int GraphicsContext3D::getGraphicsResetStatusARB() +{ + return NO_ERROR; +} + GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow) : m_attrs(attrs) diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 7e4af40..8b34f51 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -204,6 +204,13 @@ public: return shadow.m_type != ContextShadow::NoShadow; } + inline void clearCurrentPath() + { + if (!currentPath.elementCount()) + return; + currentPath = QPainterPath(); + } + QRectF clipBoundingRect() const { #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0) @@ -248,8 +255,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor(), DeviceColorSpace); - setPlatformStrokeColor(strokeColor(), DeviceColorSpace); + setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB); + setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB); // Make sure we start with the correct join mode. setLineJoin(MiterJoin); @@ -533,7 +540,7 @@ void GraphicsContext::fillPath() } else p->fillPath(path, p->brush()); - m_data->currentPath = QPainterPath(); + m_data->clearCurrentPath(); } void GraphicsContext::strokePath() @@ -566,7 +573,7 @@ void GraphicsContext::strokePath() p->strokePath(path, pen); } else p->strokePath(path, pen); - m_data->currentPath = QPainterPath(); + m_data->clearCurrentPath(); } static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY) @@ -722,7 +729,8 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef if (paintingDisabled() || !color.isValid()) return; - Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight); + Path path; + path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight); QPainter* p = m_data->p(); if (m_data->hasShadow()) { p->translate(m_data->shadow.offset()); @@ -734,7 +742,7 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef void GraphicsContext::beginPath() { - m_data->currentPath = QPainterPath(); + m_data->clearCurrentPath(); } void GraphicsContext::addPath(const Path& path) @@ -777,7 +785,7 @@ void GraphicsContext::clipPath(WindRule clipRule) QPainter* p = m_data->p(); QPainterPath newPath = m_data->currentPath; newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); - p->setClipPath(newPath); + p->setClipPath(newPath, Qt::IntersectClip); } void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int offset, const Color& color) @@ -835,8 +843,28 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool) if (paintingDisabled()) return; + IntPoint startPoint = origin; IntPoint endPoint = origin + IntSize(width, 0); - drawLine(origin, endPoint); + + // If paintengine type is X11 to avoid artifacts + // like bug https://bugs.webkit.org/show_bug.cgi?id=42248 +#if defined(Q_WS_X11) + QPainter* p = m_data->p(); + if (p->paintEngine()->type() == QPaintEngine::X11) { + // If stroke thickness is odd we need decrease Y coordinate by 1 pixel, + // because inside method adjustLineToPixelBoundaries(...), which + // called from drawLine(...), Y coordinate will be increased by 0.5f + // and then inside Qt painting engine will be rounded to next greater + // integer value. + float strokeWidth = strokeThickness(); + if (static_cast<int>(strokeWidth) % 2) { + startPoint.setY(startPoint.y() - 1); + endPoint.setY(endPoint.y() - 1); + } + } +#endif // defined(Q_WS_X11) + + drawLine(startPoint, endPoint); } void GraphicsContext::drawLineForTextChecking(const IntPoint&, int, TextCheckingLineStyle) diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp index 079d8ba..e0941f5 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp @@ -37,6 +37,7 @@ #include <QtGui/qgraphicseffect.h> #include <QtGui/qgraphicsitem.h> #include <QtGui/qgraphicsscene.h> +#include <QtGui/qgraphicswidget.h> #include <QtGui/qpainter.h> #include <QtGui/qpixmap.h> #include <QtGui/qpixmapcache.h> @@ -320,7 +321,7 @@ GraphicsLayerQtImpl::~GraphicsLayerQtImpl() // our items automatically. const QList<QGraphicsItem*> children = childItems(); QList<QGraphicsItem*>::const_iterator cit; - for (cit = children.begin(); cit != children.end(); ++cit) { + for (cit = children.constBegin(); cit != children.constEnd(); ++cit) { if (QGraphicsItem* item = *cit) { if (scene()) scene()->removeItem(item); @@ -523,7 +524,7 @@ void GraphicsLayerQtImpl::updateTransform() const QList<QGraphicsItem*> children = childItems(); QList<QGraphicsItem*>::const_iterator it; - for (it = children.begin(); it != children.end(); ++it) + for (it = children.constBegin(); it != children.constEnd(); ++it) if (GraphicsLayerQtImpl* layer= toGraphicsLayerQtImpl(*it)) layer->updateTransform(); } @@ -610,13 +611,13 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform if (!m_layer || m_changeMask == NoChanges) goto afterLayerChanges; - if (m_currentContent.contentType == HTMLContentType && (m_changeMask & ParentChange)) { + if (m_changeMask & ParentChange) { // The WebCore compositor manages item ownership. We have to make sure graphicsview doesn't // try to snatch that ownership. if (!m_layer->parent() && !parentItem()) setParentItem(0); else if (m_layer && m_layer->parent() && m_layer->parent()->nativeLayer() != parentItem()) - setParentItem(m_layer->parent()->nativeLayer()); + setParentItem(m_layer->parent()->platformLayer()); } if (m_changeMask & ChildrenChange) { @@ -634,13 +635,13 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren; QSet<QGraphicsItem*>::const_iterator it; - for (it = childrenToAdd.begin(); it != childrenToAdd.end(); ++it) { + for (it = childrenToAdd.constBegin(); it != childrenToAdd.constEnd(); ++it) { if (QGraphicsItem* w = *it) w->setParentItem(this); } QSet<QGraphicsItem*>::const_iterator rit; - for (rit = childrenToRemove.begin(); rit != childrenToRemove.end(); ++rit) { + for (rit = childrenToRemove.constBegin(); rit != childrenToRemove.constEnd(); ++rit) { if (GraphicsLayerQtImpl* w = toGraphicsLayerQtImpl(*rit)) w->setParentItem(0); } @@ -680,7 +681,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform if (scene()) scene()->update(); - if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | BackfaceVisibilityChange | PositionChange)) { + if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | BackfaceVisibilityChange | PositionChange | ParentChange)) { // Due to the differences between the way WebCore handles transforms and the way Qt handles transforms, // all these elements affect the transforms of all the descendants. forceUpdateTransform = true; @@ -737,6 +738,11 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform const QRect rect(m_layer->contentsRect()); if (m_state.contentsRect != rect) { m_state.contentsRect = rect; + if (m_pendingContent.mediaLayer) { + QGraphicsWidget* widget = qobject_cast<QGraphicsWidget*>(m_pendingContent.mediaLayer.data()); + if (widget) + widget->setGeometry(rect); + } update(); } } @@ -804,7 +810,7 @@ afterLayerChanges: children.append(m_state.maskLayer->platformLayer()); QList<QGraphicsItem*>::const_iterator it; - for (it = children.begin(); it != children.end(); ++it) { + for (it = children.constBegin(); it != children.constEnd(); ++it) { if (QGraphicsItem* item = *it) { if (GraphicsLayerQtImpl* layer = toGraphicsLayerQtImpl(item)) layer->flushChanges(true, forceUpdateTransform); @@ -850,6 +856,20 @@ void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& rect) m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange); } +void GraphicsLayerQt::setContentsNeedsDisplay() +{ + switch (m_impl->m_pendingContent.contentType) { + case GraphicsLayerQtImpl::MediaContentType: + if (!m_impl->m_pendingContent.mediaLayer) + return; + m_impl->m_pendingContent.mediaLayer.data()->update(); + break; + default: + setNeedsDisplay(); + break; + } +} + /* \reimp (GraphicsLayer.h) */ void GraphicsLayerQt::setName(const String& name) diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h index 75ca498..ed535eb 100644 --- a/WebCore/platform/graphics/qt/GraphicsLayerQt.h +++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h @@ -75,6 +75,7 @@ public: virtual void resumeAnimations(); #endif // QT_NO_ANIMATION virtual void setContentsToImage(Image*); + virtual void setContentsNeedsDisplay(); virtual void setContentsToMedia(PlatformLayer*); virtual void setContentsBackgroundColor(const Color&); #if ENABLE(3D_CANVAS) diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index ee01222..0cdc894 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -35,6 +35,7 @@ #include "StillImageQt.h" #include "TransparencyLayer.h" #include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> #include <QBuffer> #include <QColor> @@ -68,7 +69,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) pen.setColor(Qt::black); pen.setWidth(1); pen.setCapStyle(Qt::FlatCap); - pen.setJoinStyle(Qt::MiterJoin); + pen.setJoinStyle(Qt::SvgMiterJoin); pen.setMiterLimit(10); painter->setPen(pen); QBrush brush = painter->brush(); @@ -79,7 +80,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) m_image = StillImage::createForRendering(&m_pixmap); } -ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success) : m_data(size) , m_size(size) { @@ -117,7 +118,7 @@ void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, if (destContext == context()) { // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first. RefPtr<Image> copy = copyImage(); - destContext->drawImage(copy.get(), DeviceColorSpace, destRect, srcRect, op, useLowQualityScale); + destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale); } else destContext->drawImage(m_data.m_image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale); } @@ -139,7 +140,7 @@ void ImageBuffer::clip(GraphicsContext* context, const FloatRect& floatRect) con if (!nativeImage) return; - IntRect rect(floatRect); + IntRect rect = enclosingIntRect(floatRect); QPixmap alphaMask = *nativeImage; if (alphaMask.width() != rect.width() || alphaMask.height() != rect.height()) alphaMask = alphaMask.scaled(rect.width(), rect.height()); @@ -216,7 +217,7 @@ PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& i const uchar* bits = image.bits(); #endif - quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() + destx]); + quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() * 4 + destx * 4]); if (multiplied == Unmultiplied) { for (int y = 0; y < numRows; ++y) { @@ -401,7 +402,8 @@ String ImageBuffer::toDataURL(const String& mimeType, const double* quality) con } buffer.close(); - return String::format("data:%s;base64,%s", mimeType.utf8().data(), data.toBase64().data()); + + return makeString("data:", mimeType, ";base64,", data.toBase64().data()); } } diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp index 1a31d1e..962c931 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp @@ -27,6 +27,7 @@ #include "HTMLVideoElement.h" #include "NetworkingContext.h" #include "NotImplemented.h" +#include "RenderVideo.h" #include "TimeRanges.h" #include "Widget.h" #include "qwebframe.h" @@ -42,6 +43,7 @@ #include <QPainter> #include <QPoint> #include <QRect> +#include <QStyleOptionGraphicsItem> #include <QTime> #include <QTimer> #include <QUrl> @@ -49,6 +51,10 @@ #include <wtf/HashSet.h> #include <wtf/text/CString.h> +#if USE(ACCELERATED_COMPOSITING) +#include "texmap/TextureMapperPlatformLayer.h" +#endif + using namespace WTF; namespace WebCore { @@ -93,6 +99,8 @@ MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player) , m_videoScene(new QGraphicsScene) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) + , m_currentSize(0, 0) + , m_naturalSize(RenderVideo::defaultSize()) , m_isVisible(false) , m_isSeeking(false) , m_composited(false) @@ -125,8 +133,7 @@ MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player) this, SLOT(nativeSizeChanged(QSizeF))); // Grab the player control - QMediaService* service = m_mediaPlayer->service(); - if (service) { + if (QMediaService* service = m_mediaPlayer->service()) { m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>( service->requestControl(QMediaPlayerControl_iid)); } @@ -134,6 +141,10 @@ MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player) MediaPlayerPrivateQt::~MediaPlayerPrivateQt() { + m_mediaPlayer->disconnect(this); + m_mediaPlayer->stop(); + m_mediaPlayer->setMedia(QMediaContent()); + delete m_mediaPlayer; delete m_videoScene; } @@ -330,8 +341,7 @@ float MediaPlayerPrivateQt::duration() const float MediaPlayerPrivateQt::currentTime() const { - float currentTime = m_mediaPlayer->position() / 1000.0f; - return currentTime; + return m_mediaPlayer->position() / 1000.0f; } PassRefPtr<TimeRanges> MediaPlayerPrivateQt::buffered() const @@ -437,8 +447,15 @@ void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State state) } } -void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF&) +void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF& size) { + LOG(Media, "MediaPlayerPrivateQt::naturalSizeChanged(%dx%d)", + size.toSize().width(), size.toSize().height()); + + if (!size.isValid()) + return; + + m_naturalSize = size.toSize(); m_webCorePlayer->sizeChanged(); } @@ -466,7 +483,7 @@ void MediaPlayerPrivateQt::seekTimeout() void MediaPlayerPrivateQt::positionChanged(qint64) { - // Only propogate this event if we are seeking + // Only propagate this event if we are seeking if (m_isSeeking && m_queuedSeek == -1) { m_webCorePlayer->timeChanged(); m_isSeeking = false; @@ -546,6 +563,9 @@ void MediaPlayerPrivateQt::updateStates() void MediaPlayerPrivateQt::setSize(const IntSize& size) { + LOG(Media, "MediaPlayerPrivateQt::setSize(%dx%d)", + size.width(), size.height()); + if (size == m_currentSize) return; @@ -555,10 +575,15 @@ void MediaPlayerPrivateQt::setSize(const IntSize& size) IntSize MediaPlayerPrivateQt::naturalSize() const { - if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) + if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) { + LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> 0x0 (!hasVideo || !haveMetaData)"); return IntSize(); + } - return IntSize(m_videoItem->nativeSize().toSize()); + LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> %dx%d (m_naturalSize)", + m_naturalSize.width(), m_naturalSize.height()); + + return m_naturalSize; } void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect) @@ -573,10 +598,7 @@ void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect) if (!m_isVisible) return; - // Grab the painter and widget QPainter* painter = context->platformContext(); - - // Render the video m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect()); } @@ -585,7 +607,41 @@ void MediaPlayerPrivateQt::repaint() m_webCorePlayer->repaint(); } -#if USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) + +class TextureMapperVideoLayerQt : public virtual TextureMapperVideoLayer { +public: + TextureMapperVideoLayerQt(QGraphicsVideoItem* videoItem) + : m_videoItem(videoItem) + { + } + + virtual void setPlatformLayerClient(TextureMapperLayerClient* client) + { + m_client = client; + } + + virtual void paint(GraphicsContext* context) + { + if (!m_videoItem) + return; + + QStyleOptionGraphicsItem opt; + opt.exposedRect = m_videoItem.data()->sceneBoundingRect(); + opt.rect = opt.exposedRect.toRect(); + m_videoItem.data()->paint(context->platformContext(), &opt); + } + + virtual IntSize size() const + { + return m_videoItem ? IntSize(m_videoItem.data()->size().width(), m_videoItem.data()->size().height()) : IntSize(); + } + + QWeakPointer<QGraphicsVideoItem> m_videoItem; + TextureMapperLayerClient* m_client; +}; + + void MediaPlayerPrivateQt::acceleratedRenderingStateChanged() { MediaPlayerClient* client = m_webCorePlayer->mediaPlayerClient(); @@ -595,14 +651,12 @@ void MediaPlayerPrivateQt::acceleratedRenderingStateChanged() m_composited = composited; if (composited) - m_videoScene->removeItem(m_videoItem); - else - m_videoScene->addItem(m_videoItem); + m_platformLayer = new TextureMapperVideoLayerQt(m_videoItem); } PlatformLayer* MediaPlayerPrivateQt::platformLayer() const { - return m_composited ? m_videoItem : 0; + return m_composited ? m_platformLayer.get() : 0; } #endif diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h index 179bf2a..93c9d1c 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h @@ -33,6 +33,8 @@ QT_END_NAMESPACE namespace WebCore { +class TextureMapperVideoLayer; + class MediaPlayerPrivateQt : public QObject, public MediaPlayerPrivateInterface { Q_OBJECT @@ -91,12 +93,18 @@ public: bool supportsFullscreen() const { return false; } #if USE(ACCELERATED_COMPOSITING) +#if USE(TEXTURE_MAPPER) // whether accelerated rendering is supported by the media engine for the current media. virtual bool supportsAcceleratedRendering() const { return true; } // called when the rendering system flips the into or out of accelerated rendering mode. virtual void acceleratedRenderingStateChanged(); // returns an object that can be directly composited via GraphicsLayerQt (essentially a QGraphicsItem*) virtual PlatformLayer* platformLayer() const; +#else + virtual bool supportsAcceleratedRendering() const { return false; } + virtual void acceleratedRenderingStateChanged() { } + virtual PlatformLayer* platformLayer() const { return 0; } +#endif #endif virtual PlatformMedia platformMedia() const; @@ -125,11 +133,15 @@ private: QMediaPlayerControl* m_mediaPlayerControl; QGraphicsVideoItem* m_videoItem; QGraphicsScene* m_videoScene; +#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) + OwnPtr<TextureMapperVideoLayer> m_platformLayer; +#endif mutable MediaPlayer::NetworkState m_networkState; mutable MediaPlayer::ReadyState m_readyState; IntSize m_currentSize; + IntSize m_naturalSize; bool m_isVisible; bool m_isSeeking; bool m_composited; diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index b8b9d5e..508ba6a 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -335,6 +335,8 @@ void Path::addEllipse(const FloatRect& r) void Path::clear() { + if (!m_path.elementCount()) + return; m_path = QPainterPath(); } @@ -355,41 +357,6 @@ FloatPoint Path::currentPoint() const return m_path.currentPosition(); } -String Path::debugString() const -{ - QString ret; - for (int i = 0; i < m_path.elementCount(); ++i) { - const QPainterPath::Element &cur = m_path.elementAt(i); - - switch (cur.type) { - case QPainterPath::MoveToElement: - ret += QString(QLatin1String("M%1,%2 ")).arg(cur.x, 0, 'f', 2).arg(cur.y, 0, 'f', 2); - break; - case QPainterPath::LineToElement: - ret += QString(QLatin1String("L%1,%2 ")).arg(cur.x, 0, 'f', 2).arg(cur.y, 0, 'f', 2); - break; - case QPainterPath::CurveToElement: - { - const QPainterPath::Element &c1 = m_path.elementAt(i + 1); - const QPainterPath::Element &c2 = m_path.elementAt(i + 2); - - Q_ASSERT(c1.type == QPainterPath::CurveToDataElement); - Q_ASSERT(c2.type == QPainterPath::CurveToDataElement); - - ret += QString(QLatin1String("C%1,%2,%3,%4,%5,%6 ")).arg(cur.x, 0, 'f', 2).arg(cur.y, 0, 'f', 2).arg(c1.x, 0, 'f', 2) - .arg(c1.y, 0, 'f', 2).arg(c2.x, 0, 'f', 2).arg(c2.y, 0, 'f', 2); - i += 2; - break; - } - case QPainterPath::CurveToDataElement: - Q_ASSERT(false); - break; - } - } - - return ret.trimmed(); -} - void Path::apply(void* info, PathApplierFunction function) const { PathElement pelement; diff --git a/WebCore/platform/graphics/qt/TextureMapperQt.cpp b/WebCore/platform/graphics/qt/TextureMapperQt.cpp new file mode 100644 index 0000000..9236dae --- /dev/null +++ b/WebCore/platform/graphics/qt/TextureMapperQt.cpp @@ -0,0 +1,225 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "texmap/TextureMapper.h" + +#include <QtCore/qdebug.h> +#include <QtGui/qpaintengine.h> +#include <QtGui/qpixmap.h> + +#ifdef QT_OPENGL_LIB +# include "opengl/TextureMapperGL.h" +#endif + +namespace WebCore { + +class BitmapTextureQt : public BitmapTexture { + friend class TextureMapperQt; +public: + BitmapTextureQt() {} + virtual void destroy(); + virtual IntSize size() const { return IntSize(m_pixmap.width(), m_pixmap.height()); } + virtual void reset(const IntSize&, bool opaque); + virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect); + virtual void endPaint(); + virtual void setContentsToImage(Image*); + virtual bool save(const String& path); + virtual bool isValid() const { return !m_pixmap.isNull(); } + virtual bool allowOfflineTextureUpload() const { return true; } + IntRect sourceRect() const { return IntRect(0, 0, contentSize().width(), contentSize().height()); } +private: + QPainter m_painter; + QPixmap m_pixmap; +}; + +class TextureMapperQt : public TextureMapper { +public: + virtual void drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture); + virtual void bindSurface(BitmapTexture* surface); + virtual void setClip(const IntRect&); + virtual bool allowSurfaceForRoot() const { return false; } + TextureMapperQt(GraphicsContext* context); + virtual const char* type() const { return "TextureMapperQt"; } + virtual PassRefPtr<BitmapTexture> createTexture(); + + static void initialize(QPainter* painter) + { + painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false); + } + +private: + QPainter* m_painter; + RefPtr<BitmapTextureQt> m_currentSurface; +}; + +void BitmapTextureQt::destroy() +{ + if (m_pixmap.paintingActive()) + qFatal("Destroying an active pixmap"); + m_pixmap = QPixmap(); +} + +void BitmapTextureQt::reset(const IntSize& size, bool isOpaque) +{ + BitmapTexture::reset(size, isOpaque); + + if (size.width() > m_pixmap.size().width() || size.height() > m_pixmap.size().height() || m_pixmap.isNull()) + m_pixmap = QPixmap(size.width(), size.height()); + if (!isOpaque) + m_pixmap.fill(Qt::transparent); +} + +PlatformGraphicsContext* BitmapTextureQt::beginPaint(const IntRect& dirtyRect) +{ + m_painter.begin(&m_pixmap); + TextureMapperQt::initialize(&m_painter); + m_painter.setCompositionMode(QPainter::CompositionMode_Clear); + m_painter.fillRect(QRect(dirtyRect), Qt::transparent); + m_painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + return &m_painter; +} + +void BitmapTextureQt::endPaint() +{ + m_painter.end(); +} + +bool BitmapTextureQt::save(const String& path) +{ + return m_pixmap.save(path, "PNG"); +} + +void BitmapTextureQt::setContentsToImage(Image* image) +{ + if (!image) + return; + const QPixmap* pixmap = image->nativeImageForCurrentFrame(); + if (!pixmap) + return; + BitmapTexture::reset(pixmap->size(), !pixmap->hasAlphaChannel()); + m_pixmap = *pixmap; +} + +void TextureMapperQt::setClip(const IntRect& rect) +{ + QPainter* painter = m_currentSurface ? &m_currentSurface->m_painter : m_painter; + painter->setClipRect(rect); +} + +TextureMapperQt::TextureMapperQt(GraphicsContext* context) + : TextureMapper(context) + , m_painter(context->platformContext()) + , m_currentSurface(0) +{ + TextureMapperQt::initialize(m_painter); +} + +void TextureMapperQt::bindSurface(BitmapTexture* surface) +{ + if (m_currentSurface == surface) + return; + if (m_currentSurface) + m_currentSurface->m_painter.end(); + if (!surface) { + m_currentSurface = 0; + return; + } + BitmapTextureQt* surfaceQt = static_cast<BitmapTextureQt*>(surface); + if (!surfaceQt->m_painter.isActive()) + surfaceQt->m_painter.begin(&surfaceQt->m_pixmap); + m_currentSurface = surfaceQt; +} + + +void TextureMapperQt::drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture) +{ + const BitmapTextureQt& textureQt = static_cast<const BitmapTextureQt&>(texture); + QPainter* painter = m_painter; + QPixmap pixmap = textureQt.m_pixmap; + if (m_currentSurface) + painter = &m_currentSurface->m_painter; + + if (maskTexture && maskTexture->isValid()) { + const BitmapTextureQt* mask = static_cast<const BitmapTextureQt*>(maskTexture); + QPixmap intermediatePixmap(pixmap.size()); + intermediatePixmap.fill(Qt::transparent); + QPainter maskPainter(&intermediatePixmap); + maskPainter.setCompositionMode(QPainter::CompositionMode_Source); + maskPainter.drawPixmap(0, 0, pixmap); + maskPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + maskPainter.drawPixmap(QRect(0, 0, pixmap.width(), pixmap.height()), mask->m_pixmap, mask->sourceRect()); + maskPainter.end(); + pixmap = intermediatePixmap; + } + + const qreal prevOpacity = painter->opacity(); + const QTransform prevTransform = painter->transform(); + painter->setOpacity(opacity); + painter->setTransform(matrix, true); + painter->drawPixmap(targetRect, pixmap, textureQt.sourceRect()); + painter->setTransform(prevTransform); + painter->setOpacity(prevOpacity); +} + +PassRefPtr<TextureMapper> TextureMapper::create(GraphicsContext* context) +{ +#ifdef QT_OPENGL_LIB + if (context->platformContext()->paintEngine()->type() == QPaintEngine::OpenGL2) + return adoptRef(new TextureMapperGL(context)); +#endif + return adoptRef(new TextureMapperQt(context)); +} + + +PassRefPtr<BitmapTexture> TextureMapperQt::createTexture() +{ + return adoptRef(new BitmapTextureQt()); +} + +#ifdef QT_OPENGL_LIB +class RGBA32PremultimpliedBufferQt : public RGBA32PremultimpliedBuffer { +public: + virtual PlatformGraphicsContext* beginPaint(const IntRect& rect, bool opaque) + { + // m_image is only using during paint, it's safe to override it. + m_image = QImage(rect.size().width(), rect.size().height(), QImage::Format_ARGB32_Premultiplied); + if (!opaque) + m_image.fill(0); + m_painter.begin(&m_image); + TextureMapperQt::initialize(&m_painter); + m_painter.translate(-rect.x(), -rect.y()); + return &m_painter; + } + + virtual void endPaint() { m_painter.end(); } + virtual const void* data() const { return m_image.constBits(); } + +private: + QPainter m_painter; + QImage m_image; +}; + +PassRefPtr<RGBA32PremultimpliedBuffer> RGBA32PremultimpliedBuffer::create() +{ + return adoptRef(new RGBA32PremultimpliedBufferQt()); +} + +#endif +}; diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 2be7dc5..143d667 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -45,6 +45,8 @@ #include "SkColorPriv.h" #include "SkiaUtils.h" +#include <wtf/text/StringConcatenate.h> + using namespace std; namespace WebCore { @@ -58,7 +60,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) { } -ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, bool& success) : m_data(size) , m_size(size) { @@ -290,6 +292,7 @@ void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) { + context()->platformContext()->prepareForSoftwareDraw(); putImageData<Unmultiplied>(source, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); } @@ -311,7 +314,7 @@ String ImageBuffer::toDataURL(const String&, const double*) const base64EncodedData.append('\0'); // And the resulting string. - return String::format("data:image/png;base64,%s", base64EncodedData.data()); + return makeString("data:image/png;base64,", base64EncodedData.data()); } } // namespace WebCore diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index e123256..23e7be6 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -143,9 +143,7 @@ static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext // Everything else gets resampled. // If the platform context permits high quality interpolation, use it. - // High quality interpolation only enabled for scaling and translation. - if (platformContext->interpolationQuality() == InterpolationHigh - && !(platformContext->canvas()->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask))) + if (platformContext->interpolationQuality() == InterpolationHigh) return RESAMPLE_AWESOME; return RESAMPLE_LINEAR; @@ -175,12 +173,8 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm && srcIRect.height() == bitmap.height(); // We will always draw in integer sizes, so round the destination rect. - // First we need to apply canvas transformation matrix to get desired size of - // resampled image. - SkRect destRectTransformed; - canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect); SkIRect destRectRounded; - destRectTransformed.round(&destRectRounded); + destRect.round(&destRectRounded); SkIRect resizedImageRect = // Represents the size of the resized image. { 0, 0, destRectRounded.width(), destRectRounded.height() }; @@ -194,10 +188,7 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm // Compute the visible portion of our rect. SkRect destBitmapSubsetSk; ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk); - // Determine size of resampled image based on clipped destination rect. - SkRect destBitmapSubsetSkTransformed; - canvas.getTotalMatrix().mapRect(&destBitmapSubsetSkTransformed, destBitmapSubsetSk); - destBitmapSubsetSkTransformed.offset(-destBitmapSubsetSkTransformed.fLeft, -destBitmapSubsetSkTransformed.fTop); + destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop); // The matrix inverting, etc. could have introduced rounding error which // causes the bounds to be outside of the resized bitmap. We round outward @@ -205,7 +196,7 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm // need, and then clamp to the bitmap bounds so we don't get any invalid // data. SkIRect destBitmapSubsetSkI; - destBitmapSubsetSkTransformed.roundOut(&destBitmapSubsetSkI); + destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI); if (!destBitmapSubsetSkI.intersect(resizedImageRect)) return; // Resized image does not intersect. diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp index 12241f8..89323c4 100644 --- a/WebCore/platform/graphics/skia/PathSkia.cpp +++ b/WebCore/platform/graphics/skia/PathSkia.cpp @@ -227,62 +227,6 @@ void Path::transform(const AffineTransform& xform) m_path->transform(xform); } -String Path::debugString() const -{ - String result; - - SkPath::Iter iter(*m_path, false); - SkPoint pts[4]; - - int numPoints = m_path->getPoints(0, 0); - SkPath::Verb verb; - - do { - verb = iter.next(pts); - switch (verb) { - case SkPath::kMove_Verb: - result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY); - numPoints -= 1; - break; - case SkPath::kLine_Verb: - if (!iter.isCloseLine()) { - result += String::format("L%.2f,%.2f ", pts[1].fX, pts[1].fY); - numPoints -= 1; - } - break; - case SkPath::kQuad_Verb: - result += String::format("Q%.2f,%.2f,%.2f,%.2f ", - pts[1].fX, pts[1].fY, - pts[2].fX, pts[2].fY); - numPoints -= 2; - break; - case SkPath::kCubic_Verb: - result += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ", - pts[1].fX, pts[1].fY, - pts[2].fX, pts[2].fY, - pts[3].fX, pts[3].fY); - numPoints -= 3; - break; - case SkPath::kClose_Verb: - result += "Z "; - break; - case SkPath::kDone_Verb: - break; - } - } while (verb != SkPath::kDone_Verb); - - // If you have a path that ends with an M, Skia will not iterate the - // trailing M. That's nice of it, but Apple's paths output the trailing M - // and we want out layout dumps to look like theirs - if (numPoints) { - ASSERT(numPoints==1); - m_path->getLastPt(pts); - result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY); - } - - return result.stripWhiteSpace(); -} - // Computes the bounding box for the stroke and style currently selected into // the given bounding box. This also takes into account the stroke width. static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context) diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index b469312..3f9e4c1 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -34,12 +34,10 @@ #include "AffineTransform.h" #include "DrawingBuffer.h" -#include "GLES2Canvas.h" #include "GraphicsContext.h" #include "GraphicsContext3D.h" #include "ImageBuffer.h" #include "NativeImageSkia.h" -#include "SharedGraphicsContext3D.h" #include "SkiaUtils.h" #include "Texture.h" #include "TilingData.h" @@ -56,6 +54,11 @@ #include <wtf/OwnArrayPtr.h> #include <wtf/Vector.h> +#if ENABLE(ACCELERATED_2D_CANVAS) +#include "GLES2Canvas.h" +#include "SharedGraphicsContext3D.h" +#endif + namespace WebCore { extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path); @@ -207,7 +210,9 @@ PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) : m_canvas(canvas) , m_drawingToImageBuffer(false) , m_useGPU(false) +#if ENABLE(ACCELERATED_2D_CANVAS) , m_gpuCanvas(0) +#endif , m_backingStoreState(None) { m_stateStack.append(State()); @@ -216,8 +221,10 @@ PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) PlatformContextSkia::~PlatformContextSkia() { +#if ENABLE(ACCELERATED_2D_CANVAS) if (m_gpuCanvas) m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0); +#endif } void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas) @@ -705,6 +712,7 @@ private: void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* drawingBuffer, const WebCore::IntSize& size) { +#if ENABLE(ACCELERATED_2D_CANVAS) if (context && drawingBuffer) { m_useGPU = true; m_gpuCanvas = new GLES2Canvas(context, drawingBuffer, size); @@ -716,6 +724,7 @@ void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* co m_gpuCanvas.clear(); m_useGPU = false; } +#endif } void PlatformContextSkia::prepareForSoftwareDraw() const @@ -808,6 +817,7 @@ void PlatformContextSkia::markDirtyRect(const IntRect& rect) void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const { +#if ENABLE(ACCELERATED_2D_CANVAS) const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(false); SkAutoLockPixels lock(bitmap); SharedGraphicsContext3D* context = m_gpuCanvas->context(); @@ -816,7 +826,7 @@ void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const m_uploadTexture->updateSubRect(bitmap.getPixels(), m_softwareDirtyRect); AffineTransform identity; - gpuCanvas()->drawTexturedRect(m_uploadTexture.get(), m_softwareDirtyRect, m_softwareDirtyRect, identity, 1.0, DeviceColorSpace, op); + gpuCanvas()->drawTexturedRect(m_uploadTexture.get(), m_softwareDirtyRect, m_softwareDirtyRect, identity, 1.0, ColorSpaceDeviceRGB, op); // Clear out the region of the software canvas we just uploaded. m_canvas->save(); m_canvas->resetMatrix(); @@ -825,10 +835,12 @@ void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); m_canvas->restore(); m_softwareDirtyRect.setWidth(0); // Clear dirty rect. +#endif } void PlatformContextSkia::readbackHardwareToSoftware() const { +#if ENABLE(ACCELERATED_2D_CANVAS) const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(true); SkAutoLockPixels lock(bitmap); int width = bitmap.width(), height = bitmap.height(); @@ -850,6 +862,7 @@ void PlatformContextSkia::readbackHardwareToSoftware() const } } m_softwareDirtyRect.unite(IntRect(0, 0, width, height)); // Mark everything as dirty. +#endif } } // namespace WebCore diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h index eb03224..84e5d78 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.h +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -183,8 +183,11 @@ public: bool canvasClipApplied() const; bool useGPU() { return m_useGPU; } void setSharedGraphicsContext3D(SharedGraphicsContext3D*, DrawingBuffer*, const IntSize&); +#if ENABLE(ACCELERATED_2D_CANVAS) GLES2Canvas* gpuCanvas() const { return m_gpuCanvas.get(); } - +#else + GLES2Canvas* gpuCanvas() const { return 0; } +#endif // Call these before making a call that manipulates the underlying // skia::PlatformCanvas or WebCore::GLES2Canvas void prepareForSoftwareDraw() const; @@ -224,9 +227,11 @@ private: FloatSize m_imageResamplingHintDstSize; bool m_drawingToImageBuffer; bool m_useGPU; +#if ENABLE(ACCELERATED_2D_CANVAS) OwnPtr<GLES2Canvas> m_gpuCanvas; - mutable enum { None, Software, Mixed, Hardware } m_backingStoreState; mutable RefPtr<Texture> m_uploadTexture; +#endif + mutable enum { None, Software, Mixed, Hardware } m_backingStoreState; mutable IntRect m_softwareDirtyRect; }; diff --git a/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp new file mode 100644 index 0000000..cf90cb1 --- /dev/null +++ b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -0,0 +1,1444 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "GraphicsLayerTextureMapper.h" + +#include "CurrentTime.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "HashMap.h" +#include "Image.h" +#include "RefCounted.h" +#include "TextureMapper.h" +#include "TextureMapperPlatformLayer.h" +#include "Timer.h" +#include "TransformOperations.h" +#include "TranslateTransformOperation.h" +#include "UnitBezier.h" + +#define DEBUG_TEXMAP_FPS 0 + +namespace WebCore { + +struct TexmapPaintOptions { + BitmapTexture* surface; + TextureMapper* textureMapper; + GraphicsContext* context; + TextureMapperNode* rootLayer; + float opacity; + IntRect scissorRect; + IntRect visibleRect; + bool isSurface; +}; +class TextureMapperCache { +public: + void mark(BitmapTexture* texture); + + class Entry { + public: + RefPtr<BitmapTexture> texture; + Entry() : previousCost(0) { } + inline int calculateCost() const + { + if (!texture || !texture->isValid()) + return 0; + const IntSize textureSize = texture->size(); + // an image's cost in bytes is width * height * bytes per pixel (4). + return textureSize.width() * textureSize.height() * 4; + } + Entry(BitmapTexture* newTexture) + : texture(newTexture) + { + } + bool operator==(const Entry& other) const { return texture == other.texture; } + int previousCost; + }; + + TextureMapperCache() : m_totalCost(0) {} + + void purge(); + Vector<Entry> m_data; + int m_totalCost; +#ifndef TEXMAP_TEXTURE_CACHE_KBS +#define TEXMAP_TEXTURE_CACHE_KBS 24 * 1024 +#endif + static const int MaxCost = TEXMAP_TEXTURE_CACHE_KBS * 1024; + static const int PurgeAmount = MaxCost / 4; +}; + + +void TextureMapperCache::purge() +{ + // If this is in the GL implementation, we need an active GL context, because we might call glDeleteTextures. + const int size = m_data.size(); + + if (m_totalCost <= TextureMapperCache::MaxCost) + return; + + // Ensure that we have the right count. It might be inaccurate if content changed size. + // We only do this when we're actually ready to purge. + m_totalCost = 0; + for (int i = 0; i < size; ++i) + m_totalCost += m_data[i].calculateCost(); + + for (int i = size-1; i >= 0 && m_totalCost > TextureMapperCache::MaxCost - TextureMapperCache::PurgeAmount; --i) { + Entry& entry = m_data[i]; + if (entry.texture->isLocked() || !entry.texture->isValid()) + continue; + m_totalCost -= entry.previousCost; + entry.texture->destroy(); + m_data.remove(i); + } +} + +void TextureMapperCache::mark(BitmapTexture* texture) +{ + if (!texture || !texture->isValid()) + return; + + Entry entry(texture); + size_t index = m_data.find(entry); + if (!index) + return; + + if (index < m_data.size()) + m_data.remove(index); + const int cost = entry.calculateCost(); + m_totalCost -= entry.previousCost; + m_totalCost += (entry.previousCost = cost); + m_data.prepend(entry); +} + +TextureMapperCache gTextureMapperCache; + +class TextureMapperCacheLock { +public: + TextureMapperCacheLock(BitmapTexture* texture) : m_texture(texture) + { + if (m_texture) + m_texture->lock(); + } + ~TextureMapperCacheLock() + { + if (m_texture) + m_texture->unlock(); + } + +private: + RefPtr<BitmapTexture> m_texture; +}; + +class TextureMapperNode : public TextureMapperContentLayer { + +public: + // This set of flags help us defer which properties of the layer have been + // modified by the compositor, so we can know what to look for in the next flush. + enum ChangeMask { + NoChanges = 0, + + ParentChange = (1L << 0), + ChildrenChange = (1L << 1), + MaskLayerChange = (1L << 2), + PositionChange = (1L << 3), + + AnchorPointChange = (1L << 4), + SizeChange = (1L << 5), + TransformChange = (1L << 6), + ContentChange = (1L << 7), + + ContentsOrientationChange = (1L << 9), + OpacityChange = (1L << 10), + ContentsRectChange = (1L << 11), + + Preserves3DChange = (1L << 12), + MasksToBoundsChange = (1L << 13), + DrawsContentChange = (1L << 14), + ContentsOpaqueChange = (1L << 15), + + BackfaceVisibilityChange = (1L << 16), + ChildrenTransformChange = (1L << 17), + DisplayChange = (1L << 18), + BackgroundColorChange = (1L << 19), + + ReplicaLayerChange = (1L << 20) + }; + + // The compositor lets us special-case images and colors, so we try to do so. + enum StaticContentType { HTMLContentType, DirectImageContentType, ColorContentType, MediaContentType, Canvas3DContentType}; + + TextureMapperNode* rootLayer(); + + TextureMapperNode(GraphicsLayerTextureMapper* newLayer); + virtual ~TextureMapperNode(); + + void clearDirectImage(); + void computeTransformations(); + IntSize nearestSurfaceSize() const; + void computeReplicaTransform(); + void computeLayerType(); + void computeLocalTransform(); + void flattenTo2DSpaceIfNecessary(); + void initializeTextureMapper(TextureMapper*); + void invalidateTransform(); + void notifyChange(ChangeMask); + void syncCompositingState(bool recurse); + void performPostSyncOperations(); + void setNeedsDisplay(); + void setNeedsDisplayInRect(IntRect); + virtual void cleanupTextureMapper(); + + void paintRecursive(TexmapPaintOptions options); + void paintSelf(const TexmapPaintOptions& options); + void uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect); + + int countDescendantsWithContent() const; + bool hasSurfaceDescendants() const; + + IntSize size() const { return m_size; } + + virtual void setPlatformLayerClient(TextureMapperLayerClient*); + virtual void paint(GraphicsContext*, const IntSize&, const IntRect& targetRect, const IntRect& exposedRect, const TransformationMatrix& transform, float opacity); + + static TextureMapperNode* toTextureMapperNode(GraphicsLayer*); +public: + GraphicsLayerTextureMapper* m_layer; + const char* m_lastTextureMapperType; + RefPtr<TextureMapper> m_lastTextureMapper; + struct TransformData { + TransformationMatrix base, target, replica, forDescendants, perspective, local; + IntRect targetBoundingRect; + float centerZ; + bool dirty, localDirty, perspectiveDirty; + IntRect boundingRectFromRoot; + TransformData() : dirty(true), localDirty(true), perspectiveDirty(true) { } + }; + + TransformData m_transforms; + + enum LayerType { + DefaultLayer, + RootLayer, + ScissorLayer, + ClipLayer, + TransparencyLayer + }; + + LayerType m_layerType; + + struct ContentData { + IntRect needsDisplayRect; + bool needsDisplay; + Color backgroundColor; + + StaticContentType contentType; + RefPtr<Image> image; + TextureMapperVideoLayer* media; + + ContentData() + : needsDisplay(false) + , contentType(HTMLContentType) + , image(0) + , media(0) + { + } + + }; + + inline IntRect targetRect() const + { + return m_currentContent.contentType == HTMLContentType ? entireRect() : m_state.contentsRect; + } + + inline IntRect entireRect() const + { + return IntRect(0, 0, m_size.width(), m_size.height()); + } + + inline IntRect replicaRect() const + { + return m_layerType == TransparencyLayer ? IntRect(0, 0, m_nearestSurfaceSize.width(), m_nearestSurfaceSize.height()) : entireRect(); + } + + RefPtr<BitmapTexture> m_texture; + RefPtr<BitmapTexture> m_surface, m_replicaSurface; + + ContentData m_pendingContent; + ContentData m_currentContent; + + Vector<TextureMapperNode*> m_children; + TextureMapperNode* m_parent; + TextureMapperNode* m_effectTarget; + int m_changeMask; + IntSize m_size, m_nearestSurfaceSize; + String m_name; + TextureMapperLayerClient* m_platformClient; + + struct State { + FloatPoint pos; + FloatPoint3D anchorPoint; + FloatSize size; + TransformationMatrix transform; + TransformationMatrix childrenTransform; + Color backgroundColor; + Color currentColor; + GraphicsLayer::CompositingCoordinatesOrientation geoOrientation; + GraphicsLayer::CompositingCoordinatesOrientation contentsOrientation; + float opacity; + IntRect contentsRect; + int descendantsWithContent; + TextureMapperNode* maskLayer; + TextureMapperNode* replicaLayer; + bool preserves3D; + bool masksToBounds; + bool drawsContent; + bool contentsOpaque; + bool backfaceVisibility; + bool visible; + bool dirty; + bool tiled; + bool hasSurfaceDescendants; + + State() + : opacity(1.f) + , descendantsWithContent(0) + , maskLayer(0) + , replicaLayer(0) + , preserves3D(false) + , masksToBounds(false) + , drawsContent(false) + , contentsOpaque(false) + , backfaceVisibility(false) + , visible(true) + , dirty(true) + , tiled(false) + , hasSurfaceDescendants(false) + { + } + }; + State m_state; +}; + +void TextureMapperNode::setNeedsDisplayInRect(IntRect rect) +{ + if (m_platformClient) { + if (m_state.hasSurfaceDescendants) { + m_platformClient->setNeedsDisplay(); + return; + } + rect.intersect(IntRect(0, 0, m_size.width(), m_size.height())); + if (rect.isEmpty()) + return; + m_platformClient->setNeedsDisplayInRect(rect); + return; + } + + if (!m_parent) + return; + + m_parent->setNeedsDisplayInRect(rect); +} + +void TextureMapperNode::setNeedsDisplay() +{ + if (m_effectTarget) + m_effectTarget->setNeedsDisplay(); + if (m_transforms.targetBoundingRect.isEmpty()) + return; + if (m_state.drawsContent || m_currentContent.contentType != HTMLContentType) + setNeedsDisplayInRect(m_transforms.targetBoundingRect); +} + + +void TextureMapperNode::setPlatformLayerClient(TextureMapperLayerClient* client) +{ + m_platformClient = client; +} + +static int compareGraphicsLayersZValue(const void* a, const void* b) +{ + typedef const TextureMapperNode* NodePtr; + const NodePtr* nodeA = static_cast<const NodePtr*>(a); + const NodePtr* nodeB = static_cast<const NodePtr*>(b); + return int(((*nodeA)->m_transforms.centerZ - (*nodeB)->m_transforms.centerZ) * 1000); +} +inline static void sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last) +{ + qsort(array.data(), array.size(), sizeof(TextureMapperNode*), compareGraphicsLayersZValue); +} + +bool TextureMapperNode::hasSurfaceDescendants() const +{ + if (m_layerType == ClipLayer || m_layerType == TransparencyLayer || m_state.replicaLayer) + return true; + const int size = m_children.size(); + for (int i = 0; i < size; ++i) { + if (TextureMapperNode* child = m_children[i]) { + if (child->hasSurfaceDescendants()) + return true; + } + } + return false; + +} + +void TextureMapperNode::paint(GraphicsContext* context, const IntSize& size, const IntRect& targetRect, const IntRect& exposedRect, const TransformationMatrix& transform, float opacity) +{ + ASSERT(m_layerType == RootLayer); + if (m_size.isEmpty()) + return; + +#if 0 + WTF::StopWatch stopWatch; + ("[TextureMapper] RootPaint!!\n"); +#endif + + RefPtr<TextureMapper> textureMapper = TextureMapper::create(context); + + if (textureMapper->type() != m_lastTextureMapperType) + gTextureMapperCache.m_data.clear(); + + m_lastTextureMapper = textureMapper; + TexmapPaintOptions opt; + opt.opacity = 1; + opt.rootLayer = this; + opt.scissorRect = targetRect; + opt.visibleRect = exposedRect; + opt.textureMapper = textureMapper.get(); + opt.context = textureMapper->graphicsContext(); + opt.surface = 0; + paintRecursive(opt); + + if (textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants) { + textureMapper->bindSurface(0); + textureMapper->paintToTarget(*m_surface.get(), size, transform, opacity * m_state.opacity, targetRect); + } + gTextureMapperCache.purge(); +} + +int TextureMapperNode::countDescendantsWithContent() const +{ + if (!m_state.visible || m_state.opacity < 0.001) + return 0; + int descendantsWithContent = (m_state.drawsContent || m_currentContent.contentType != HTMLContentType) ? 1 : 0; + + const int size = m_children.size(); + for (int i = 0; i < size; ++i) { + if (TextureMapperNode* child = m_children[i]) + descendantsWithContent += child->countDescendantsWithContent(); + } + + return descendantsWithContent; +} + +inline TextureMapperNode* TextureMapperNode::toTextureMapperNode(GraphicsLayer* layer) +{ + return layer ? static_cast<GraphicsLayerTextureMapper*>(layer)->m_node.get() : 0; +} + +void TextureMapperNode::computeLayerType() +{ + // calculate layer type. A layer can be one of the following: + // RootLayer: the top level. Draws to a framebuffer, and the target texture draws into the viewport. + // only one layer is the root layer. + // ScissorLayer: draws to the current framebuffer, and applies an extra scissor before drawing its children. + // A scissor layer is a layer with children that masks to bounds, is not a transparency layer, and has a rectangular clip. + // ClipLayer: creates a new framebuffer, the size of the layer, and then paints it to the enclosing BitmapTexture with the layer's transform/opacity. + // A clip layer is a layer that masks to bounds, doesn't preserve 3D, has children, and has a transparency/mask or a non-rectangular transform. + // TransparencyLayer: creates a new framebuffer idetical in size to the current framebuffer. Then draws the fb's texture to the current framebuffer with identity transform. + // Used for layers with children and transparency/mask that preserve 3D or don't mask to bounds. + // DefaultLayer: draws itself and its children directly to the current framebuffer. + // any layer that doesn't conform to the other rules is a DefaultLayer. + + const bool selfHasContent = m_state.drawsContent || (m_currentContent.contentType != HTMLContentType); + const bool hasDescendantsWithContent = m_state.descendantsWithContent - (selfHasContent ? 1 : 0); + const bool hasTransparency = m_state.opacity < 0.99 || m_state.maskLayer; + const bool hasReplica = m_state.replicaLayer; + m_layerType = DefaultLayer; + + // Layer has no parent, it must be a root layer. + if (!m_parent && !m_effectTarget) { + m_layerType = RootLayer; + return; + } + + // A layer with no contents is always a default layer. + if (!m_state.descendantsWithContent) + return; + + // A layer with content-descendants and a mask is always a clip layer. + if (hasDescendantsWithContent && m_state.maskLayer) { + m_layerType = ClipLayer; + return; + } + + // A masks-to bounds layer can be a clip or a scissor layer. It's a scissor layer only if it has a trivial clip (identity or translation), or if it has transparency. + // That's because a ClipLayer would create an intermediate drawing surface (FB) - we want to limit it to when it's actually necessary, i.e. transparency or non-trivial clip. + if (m_state.masksToBounds && hasDescendantsWithContent) { + if (hasTransparency || !m_state.transform.isIdentityOrTranslation() || m_parent->m_state.preserves3D) + m_layerType = ClipLayer; + else + m_layerType = ScissorLayer; + return; + } + + // We use a transparency layer when we have two of the following 3: replica, transparency, descendants with contents. + if ((hasReplica && hasDescendantsWithContent) || (hasReplica && hasTransparency) || (hasTransparency && m_state.descendantsWithContent > 1)) + m_layerType = TransparencyLayer; +} +void TextureMapperNode::initializeTextureMapper(TextureMapper* textureMapper) +{ + if (textureMapper->type() == m_lastTextureMapperType) + return; + m_surface = textureMapper->createTexture(); + m_replicaSurface = textureMapper->createTexture(); + m_texture = textureMapper->createTexture(); + gTextureMapperCache.mark(m_texture.get()); + m_lastTextureMapperType = textureMapper->type(); +} + +TextureMapperNode::TextureMapperNode(GraphicsLayerTextureMapper* newLayer) + : m_layer(newLayer) + , m_lastTextureMapperType(0) + , m_lastTextureMapper(0) + , m_layerType(DefaultLayer) + , m_surface(0) + , m_parent(0) + , m_effectTarget(0) + , m_changeMask(NoChanges) + , m_platformClient(0) +{ + +} + +TextureMapperNode* TextureMapperNode::rootLayer() +{ + if (m_effectTarget) + return m_effectTarget->rootLayer(); + if (m_parent) + return m_parent->rootLayer(); + return this; +} + +void TextureMapperNode::invalidateTransform() +{ + m_transforms.dirty = true; + if (m_layerType != ClipLayer) + m_state.dirty = true; + if (m_state.replicaLayer) + m_state.replicaLayer->invalidateTransform(); + const int size = m_children.size(); + for (int i = 0; i < size; ++i) { + if (TextureMapperNode* layer = m_children[i]) + layer->invalidateTransform(); + } +} + +void TextureMapperNode::computeLocalTransform() +{ + if (!m_transforms.localDirty) + return; + const float originX = m_state.anchorPoint.x() * m_size.width(); + const float originY = m_state.anchorPoint.y() * m_size.height(); + m_transforms.local = + TransformationMatrix() + .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z()) + .multLeft(m_state.transform) + .translate3d(-originX, -originY, -m_state.anchorPoint.z()); + m_transforms.localDirty = false; +} + +void TextureMapperNode::flattenTo2DSpaceIfNecessary() +{ + if (m_state.preserves3D) + return; + m_transforms.forDescendants.setM13(0); + m_transforms.forDescendants.setM23(0); + m_transforms.forDescendants.setM31(0); + m_transforms.forDescendants.setM32(0); + m_transforms.forDescendants.setM33(1); + m_transforms.forDescendants.setM34(0); + m_transforms.forDescendants.setM43(0); +} + +IntSize TextureMapperNode::nearestSurfaceSize() const +{ + if (m_layerType == ClipLayer || m_layerType == RootLayer) + return m_surface && !m_surface->size().isEmpty() ? m_surface->size() : m_size; + return m_parent->nearestSurfaceSize(); +} + +void TextureMapperNode::computeReplicaTransform() +{ + if (!m_state.replicaLayer) + return; + + m_nearestSurfaceSize = nearestSurfaceSize(); + + if (m_layerType != TransparencyLayer) { + m_transforms.replica = TransformationMatrix(m_transforms.target).multLeft(m_state.replicaLayer->m_transforms.local); + return; + } + + const float originX = m_transforms.target.m41(); + const float originY = m_transforms.target.m42(); + m_transforms.replica = + TransformationMatrix() + .translate(originX, originY) + .multLeft(m_state.replicaLayer->m_transforms.local) + .translate(-originX, -originY); +} + +void TextureMapperNode::computeTransformations() +{ + if (!m_transforms.dirty) + return; + + m_transforms.dirty = false; + if ((m_size.isEmpty() && m_state.masksToBounds)) + return; + + TextureMapperNode* parent = m_parent; + computeLocalTransform(); + + m_transforms.target = TransformationMatrix(parent ? parent->m_transforms.forDescendants : TransformationMatrix()).multLeft(m_transforms.local); + m_transforms.forDescendants = (m_layerType == ClipLayer ? TransformationMatrix() : m_transforms.target); + + if (m_effectTarget) + return; + + m_transforms.targetBoundingRect = IntRect(m_transforms.target.mapRect(entireRect())); + if (m_state.replicaLayer) + m_state.replicaLayer->computeTransformations(); + + flattenTo2DSpaceIfNecessary(); + + if (!m_state.backfaceVisibility && m_transforms.target.inverse().m33() < 0) { + m_state.visible = false; + return; + } + m_state.visible = true; + + if (parent && parent->m_state.preserves3D) + m_transforms.centerZ = m_transforms.target.mapPoint(FloatPoint3D(m_size.width() / 2, m_size.height() / 2, 0)).z(); + + if (!m_children.size()) + return; + + if (m_state.childrenTransform.isIdentity()) + return; + + const FloatPoint centerPoint = FloatPoint(m_size.width() / 2, m_size.height() / 2); + if (m_transforms.perspectiveDirty) + m_transforms.perspective = TransformationMatrix() + .translate(centerPoint.x(), centerPoint.y()) + .multLeft(m_state.childrenTransform) + .translate(-centerPoint.x(), -centerPoint.y()); + m_transforms.perspectiveDirty = false; + m_transforms.forDescendants.multLeft(m_transforms.perspective); +} + +void TextureMapperNode::uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect) +{ + if (m_size.isEmpty() || !m_layer) { + m_texture->destroy(); + return; + } + + if (m_currentContent.contentType == DirectImageContentType) { + if (m_currentContent.image) + m_texture->setContentsToImage(m_currentContent.image.get()); + return; + } + + if (m_currentContent.contentType == MediaContentType) { + if (!m_currentContent.media) + return; + m_texture->reset(m_size, true); + PlatformGraphicsContext* platformContext = m_texture->beginPaintMedia(); + GraphicsContext context(platformContext); + m_currentContent.media->paint(&context); + m_texture->endPaint(); + return; + } + + const bool needsReset = (m_texture->contentSize() != m_size) || !m_texture->isValid(); + if ((m_currentContent.contentType != HTMLContentType) + || (!m_currentContent.needsDisplay && m_currentContent.needsDisplayRect.isEmpty() && !needsReset)) + return; + + WTF::StopWatch stopWatch; + IntRect dirtyRect = IntRect(0, 0, m_size.width(), m_size.height()); + if (!needsReset && !m_currentContent.needsDisplay) + dirtyRect.intersect(m_currentContent.needsDisplayRect); + if (needsReset) + m_texture->reset(m_size, m_state.contentsOpaque); + m_pendingContent.needsDisplayRect = IntRect(); + + { + GraphicsContext context(m_texture->beginPaint(dirtyRect)); + if (textureMapper && textureMapper->graphicsContext()) { + GraphicsContext* originalContext = textureMapper->graphicsContext(); + context.setImageInterpolationQuality(originalContext->imageInterpolationQuality()); + context.setTextDrawingMode(originalContext->textDrawingMode()); + } + m_layer->paintGraphicsLayerContents(context, dirtyRect); + } + m_texture->endPaint(); + { +#if 0 + LOG("[TextureMapper] Re-render(%d) layer(%p) %d::%d::%d (%dx%d) [%dms]\n", ++renderCount, this, + needsReset, m_currentContent.needsDisplay, !m_currentContent.needsDisplayRect.isEmpty(), + dirtyRect.width(), dirtyRect.height(), int(stopWatch.elapsed() * 1000)); + static int renderCount = 0; + m_texture->save(String().format("/tmp/layer_%d.png", renderCount)); +#endif + } + m_currentContent.needsDisplay = false; + +} + +void TextureMapperNode::paintSelf(const TexmapPaintOptions& options) +{ + if (!m_layer || m_size.isEmpty() || (!m_state.drawsContent && m_currentContent.contentType == HTMLContentType)) + return; + + RefPtr<BitmapTexture> maskTexture = m_state.maskLayer ? m_state.maskLayer->m_texture : 0; + RefPtr<BitmapTexture> replicaMaskTexture = 0; + if (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer) + replicaMaskTexture = m_state.replicaLayer->m_state.maskLayer->m_texture; + + const float opacity = options.isSurface ? 1 : options.opacity; + + uploadTextureFromContent(options.textureMapper, options.visibleRect); + if (m_state.replicaLayer && !options.isSurface) + options.textureMapper->drawTexture(*m_texture.get(), replicaRect(), m_transforms.replica, + opacity * m_state.replicaLayer->m_state.opacity, + replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get()); + + const IntRect rect = m_layerType == ClipLayer ? entireRect() : targetRect(); + const TransformationMatrix transform = m_layerType == ClipLayer ? TransformationMatrix() : m_transforms.target; + options.textureMapper->drawTexture(*m_texture.get(), rect, transform, opacity, options.isSurface ? 0 : maskTexture.get()); +} + +void TextureMapperNode::paintRecursive(TexmapPaintOptions options) +{ + WTF::StopWatch stopWatch; + + bool isDirty = m_state.dirty; + m_state.dirty = false; + + if ((m_size.isEmpty() && (m_state.masksToBounds + || m_children.isEmpty())) || !m_state.visible || options.opacity < 0.01 || m_state.opacity < 0.01) + return; + + initializeTextureMapper(options.textureMapper); + computeReplicaTransform(); + + if (m_state.maskLayer) { + m_state.maskLayer->initializeTextureMapper(options.textureMapper); + m_state.maskLayer->m_state.dirty = false; + } + + if (m_state.replicaLayer) { + m_state.replicaLayer->initializeTextureMapper(options.textureMapper); + m_state.replicaLayer->m_state.dirty = false; + if (m_state.replicaLayer->m_state.maskLayer) { + m_state.replicaLayer->m_state.maskLayer->initializeTextureMapper(options.textureMapper); + m_state.replicaLayer->m_state.maskLayer->m_state.dirty = false; + } + } + + TextureMapperNode* replica = m_state.replicaLayer; + const bool isSurface = (m_layerType == ClipLayer + || m_layerType == TransparencyLayer + || (m_layerType == RootLayer + && (options.textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants) + )); + if (isSurface) + uploadTextureFromContent(options.textureMapper, options.visibleRect); + const IntRect boundingRectfromNearestSurface = m_transforms.targetBoundingRect; + + options.opacity *= m_state.opacity; + + TexmapPaintOptions optionsForDescendants(options); + optionsForDescendants.opacity = isSurface ? 1 : options.opacity; + options.isSurface = isSurface; + + if (m_layerType == ClipLayer) { + optionsForDescendants.visibleRect = TransformationMatrix().translate(-boundingRectfromNearestSurface.x(), -boundingRectfromNearestSurface.y()).mapRect(options.visibleRect); + optionsForDescendants.scissorRect = IntRect(0, 0, m_size.width(), m_size.height()); + } + + if (m_layerType == ScissorLayer) + optionsForDescendants.scissorRect.intersect(m_transforms.targetBoundingRect); + options.textureMapper->setClip(optionsForDescendants.scissorRect); + + TextureMapperCacheLock(m_texture.get()); + TextureMapperCacheLock(m_surface.get()); + TextureMapperCacheLock(m_replicaSurface.get()); + + gTextureMapperCache.purge(); + + if (isSurface) { + ASSERT(m_surface); + if (!m_surface->isValid()) + isDirty = true; + if (m_state.tiled) { + m_surface->reset(options.visibleRect.size()); + m_surface->setOffset(options.visibleRect.location()); + } else if (isDirty) + m_surface->reset(m_layerType == TransparencyLayer ? options.surface->size() : m_size); + gTextureMapperCache.mark(m_surface.get()); + options.textureMapper->bindSurface(m_surface.get()); + + optionsForDescendants.surface = m_surface.get(); + } else if (m_surface) + m_surface->destroy(); + + RefPtr<BitmapTexture> maskTexture; + RefPtr<BitmapTexture> replicaMaskTexture; + if (TextureMapperNode* mask = m_state.maskLayer) { + mask->uploadTextureFromContent(options.textureMapper, options.visibleRect); + maskTexture = mask->m_texture; + } + + if (replica && replica->m_state.maskLayer) { + replica->m_state.maskLayer->uploadTextureFromContent(options.textureMapper, options.visibleRect); + replicaMaskTexture = replica->m_state.maskLayer->m_texture; + } + + int childrenSize = m_children.size(); + if (isDirty || !isSurface || m_state.tiled || !m_surface->isValid()) { + bool didPaintSelf = false; + if (!m_state.preserves3D || m_children.isEmpty()) { + paintSelf(options); + didPaintSelf = true; + } + + if (m_children.isEmpty() && !isSurface) + return; + + if (m_layerType == ScissorLayer) + optionsForDescendants.scissorRect.intersect(m_transforms.target.mapRect(IntRect(0, 0, m_size.width(), m_size.height()))); + + for (int i = 0; i < childrenSize; ++i) { + TextureMapperNode* layer = m_children[i]; + if (!layer) + continue; + + if (!didPaintSelf && layer->m_transforms.centerZ >= 0) { + paintSelf(options); + didPaintSelf = true; + } + layer->paintRecursive(optionsForDescendants); + if (isSurface) { + ASSERT(m_surface); + gTextureMapperCache.mark(m_surface.get()); + options.textureMapper->bindSurface(m_surface.get()); + } + } + if (!didPaintSelf) { + paintSelf(options); + didPaintSelf = true; + } + } + + if (m_layerType == RootLayer || m_layerType == DefaultLayer || m_layerType == ScissorLayer) + return; + + ASSERT(m_surface); + BitmapTexture& texture = *m_surface.get(); + if (replica) { + ASSERT(m_replicaSurface); + m_replicaSurface->reset(options.surface->size()); + m_replicaSurface->setOffset(options.surface->offset()); + gTextureMapperCache.mark(m_replicaSurface.get()); + options.textureMapper->bindSurface(m_replicaSurface.get()); + options.textureMapper->drawTexture(texture, replicaRect(), m_transforms.replica, replica->m_state.opacity, replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get()); + options.textureMapper->drawTexture(texture, IntRect(IntPoint(0, 0), options.surface->size()), TransformationMatrix(), 1.0f, maskTexture.get()); + options.textureMapper->bindSurface(options.surface); + gTextureMapperCache.mark(options.surface); + options.textureMapper->drawTexture(*m_replicaSurface.get(), IntRect(IntPoint(0, 0), options.surface->size()), TransformationMatrix(), options.opacity, 0); + return; + } + + options.textureMapper->bindSurface(options.surface); + options.textureMapper->drawTexture(texture, + m_layerType == TransparencyLayer ? IntRect(IntPoint(0, 0), options.surface->size()) : + targetRect(), + m_layerType == TransparencyLayer ? TransformationMatrix() : m_transforms.target, + options.opacity, maskTexture.get()); + gTextureMapperCache.mark(&texture); +} + +void TextureMapperNode::cleanupTextureMapper() +{ + if (m_texture) + m_texture->destroy(); + if (m_surface) + m_surface->destroy(); + if (m_replicaSurface) + m_replicaSurface->destroy(); + for (int i = 0; i < m_children.size(); ++i) { + if (m_children[i]) + m_children[i]->cleanupTextureMapper(); + } + if (m_lastTextureMapper) + m_lastTextureMapper->cleanup(); +} + +TextureMapperNode::~TextureMapperNode() +{ + setNeedsDisplay(); + { + const int childrenSize = m_children.size(); + for (int i = childrenSize-1; i >= 0; --i) { + ASSERT(m_children[i]->m_parent == this); + m_children[i]->m_parent = 0; + } + } + if (m_parent) + m_parent->m_children.remove(m_parent->m_children.find(this)); +} + +void TextureMapperNode::notifyChange(ChangeMask changeMask) +{ + m_changeMask |= changeMask; + if (!m_layer->client()) + return; + m_layer->client()->notifySyncRequired(m_layer); +} + +void TextureMapperNode::performPostSyncOperations() +{ + const LayerType prevLayerType = m_layerType; + computeLayerType(); + if (prevLayerType != m_layerType) + m_state.dirty = true; + if (m_transforms.dirty) + setNeedsDisplay(); + + computeTransformations(); + if (m_state.maskLayer && !m_state.dirty) + m_state.dirty = m_state.maskLayer->m_state.dirty; + if (m_state.replicaLayer && !m_state.dirty) + m_state.dirty = m_state.replicaLayer->m_state.dirty; + + const int size = m_children.size(); + + for (int i = size - 1; i >= 0; --i) { + TextureMapperNode* layer = m_children[i]; + + layer->performPostSyncOperations(); + if (!m_state.dirty) + m_state.dirty = layer->m_state.dirty; + } + m_state.hasSurfaceDescendants = hasSurfaceDescendants(); + if (m_state.dirty) + m_state.descendantsWithContent = countDescendantsWithContent(); + + if (m_state.preserves3D) + sortByZOrder(m_children, 0, size); + if (m_state.dirty) + setNeedsDisplay(); +} + +void TextureMapperNode::syncCompositingState(bool recurse) +{ + bool needsToInvalidateTransform = false; + + if (!m_layer) + return; + + if (m_changeMask == NoChanges) + goto afterCurrentLayerSync; + + setNeedsDisplay(); + if (m_parent) + m_parent->m_state.dirty = true; + + if (m_currentContent.contentType == HTMLContentType && (m_changeMask & ParentChange)) { + // The WebCore compositor manages item ownership. We have to make sure graphicsview doesn't + // try to snatch that ownership. + + if (!m_layer->parent()) + m_parent = 0; + else + m_parent = toTextureMapperNode(m_layer->parent()); + + if (!m_layer->parent() && m_parent) { + size_t index = m_parent->m_children.find(this); + m_parent->m_children.remove(index); + } + + } + + if (m_changeMask & ChildrenChange) { + m_children.clear(); + for (size_t i = 0; i < m_layer->children().size(); ++i) { + if (TextureMapperNode* child = toTextureMapperNode(m_layer->children()[i])) { + if (!child) + continue; + m_children.append(child); + child->m_parent = this; + } + } + m_state.dirty = true; + } + + if (m_changeMask & (SizeChange | ContentsRectChange)) { + IntSize wantedSize = IntSize(m_layer->size().width(), m_layer->size().height()); + if (wantedSize.isEmpty() && m_pendingContent.contentType == HTMLContentType) + wantedSize = IntSize(m_layer->contentsRect().width(), m_layer->contentsRect().height()); + + if (wantedSize != m_size) { + m_size = IntSize(wantedSize.width(), wantedSize.height()); + if (m_platformClient) + m_platformClient->setSizeChanged(m_size); + const bool needsTiling = m_size.width() > 2000 || m_size.height() > 2000; + if (m_state.tiled != needsTiling) + m_state.tiled = needsTiling; + m_state.dirty = true; + } + } + + if (m_changeMask & MaskLayerChange) { + if (TextureMapperNode* layer = toTextureMapperNode(m_layer->maskLayer())) + layer->m_effectTarget = this; + } + + if (m_changeMask & ReplicaLayerChange) { + if (TextureMapperNode* layer = toTextureMapperNode(m_layer->replicaLayer())) + layer->m_effectTarget = this; + } + + if (m_changeMask & (TransformChange | SizeChange | AnchorPointChange | PositionChange)) + m_transforms.localDirty = true; + + if (m_changeMask & (ChildrenTransformChange | SizeChange)) + m_transforms.perspectiveDirty = true; + + if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | ContentsRectChange | BackfaceVisibilityChange | PositionChange | MaskLayerChange | DrawsContentChange | ContentChange | ReplicaLayerChange)) { + // Due to the differences between the way WebCore handles transforms and the way Qt handles transforms, + // all these elements affect the transforms of all the descendants. + needsToInvalidateTransform = true; + } + + if (m_changeMask & DisplayChange) + m_state.dirty = true; + + m_state.maskLayer = toTextureMapperNode(m_layer->maskLayer()); + m_state.replicaLayer = toTextureMapperNode(m_layer->replicaLayer()); + m_state.pos = m_layer->position(); + m_state.anchorPoint = m_layer->anchorPoint(); + m_state.size = m_layer->size(); + m_state.transform = m_layer->transform(); + m_state.contentsRect = m_layer->contentsRect(); + m_state.opacity = m_layer->opacity(); + m_state.contentsRect = m_layer->contentsRect(); + m_state.preserves3D = m_layer->preserves3D(); + m_state.masksToBounds = m_layer->masksToBounds(); + m_state.drawsContent = m_layer->drawsContent(); + m_state.contentsOpaque = m_layer->contentsOpaque(); + m_state.backfaceVisibility = m_layer->backfaceVisibility(); + m_state.childrenTransform = m_layer->childrenTransform(); + m_currentContent.contentType = m_pendingContent.contentType; + m_currentContent.image = m_pendingContent.image; + m_currentContent.media = m_pendingContent.media; + m_currentContent.backgroundColor = m_pendingContent.backgroundColor; + m_currentContent.needsDisplay = m_currentContent.needsDisplay || m_pendingContent.needsDisplay; + m_currentContent.needsDisplayRect.unite(m_pendingContent.needsDisplayRect); + m_pendingContent.needsDisplay = false; + m_pendingContent.needsDisplayRect = IntRect(); + m_changeMask = NoChanges; + afterCurrentLayerSync: + if (needsToInvalidateTransform) + invalidateTransform(); + + if (m_state.maskLayer) { + m_state.maskLayer->syncCompositingState(false); + if (m_state.maskLayer->m_size.isEmpty()) + m_state.maskLayer->m_size = m_size; + } + + if (m_state.replicaLayer) + m_state.replicaLayer->syncCompositingState(false); + +#if 0 + if (m_state.dirty && m_texture && m_texture->allowOfflineTextureUpload()) + uploadTextureFromContent(0); +#endif + + if (!recurse) + return; + + const int childrenSize = m_children.size(); + for (int i = childrenSize-1; i >= 0; --i) + m_children[i]->syncCompositingState(true); +} + +GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(GraphicsLayerClient* client) + : GraphicsLayer(client) + , m_node(new TextureMapperNode(this)) +{ +} + +void GraphicsLayerTextureMapper::setName(const String& name) +{ + m_node->m_name = name; +} + +GraphicsLayerTextureMapper::~GraphicsLayerTextureMapper() +{ +} + +/* \reimp (GraphicsLayer.h): The current size might change, thus we need to update the whole display. +*/ +void GraphicsLayerTextureMapper::setNeedsDisplay() +{ + m_node->m_pendingContent.needsDisplay = true; + m_node->notifyChange(TextureMapperNode::DisplayChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (m_node->m_pendingContent.needsDisplay) + return; + m_node->m_pendingContent.needsDisplayRect.unite(IntRect(rect)); + m_node->notifyChange(TextureMapperNode::DisplayChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setParent(GraphicsLayer* layer) +{ + m_node->notifyChange(TextureMapperNode::ParentChange); + GraphicsLayer::setParent(layer); +} + +/* \reimp (GraphicsLayer.h) +*/ +bool GraphicsLayerTextureMapper::setChildren(const Vector<GraphicsLayer*>& children) +{ + m_node->notifyChange(TextureMapperNode::ChildrenChange); + return GraphicsLayer::setChildren(children); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChild(GraphicsLayer* layer) +{ + m_node->notifyChange(TextureMapperNode::ChildrenChange); + GraphicsLayer::addChild(layer); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChildAtIndex(GraphicsLayer* layer, int index) +{ + GraphicsLayer::addChildAtIndex(layer, index); + m_node->notifyChange(TextureMapperNode::ChildrenChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildAbove(layer, sibling); + m_node->notifyChange(TextureMapperNode::ChildrenChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + + GraphicsLayer::addChildBelow(layer, sibling); + m_node->notifyChange(TextureMapperNode::ChildrenChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + if (GraphicsLayer::replaceChild(oldChild, newChild)) { + m_node->notifyChange(TextureMapperNode::ChildrenChange); + return true; + } + + return false; +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::removeFromParent() +{ + if (!parent()) + return; + m_node->notifyChange(TextureMapperNode::ParentChange); + GraphicsLayer::removeFromParent(); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setMaskLayer(GraphicsLayer* value) +{ + if (value == maskLayer()) + return; + GraphicsLayer::setMaskLayer(value); + m_node->notifyChange(TextureMapperNode::MaskLayerChange); +} + + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setReplicatedByLayer(GraphicsLayer* value) +{ + if (value == replicaLayer()) + return; + GraphicsLayer::setReplicatedByLayer(value); + m_node->notifyChange(TextureMapperNode::ReplicaLayerChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setPosition(const FloatPoint& value) +{ + if (value == position()) + return; + GraphicsLayer::setPosition(value); + m_node->notifyChange(TextureMapperNode::PositionChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setAnchorPoint(const FloatPoint3D& value) +{ + if (value == anchorPoint()) + return; + GraphicsLayer::setAnchorPoint(value); + m_node->notifyChange(TextureMapperNode::AnchorPointChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setSize(const FloatSize& value) +{ + if (value == size()) + return; + + GraphicsLayer::setSize(value); + m_node->notifyChange(TextureMapperNode::SizeChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setTransform(const TransformationMatrix& value) +{ + if (value == transform()) + return; + + GraphicsLayer::setTransform(value); + m_node->notifyChange(TextureMapperNode::TransformChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setChildrenTransform(const TransformationMatrix& value) +{ + if (value == childrenTransform()) + return; + GraphicsLayer::setChildrenTransform(value); + m_node->notifyChange(TextureMapperNode::ChildrenTransformChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setPreserves3D(bool value) +{ + if (value == preserves3D()) + return; + GraphicsLayer::setPreserves3D(value); + m_node->notifyChange(TextureMapperNode::Preserves3DChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setMasksToBounds(bool value) +{ + if (value == masksToBounds()) + return; + GraphicsLayer::setMasksToBounds(value); + m_node->notifyChange(TextureMapperNode::MasksToBoundsChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setDrawsContent(bool value) +{ + if (value == drawsContent()) + return; + m_node->notifyChange(TextureMapperNode::DrawsContentChange); + GraphicsLayer::setDrawsContent(value); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setBackgroundColor(const Color& value) +{ + if (value == m_node->m_pendingContent.backgroundColor) + return; + m_node->m_pendingContent.backgroundColor = value; + GraphicsLayer::setBackgroundColor(value); + m_node->notifyChange(TextureMapperNode::BackgroundColorChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::clearBackgroundColor() +{ + if (!m_node->m_pendingContent.backgroundColor.isValid()) + return; + m_node->m_pendingContent.backgroundColor = Color(); + GraphicsLayer::clearBackgroundColor(); + m_node->notifyChange(TextureMapperNode::BackgroundColorChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsOpaque(bool value) +{ + if (value == contentsOpaque()) + return; + m_node->notifyChange(TextureMapperNode::ContentsOpaqueChange); + GraphicsLayer::setContentsOpaque(value); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setBackfaceVisibility(bool value) +{ + if (value == backfaceVisibility()) + return; + GraphicsLayer::setBackfaceVisibility(value); + m_node->notifyChange(TextureMapperNode::BackfaceVisibilityChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setOpacity(float value) +{ + if (value == opacity()) + return; + GraphicsLayer::setOpacity(value); + m_node->notifyChange(TextureMapperNode::OpacityChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsRect(const IntRect& value) +{ + if (value == contentsRect()) + return; + GraphicsLayer::setContentsRect(value); + m_node->notifyChange(TextureMapperNode::ContentsRectChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsToImage(Image* image) +{ + m_node->notifyChange(TextureMapperNode::ContentChange); + m_node->m_pendingContent.contentType = image ? TextureMapperNode::DirectImageContentType : TextureMapperNode::HTMLContentType; + m_node->m_pendingContent.image = image; + GraphicsLayer::setContentsToImage(image); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsBackgroundColor(const Color& color) +{ + m_node->notifyChange(TextureMapperNode::ContentChange); + m_node->m_pendingContent.contentType = TextureMapperNode::ColorContentType; + m_node->m_pendingContent.backgroundColor = color; + GraphicsLayer::setContentsBackgroundColor(color); +} + + +void GraphicsLayerTextureMapper::setContentsToMedia(PlatformLayer* media) +{ + GraphicsLayer::setContentsToMedia(media); + m_node->notifyChange(TextureMapperNode::ContentChange); + m_node->m_pendingContent.contentType = media ? TextureMapperNode::MediaContentType : TextureMapperNode::HTMLContentType; + if (media) + m_node->m_pendingContent.media = static_cast<TextureMapperVideoLayer*>(media); + else + m_node->m_pendingContent.media = 0; +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsOrientation(CompositingCoordinatesOrientation orientation) +{ + if (contentsOrientation() == orientation) + return; + m_node->notifyChange(TextureMapperNode::ContentsOrientationChange); + GraphicsLayer::setContentsOrientation(orientation); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::syncCompositingStateForThisLayerOnly() +{ + m_node->syncCompositingState(false); + m_node->performPostSyncOperations(); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::syncCompositingState() +{ + GraphicsLayer::syncCompositingState(); + m_node->syncCompositingState(true); + m_node->performPostSyncOperations(); +} + +/* \reimp (GraphicsLayer.h) + */ +NativeLayer GraphicsLayerTextureMapper::nativeLayer() const +{ + return m_node.get(); +} + +/* \reimp (GraphicsLayer.h) +*/ +PlatformLayer* GraphicsLayerTextureMapper::platformLayer() const +{ + return m_node.get(); +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerTextureMapper(client); +} + +} diff --git a/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h new file mode 100644 index 0000000..36ebd74 --- /dev/null +++ b/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef GraphicsLayerTextureMapper_h +#define GraphicsLayerTextureMapper_h + +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerClient.h" +#include "Image.h" + +#if ENABLE(3D_CANVAS) +#include "GraphicsContext3D.h" +#endif + +#define ENABLE_TEXMAP_ANIMATION 0 + +namespace WebCore { + +class TextureMapperNode; +class BitmapTexture; +class TextureMapper; + +class GraphicsLayerTextureMapper : public GraphicsLayer { + friend class TextureMapperNode; + +public: + GraphicsLayerTextureMapper(GraphicsLayerClient*); + virtual ~GraphicsLayerTextureMapper(); + + // reimps from GraphicsLayer.h + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + virtual void setParent(GraphicsLayer* layer); + virtual bool setChildren(const Vector<GraphicsLayer*>&); + virtual void addChild(GraphicsLayer*); + virtual void addChildAtIndex(GraphicsLayer*, 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 setMaskLayer(GraphicsLayer* layer); + virtual void setPosition(const FloatPoint& p); + virtual void setAnchorPoint(const FloatPoint3D& p); + virtual void setSize(const FloatSize& size); + virtual void setTransform(const TransformationMatrix& t); + virtual void setChildrenTransform(const TransformationMatrix& t); + virtual void setPreserves3D(bool b); + virtual void setMasksToBounds(bool b); + virtual void setDrawsContent(bool b); + virtual void setBackgroundColor(const Color&); + virtual void clearBackgroundColor(); + virtual void setContentsOpaque(bool b); + virtual void setBackfaceVisibility(bool b); + virtual void setOpacity(float opacity); + virtual void setContentsRect(const IntRect& r); + virtual void setReplicatedByLayer(GraphicsLayer*); + virtual void setContentsToImage(Image*); + virtual void setContentsToMedia(PlatformLayer*); + virtual void setContentsBackgroundColor(const Color&); +#if ENABLE(3D_CANVAS) + virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); + virtual void setGraphicsContext3DNeedsDisplay(); +#endif + virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation); + virtual void syncCompositingState(); + virtual void syncCompositingStateForThisLayerOnly(); + virtual void setName(const String& name); + virtual NativeLayer nativeLayer() const; + virtual PlatformLayer* platformLayer() const; + + virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, + const String& /*keyframesName*/, double /*timeOffset*/) { return false; } + +private: + OwnPtr<TextureMapperNode> m_node; +}; + +} +#endif // GraphicsLayerTextureMapper_h diff --git a/WebCore/platform/graphics/texmap/TextureMapper.h b/WebCore/platform/graphics/texmap/TextureMapper.h new file mode 100644 index 0000000..03c1c6d --- /dev/null +++ b/WebCore/platform/graphics/texmap/TextureMapper.h @@ -0,0 +1,120 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +#ifndef TextureMapper_h +#define TextureMapper_h + +#if USE(ACCELERATED_COMPOSITING) +#if (defined(QT_OPENGL_LIB)) + #if defined(QT_OPENGL_ES_2) && !defined(TEXMAP_OPENGL_ES_2) + #define TEXMAP_OPENGL_ES_2 + #endif +#endif + +#include "GraphicsContext.h" +#include "IntRect.h" +#include "IntSize.h" +#include "TransformationMatrix.h" + +/* + TextureMapper is a mechanism that enables hardware acceleration of CSS animations (accelerated compositing) without + a need for a platform specific scene-graph library like CoreAnimations or QGraphicsView. +*/ + +namespace WebCore { + +class TextureMapper; + +// A 2D texture that can be the target of software or GL rendering. +class BitmapTexture : public RefCounted<BitmapTexture> { +public: + BitmapTexture() : m_lockCount(0) {} + virtual ~BitmapTexture() { } + + virtual bool allowOfflineTextureUpload() const { return false; } + virtual void destroy() = 0; + virtual IntSize size() const = 0; + virtual bool isValid() const = 0; + virtual void reset(const IntSize& size, bool opaque = false) + { + m_isOpaque = opaque; + m_contentSize = size; + } + + virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect) = 0; + virtual void endPaint() = 0; + virtual PlatformGraphicsContext* beginPaintMedia() + { + return beginPaint(IntRect(0, 0, size().width(), size().height())); + } + virtual void setContentsToImage(Image*) = 0; + virtual bool save(const String& filename) { return false; } + + inline void lock() { ++m_lockCount; } + inline void unlock() { --m_lockCount; } + inline bool isLocked() { return m_lockCount; } + inline IntSize contentSize() const { return m_contentSize; } + inline void setOffset(const IntPoint& o) { m_offset = o; } + inline IntPoint offset() const { return m_offset; } +private: + int m_lockCount; + IntSize m_contentSize; + bool m_isOpaque; + IntPoint m_offset; +}; + +// A "context" class used to encapsulate accelerated texture mapping functions: i.e. drawing a texture +// onto the screen or into another texture with a specified transform, opacity and mask. +class TextureMapper : public RefCounted<TextureMapper> { + friend class BitmapTexture; + +public: + static PassRefPtr<TextureMapper> create(GraphicsContext*); + virtual ~TextureMapper() { } + + virtual void drawTexture(const BitmapTexture& texture, const IntRect& target, const TransformationMatrix& matrix = TransformationMatrix(), float opacity = 1.0f, const BitmapTexture* maskTexture = 0) = 0; + + // makes a surface the target for the following drawTexture calls. + virtual void bindSurface(BitmapTexture* surface) = 0; + virtual void paintToTarget(const BitmapTexture& texture, const IntSize&, const TransformationMatrix& matrix, float opacity, const IntRect& visibleRect) + { + drawTexture(texture, IntRect(0, 0, texture.contentSize().width(), texture.contentSize().height()), matrix, opacity, 0); + } + + virtual void setClip(const IntRect&) = 0; + virtual bool allowSurfaceForRoot() const = 0; + virtual PassRefPtr<BitmapTexture> createTexture() = 0; + virtual const char* type() const = 0; + virtual void cleanup() {} + + GraphicsContext* graphicsContext() const + { + return m_gc; + } + +protected: + TextureMapper(GraphicsContext* gc) : m_gc(gc) {} + GraphicsContext* m_gc; +}; + +}; + +#endif + +#endif diff --git a/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h b/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h new file mode 100644 index 0000000..23e9fc9 --- /dev/null +++ b/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef TextureMapperPlatformLayer_h +#define TextureMapperPlatformLayer_h + +namespace WebCore { + +class GraphicsContext; +class IntRect; +class IntSize; +class TransformationMatrix; + + +// Glue layer to connect the texmap layer to the platform specific container. +class TextureMapperLayerClient { +public: + virtual ~TextureMapperLayerClient() {} + virtual void setNeedsDisplay() = 0; + virtual void setNeedsDisplayInRect(const IntRect& rect) = 0; + virtual void setSizeChanged(const IntSize&) = 0; +}; + +class TextureMapperPlatformLayer { +public: + enum Type { + ContentLayer, + VideoLayer + }; + + virtual Type layerType() const = 0; + virtual ~TextureMapperPlatformLayer() {} +}; + +class TextureMapperContentLayer : public TextureMapperPlatformLayer { +public: + virtual void setPlatformLayerClient(TextureMapperLayerClient*) = 0; + virtual void paint(GraphicsContext*, const IntSize&, const IntRect& targetRect, const IntRect& exposedRect, const TransformationMatrix& transform, float opacity) {} + virtual IntSize size() const = 0; + virtual void cleanupTextureMapper() {} + virtual Type layerType() const { return ContentLayer; } +}; + +#if ENABLE(VIDEO) +class TextureMapperVideoLayer : public TextureMapperPlatformLayer { +public: + virtual void paint(GraphicsContext*) = 0; + virtual Type layerType() const { return VideoLayer; } +}; +#endif + +} + +#endif // TextureMapperPlatformLayer_h diff --git a/WebCore/platform/graphics/transforms/AffineTransform.cpp b/WebCore/platform/graphics/transforms/AffineTransform.cpp index be18e07..f275526 100644 --- a/WebCore/platform/graphics/transforms/AffineTransform.cpp +++ b/WebCore/platform/graphics/transforms/AffineTransform.cpp @@ -41,8 +41,8 @@ static void affineTransformDecompose(const AffineTransform& matrix, double sr[9] AffineTransform m(matrix); // Compute scaling factors - double sx = sqrt(m.a() * m.a() + m.b() * m.b()); - double sy = sqrt(m.c() * m.c() + m.d() * m.d()); + double sx = matrix.xScale(); + double sy = matrix.yScale(); // Compute cross product of transformed unit vectors. If negative, // one axis was flipped. @@ -119,6 +119,16 @@ bool AffineTransform::isIdentity() const && m_transform[4] == 0 && m_transform[5] == 0); } +double AffineTransform::xScale() const +{ + return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]); +} + +double AffineTransform::yScale() const +{ + return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]); +} + double AffineTransform::det() const { return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2]; diff --git a/WebCore/platform/graphics/transforms/AffineTransform.h b/WebCore/platform/graphics/transforms/AffineTransform.h index 289ec54..baee102 100644 --- a/WebCore/platform/graphics/transforms/AffineTransform.h +++ b/WebCore/platform/graphics/transforms/AffineTransform.h @@ -110,7 +110,10 @@ public: AffineTransform& skew(double angleX, double angleY); AffineTransform& skewX(double angle); AffineTransform& skewY(double angle); - + + double xScale() const; + double yScale() const; + double det() const; bool isInvertible() const; AffineTransform inverse() const; diff --git a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h index 7430dbc..0a0aaf0 100644 --- a/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h +++ b/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h @@ -37,6 +37,8 @@ public: return adoptRef(new Matrix3DTransformOperation(matrix)); } + TransformationMatrix matrix() const {return m_matrix; } + private: virtual bool isIdentity() const { return m_matrix.isIdentity(); } diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h index ee47a11..fd9b27e 100644 --- a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h +++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h @@ -42,6 +42,8 @@ public: return adoptRef(new MatrixTransformOperation(t)); } + TransformationMatrix matrix() const { return TransformationMatrix(m_a, m_b, m_c, m_d, m_e, m_f); } + private: virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; } diff --git a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h index a665f3e..834cc83 100644 --- a/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h +++ b/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h @@ -36,6 +36,8 @@ public: { return adoptRef(new PerspectiveTransformOperation(p)); } + + double perspective() const { return m_p; } private: virtual bool isIdentity() const { return m_p == 0; } diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/WebCore/platform/graphics/transforms/RotateTransformOperation.h index 699ea43..2acb002 100644 --- a/WebCore/platform/graphics/transforms/RotateTransformOperation.h +++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.h @@ -41,6 +41,9 @@ public: return adoptRef(new RotateTransformOperation(x, y, z, angle, type)); } + double x() const { return m_x; } + double y() const { return m_y; } + double z() const { return m_z; } double angle() const { return m_angle; } private: diff --git a/WebCore/platform/graphics/transforms/SkewTransformOperation.h b/WebCore/platform/graphics/transforms/SkewTransformOperation.h index 6343710..afe9a7b 100644 --- a/WebCore/platform/graphics/transforms/SkewTransformOperation.h +++ b/WebCore/platform/graphics/transforms/SkewTransformOperation.h @@ -36,6 +36,9 @@ public: return adoptRef(new SkewTransformOperation(angleX, angleY, type)); } + double angleX() const { return m_angleX; } + double angleY() const { return m_angleY; } + private: virtual bool isIdentity() const { return m_angleX == 0 && m_angleY == 0; } virtual OperationType getOperationType() const { return m_type; } diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h index a66cc3d..ea48d49 100644 --- a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h +++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h @@ -46,6 +46,10 @@ public: double y(const IntSize& borderBoxSize) const { return m_y.calcFloatValue(borderBoxSize.height()); } double z(const IntSize&) const { return m_z.calcFloatValue(1); } + Length x() const { return m_x; } + Length y() const { return m_y; } + Length z() const { return m_z; } + private: virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0 && m_z.calcFloatValue(1) == 0; } diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index c6437f2..2f1fb41 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -360,14 +360,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, DeviceColorSpace); + graphicsContext->setFillColor(shadowFillColor, ColorSpaceDeviceRGB); CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width(), point.y() + translation.height() + shadowOffset.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowOffset.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowOffset.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } - graphicsContext->setFillColor(fillColor, DeviceColorSpace); + graphicsContext->setFillColor(fillColor, ColorSpaceDeviceRGB); } CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); @@ -378,7 +378,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo } if (hasSimpleShadow) - graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, DeviceColorSpace); + graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, ColorSpaceDeviceRGB); wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); } diff --git a/WebCore/platform/graphics/win/GDIExtras.cpp b/WebCore/platform/graphics/win/GDIExtras.cpp new file mode 100644 index 0000000..4bd95da --- /dev/null +++ b/WebCore/platform/graphics/win/GDIExtras.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GDIExtras.h" + +#include "SoftLinking.h" + +namespace WebCore { + +#if OS(WINCE) +SOFT_LINK_LIBRARY(coredll) +SOFT_LINK_OPTIONAL(coredll, AlphaBlend, BOOL, APIENTRY, (HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, + int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction)) + +AlphaBlendPointerType AlphaBlendPointer() +{ + return AlphaBlendPtr(); +} +#endif + +} // namespace WebCore diff --git a/WebCore/platform/graphics/win/GDIExtras.h b/WebCore/platform/graphics/win/GDIExtras.h new file mode 100644 index 0000000..0166124 --- /dev/null +++ b/WebCore/platform/graphics/win/GDIExtras.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GDIExtras_h +#define GDIExtras_h + +#include <windows.h> + +namespace WebCore { + +typedef BOOL (APIENTRY *AlphaBlendPointerType) (HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, + int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction); + +#if OS(WINCE) +AlphaBlendPointerType AlphaBlendPointer(); +#endif + +inline bool hasAlphaBlendSupport() +{ +#if OS(WINCE) + return AlphaBlendPointer(); +#else + return true; +#endif +} + +inline bool alphaBlendIfSupported(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, HDC hdcSrc, + int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction) +{ +#if OS(WINCE) + AlphaBlendPointerType alphaBlendPointer = AlphaBlendPointer(); + if (!alphaBlendPointer) + return false; + + alphaBlendPointer(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, blendFunction); +#else + AlphaBlend(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, blendFunction); +#endif + return true; +} + +} // namespace WebCore + +#endif // GDIExtras_h diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 0203d42..c9288e5 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -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(), DeviceColorSpace); - setPlatformStrokeColor(strokeColor(), DeviceColorSpace); + setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB); + setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB); } } @@ -129,6 +129,8 @@ void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int of // FIXME: implement } +// FIXME: This is nearly identical to the GraphicsContext::drawFocusRing function in GraphicsContextMac.mm. +// The code could move to GraphicsContextCG.cpp and be shared. void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) { if (paintingDisabled()) @@ -136,7 +138,7 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int float radius = (width - 1) / 2.0f; offset += radius; - CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0; + CGColorRef colorRef = color.isValid() ? cachedCGColor(color, ColorSpaceDeviceRGB) : 0; CGMutablePathRef focusRingPath = CGPathCreateMutable(); unsigned rectCount = rects.size(); @@ -151,8 +153,6 @@ void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int wkDrawFocusRing(context, colorRef, radius); - CGColorRelease(colorRef); - CGPathRelease(focusRingPath); CGContextRestoreGState(context); diff --git a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp index dad5da1..f7674db 100644 --- a/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp +++ b/WebCore/platform/graphics/win/GraphicsLayerCACF.cpp @@ -99,9 +99,7 @@ TransformationMatrix CAToTransform3D(const CATransform3D& fromT3D) static void setLayerBorderColor(WKCACFLayer* layer, const Color& color) { - CGColorRef borderColor = createCGColor(color); - layer->setBorderColor(borderColor); - CGColorRelease(borderColor); + layer->setBorderColor(cachedCGColor(color, ColorSpaceDeviceRGB)); } static void clearBorderColor(WKCACFLayer* layer) @@ -111,9 +109,7 @@ static void clearBorderColor(WKCACFLayer* layer) static void setLayerBackgroundColor(WKCACFLayer* layer, const Color& color) { - CGColorRef bgColor = createCGColor(color); - layer->setBackgroundColor(bgColor); - CGColorRelease(bgColor); + layer->setBackgroundColor(cachedCGColor(color, ColorSpaceDeviceRGB)); } static void clearLayerBackgroundColor(WKCACFLayer* layer) diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp index a0fbba7..e65b859 100644 --- a/WebCore/platform/graphics/win/ImageCGWin.cpp +++ b/WebCore/platform/graphics/win/ImageCGWin.cpp @@ -78,9 +78,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), DeviceColorSpace, CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy); // Do cleanup CGContextRelease(cgContext); diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index e3c5ea0..70b132e 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), DeviceColorSpace, CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy); else - draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); + draw(&gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy); // Do cleanup cairo_destroy(targetRef); @@ -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()), DeviceColorSpace, compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), ColorSpaceDeviceRGB, 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()), DeviceColorSpace, compositeOp); + draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, compositeOp); } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp index 4a7e45e..4a7e45e 100755..100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateFullscreenWindow.cpp diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp index 354e0bf..1b4f1d9 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.cpp @@ -42,7 +42,6 @@ #include "ScrollView.h" #include "Settings.h" #include "SoftLinking.h" -#include "StringBuilder.h" #include "TimeRanges.h" #include "Timer.h" #include <AssertMacros.h> @@ -53,6 +52,7 @@ #include <wtf/MainThread.h> #include <wtf/MathExtras.h> #include <wtf/StdLibExtras.h> +#include <wtf/text/StringBuilder.h> #include <wtf/text/StringHash.h> #if USE(ACCELERATED_COMPOSITING) @@ -174,6 +174,8 @@ MediaPlayerPrivateQuickTimeVisualContext::MediaPlayerPrivateQuickTimeVisualConte , m_movieTransform(CGAffineTransformIdentity) #endif , m_visualContextClient(new MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient(this)) + , m_delayingLoad(false) + , m_preload(MediaPlayer::Auto) { } @@ -241,7 +243,7 @@ static void addCookieParam(StringBuilder& cookieBuilder, const String& name, con // Add parameter name, and value if there is one. cookieBuilder.append(name); if (!value.isEmpty()) { - cookieBuilder.append("="); + cookieBuilder.append('='); cookieBuilder.append(value); } } @@ -275,7 +277,7 @@ void MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime(const St addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires)); if (cookie.httpOnly) addCookieParam(cookieBuilder, "httpOnly", String()); - cookieBuilder.append(";"); + cookieBuilder.append(';'); String cookieURL; if (!cookie.domain.isEmpty()) { @@ -316,8 +318,28 @@ static void disableComponentsOnce() QTMovie::disableComponent(componentsToDisable[i]); } +void MediaPlayerPrivateQuickTimeVisualContext::resumeLoad() +{ + m_delayingLoad = false; + + if (!m_movieURL.isEmpty()) + loadInternal(m_movieURL); +} + void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url) { + m_movieURL = url; + + if (m_preload == MediaPlayer::None) { + m_delayingLoad = true; + return; + } + + loadInternal(url); +} + +void MediaPlayerPrivateQuickTimeVisualContext::loadInternal(const String& url) +{ if (!QTMovie::initializeQuickTime()) { // FIXME: is this the right error to return? m_networkState = MediaPlayer::DecodeError; @@ -347,6 +369,12 @@ void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url) m_movie->setVolume(m_player->volume()); } +void MediaPlayerPrivateQuickTimeVisualContext::prepareToPlay() +{ + if (!m_movie || m_delayingLoad) + resumeLoad(); +} + void MediaPlayerPrivateQuickTimeVisualContext::play() { if (!m_movie) @@ -1005,6 +1033,13 @@ bool MediaPlayerPrivateQuickTimeVisualContext::hasSingleSecurityOrigin() const return true; } +void MediaPlayerPrivateQuickTimeVisualContext::setPreload(MediaPlayer::Preload preload) +{ + m_preload = preload; + if (m_delayingLoad && m_preload != MediaPlayer::None) + resumeLoad(); +} + MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::currentRenderingMode() const { if (!m_movie) diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h index 272b90f..4c62558 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeVisualContext.h @@ -74,9 +74,12 @@ private: void load(const String& url); void cancelLoad(); + void loadInternal(const String& url); + void resumeLoad(); void play(); void pause(); + void prepareToPlay(); bool paused() const; bool seeking() const; @@ -111,6 +114,8 @@ private: bool hasClosedCaptions() const; void setClosedCaptionsVisible(bool); + void setPreload(MediaPlayer::Preload); + void updateStates(); void doSeek(); void cancelSeek(); @@ -189,6 +194,9 @@ private: bool m_isStreaming; bool m_visible; bool m_newFrameAvailable; + bool m_delayingLoad; + String m_movieURL; + MediaPlayer::Preload m_preload; #if DRAW_FRAME_RATE double m_frameCountWhilePlaying; double m_timeStartedPlaying; diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index c37f5d5..39e8a11 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -38,7 +38,6 @@ #include "QTMovieTask.h" #include "ScrollView.h" #include "SoftLinking.h" -#include "StringBuilder.h" #include "TimeRanges.h" #include "Timer.h" #include <Wininet.h> @@ -46,6 +45,7 @@ #include <wtf/HashSet.h> #include <wtf/MathExtras.h> #include <wtf/StdLibExtras.h> +#include <wtf/text/StringBuilder.h> #include <wtf/text/StringHash.h> #if USE(ACCELERATED_COMPOSITING) @@ -159,7 +159,7 @@ static void addCookieParam(StringBuilder& cookieBuilder, const String& name, con // Add parameter name, and value if there is one. cookieBuilder.append(name); if (!value.isEmpty()) { - cookieBuilder.append("="); + cookieBuilder.append('='); cookieBuilder.append(value); } } @@ -194,7 +194,7 @@ void MediaPlayerPrivate::setUpCookiesForQuickTime(const String& url) addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires)); if (cookie.httpOnly) addCookieParam(cookieBuilder, "httpOnly", String()); - cookieBuilder.append(";"); + cookieBuilder.append(';'); String cookieURL; if (!cookie.domain.isEmpty()) { diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp index 1685a30..d75c854 100644 --- a/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.cpp @@ -29,8 +29,8 @@ #include "WKCACFContextFlusher.h" +#include <WebKitSystemInterface/WebKitSystemInterface.h> #include <wtf/StdLibExtras.h> -#include <QuartzCore/CACFContext.h> namespace WebCore { @@ -48,24 +48,18 @@ WKCACFContextFlusher::~WKCACFContextFlusher() { } -void WKCACFContextFlusher::addContext(CACFContextRef context) +void WKCACFContextFlusher::addContext(WKCACFContext* context) { ASSERT(context); - if (m_contexts.add(context).second) - CFRetain(context); + m_contexts.add(context); } -void WKCACFContextFlusher::removeContext(CACFContextRef context) +void WKCACFContextFlusher::removeContext(WKCACFContext* context) { ASSERT(context); - ContextSet::iterator found = m_contexts.find(context); - if (found == m_contexts.end()) - return; - - CFRelease(*found); - m_contexts.remove(found); + m_contexts.remove(context); } void WKCACFContextFlusher::flushAllContexts() @@ -76,11 +70,8 @@ void WKCACFContextFlusher::flushAllContexts() 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); - } + for (ContextSet::const_iterator it = contextsToFlush.begin(); it != end; ++it) + wkCACFContextFlush(*it); } } diff --git a/WebCore/platform/graphics/win/WKCACFContextFlusher.h b/WebCore/platform/graphics/win/WKCACFContextFlusher.h index 9ce76aa..17ec41d 100644 --- a/WebCore/platform/graphics/win/WKCACFContextFlusher.h +++ b/WebCore/platform/graphics/win/WKCACFContextFlusher.h @@ -32,7 +32,7 @@ #include <wtf/HashSet.h> -typedef struct _CACFContext* CACFContextRef; +struct WKCACFContext; namespace WebCore { @@ -40,8 +40,8 @@ class WKCACFContextFlusher : public Noncopyable { public: static WKCACFContextFlusher& shared(); - void addContext(CACFContextRef); - void removeContext(CACFContextRef); + void addContext(WKCACFContext*); + void removeContext(WKCACFContext*); void flushAllContexts(); @@ -49,7 +49,7 @@ private: WKCACFContextFlusher(); ~WKCACFContextFlusher(); - typedef HashSet<CACFContextRef> ContextSet; + typedef HashSet<WKCACFContext*> ContextSet; ContextSet m_contexts; }; diff --git a/WebCore/platform/graphics/win/WKCACFLayer.cpp b/WebCore/platform/graphics/win/WKCACFLayer.cpp index bf47925..a8714e3 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayer.cpp @@ -30,15 +30,10 @@ #include "WKCACFLayer.h" #include "WKCACFLayerRenderer.h" -#include <wtf/text/CString.h> - +#include <WebKitSystemInterface/WebKitSystemInterface.h> #include <stdio.h> -#include <QuartzCore/CACFContext.h> -#include <QuartzCore/CARender.h> - -#ifndef NDEBUG #include <wtf/CurrentTime.h> -#endif +#include <wtf/text/CString.h> namespace WebCore { @@ -190,9 +185,9 @@ WKCACFLayer::~WKCACFLayer() CACFLayerSetDisplayCallback(layer(), 0); } -void WKCACFLayer::becomeRootLayerForContext(CACFContextRef context) +void WKCACFLayer::becomeRootLayerForContext(WKCACFContext* context) { - CACFContextSetLayer(context, layer()); + wkCACFContextSetLayer(context, layer()); setNeedsCommit(); } diff --git a/WebCore/platform/graphics/win/WKCACFLayer.h b/WebCore/platform/graphics/win/WKCACFLayer.h index 7243508..4c6639a 100644 --- a/WebCore/platform/graphics/win/WKCACFLayer.h +++ b/WebCore/platform/graphics/win/WKCACFLayer.h @@ -41,6 +41,8 @@ #include "PlatformString.h" #include "TransformationMatrix.h" +struct WKCACFContext; + namespace WebCore { class WKCACFLayer; @@ -83,7 +85,7 @@ public: } // Makes this layer the root when the passed context is rendered - void becomeRootLayerForContext(CACFContextRef); + void becomeRootLayerForContext(WKCACFContext*); static RetainPtr<CFTypeRef> cfValue(float value) { return RetainPtr<CFTypeRef>(AdoptCF, CFNumberCreate(0, kCFNumberFloat32Type, &value)); } static RetainPtr<CFTypeRef> cfValue(const TransformationMatrix& value) diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp index 4f39b13..73cb794 100755..100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp @@ -36,9 +36,7 @@ #include "WKCACFContextFlusher.h" #include "WKCACFLayer.h" #include "WebCoreInstanceHandle.h" -#include <CoreGraphics/CGSRegion.h> -#include <QuartzCore/CACFContext.h> -#include <QuartzCore/CARenderOGL.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> #include <wtf/HashMap.h> #include <wtf/OwnArrayPtr.h> #include <wtf/OwnPtr.h> @@ -108,7 +106,7 @@ private: WKCACFLayerRenderer* m_renderer; }; -typedef HashMap<CACFContextRef, WKCACFLayerRenderer*> ContextToWindowMap; +typedef HashMap<WKCACFContext*, WKCACFLayerRenderer*> ContextToWindowMap; static ContextToWindowMap& windowsForContexts() { @@ -206,7 +204,7 @@ bool WKCACFLayerRenderer::acceleratedCompositingAvailable() return available; } -void WKCACFLayerRenderer::didFlushContext(CACFContextRef context) +void WKCACFLayerRenderer::didFlushContext(WKCACFContext* context) { WKCACFLayerRenderer* window = windowsForContexts().get(context); if (!window) @@ -226,15 +224,13 @@ WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client) : m_client(client) , m_mightBeAbleToCreateDeviceLater(true) , m_rootLayer(WKCACFRootLayer::create(this)) - , m_context(AdoptCF, CACFContextCreate(0)) - , m_renderContext(static_cast<CARenderContext*>(CACFContextGetRenderContext(m_context.get()))) - , m_renderer(0) + , m_context(wkCACFContextCreate()) , m_hostWindow(0) , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired) , m_backingStoreDirty(false) , m_mustResetLostDeviceBeforeRendering(false) { - windowsForContexts().set(m_context.get(), this); + windowsForContexts().set(m_context, this); // Under the root layer, we have a clipping layer to clip the content, // that contains a scroll layer that we use for scrolling the content. @@ -250,13 +246,13 @@ WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client) m_rootLayer->setGeometryFlipped(true); #ifndef NDEBUG - CGColorRef debugColor = createCGColor(Color(255, 0, 0, 204)); + CGColorRef debugColor = CGColorCreateGenericRGB(1, 0, 0, 0.8); m_rootLayer->setBackgroundColor(debugColor); CGColorRelease(debugColor); #endif if (m_context) - m_rootLayer->becomeRootLayerForContext(m_context.get()); + m_rootLayer->becomeRootLayerForContext(m_context); #ifndef NDEBUG char* printTreeFlag = getenv("CA_PRINT_TREE"); @@ -267,6 +263,7 @@ WKCACFLayerRenderer::WKCACFLayerRenderer(WKCACFLayerRendererClient* client) WKCACFLayerRenderer::~WKCACFLayerRenderer() { destroyRenderer(); + wkCACFContextDestroy(m_context); } WKCACFLayer* WKCACFLayerRenderer::rootLayer() const @@ -298,7 +295,7 @@ void WKCACFLayerRenderer::setRootChildLayer(WKCACFLayer* layer) void WKCACFLayerRenderer::layerTreeDidChange() { - WKCACFContextFlusher::shared().addContext(m_context.get()); + WKCACFContextFlusher::shared().addContext(m_context); renderSoon(); } @@ -373,7 +370,7 @@ bool WKCACFLayerRenderer::createRenderer() initD3DGeometry(); - m_renderer = CARenderOGLNew(&kCARenderDX9Callbacks, m_d3dDevice.get(), 0); + wkCACFContextInitializeD3DDevice(m_context, m_d3dDevice.get()); if (IsWindow(m_hostWindow)) m_rootLayer->setBounds(bounds()); @@ -384,14 +381,10 @@ bool WKCACFLayerRenderer::createRenderer() void WKCACFLayerRenderer::destroyRenderer() { if (m_context) { - CACFContextSetLayer(m_context.get(), 0); - windowsForContexts().remove(m_context.get()); - WKCACFContextFlusher::shared().removeContext(m_context.get()); + windowsForContexts().remove(m_context); + WKCACFContextFlusher::shared().removeContext(m_context); } - if (m_renderer) - CARenderOGLDestroy(m_renderer); - m_renderer = 0; m_d3dDevice = 0; if (s_d3d) s_d3d->Release(); @@ -476,7 +469,7 @@ void WKCACFLayerRenderer::paint() render(dirtyRects); } -void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) +void WKCACFLayerRenderer::render(const Vector<CGRect>& windowDirtyRects) { ASSERT(m_d3dDevice); @@ -499,31 +492,21 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) CFTimeInterval t = CACurrentMediaTime(); // Give the renderer some space to use. This needs to be valid until the - // CARenderUpdateFinish() call below. + // wkCACFContextFinishUpdate() call below. char space[4096]; - CARenderUpdate* u = CARenderUpdateBegin(space, sizeof(space), t, 0, 0, &bounds); - if (!u) + if (!wkCACFContextBeginUpdate(m_context, space, sizeof(space), t, bounds, windowDirtyRects.data(), windowDirtyRects.size())) 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); + // FIXME: don't need to clear dirty region if layer tree is opaque. - if (!rgn) + WKCACFUpdateRectEnumerator* e = wkCACFContextCopyUpdateRectEnumerator(m_context); + if (!e) 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)) { + for (const CGRect* r = wkCACFUpdateRectEnumeratorNextRect(e); r; r = wkCACFUpdateRectEnumeratorNextRect(e)) { D3DRECT rect; rect.x1 = r->origin.x; rect.x2 = rect.x1 + r->size.width; @@ -532,8 +515,7 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) rects.append(rect); } - CGSReleaseRegionEnumerator(e); - CGSReleaseRegion(rgn); + wkCACFUpdateRectEnumeratorRelease(e); if (rects.isEmpty()) break; @@ -541,13 +523,13 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) m_d3dDevice->Clear(rects.size(), rects.data(), D3DCLEAR_TARGET, 0, 1.0f, 0); m_d3dDevice->BeginScene(); - CARenderOGLRender(m_renderer, u); + wkCACFContextRenderUpdate(m_context); m_d3dDevice->EndScene(); err = m_d3dDevice->Present(0, 0, 0, 0); if (err == D3DERR_DEVICELOST) { - CARenderUpdateAddRect(u, &bounds); + wkCACFContextAddUpdateRect(m_context, bounds); if (!resetDevice(LostDevice)) { // We can't reset the device right now. Try again soon. renderSoon(); @@ -556,7 +538,7 @@ void WKCACFLayerRenderer::render(const Vector<CGRect>& dirtyRects) } } while (err == D3DERR_DEVICELOST); - CARenderUpdateFinish(u); + wkCACFContextFinishUpdate(m_context); #ifndef NDEBUG if (m_printTree) @@ -598,7 +580,7 @@ void WKCACFLayerRenderer::initD3DGeometry() bool WKCACFLayerRenderer::resetDevice(ResetReason reason) { ASSERT(m_d3dDevice); - ASSERT(m_renderContext); + ASSERT(m_context); HRESULT hr = m_d3dDevice->TestCooperativeLevel(); @@ -617,10 +599,10 @@ bool WKCACFLayerRenderer::resetDevice(ResetReason reason) // We can reset the device. - // We have to purge the CARenderOGLContext whenever we reset the IDirect3DDevice9 in order to + // We have to release the context's D3D resrouces whenever we reset the IDirect3DDevice9 in order to // destroy any D3DPOOL_DEFAULT resources that Core Animation has allocated (e.g., textures used // for mask layers). See <http://msdn.microsoft.com/en-us/library/bb174425(v=VS.85).aspx>. - CARenderOGLPurge(m_renderer); + wkCACFContextReleaseD3DResources(m_context); D3DPRESENT_PARAMETERS parameters = initialPresentationParameters(); hr = m_d3dDevice->Reset(¶meters); diff --git a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h index 1d73b99..763fffa 100755..100644 --- a/WebCore/platform/graphics/win/WKCACFLayerRenderer.h +++ b/WebCore/platform/graphics/win/WKCACFLayerRenderer.h @@ -41,9 +41,7 @@ #include <CoreGraphics/CGGeometry.h> interface IDirect3DDevice9; -typedef struct _CACFContext* CACFContextRef; -typedef struct _CARenderContext CARenderContext; -typedef struct _CARenderOGLContext CARenderOGLContext; +struct WKCACFContext; namespace WebCore { @@ -64,7 +62,7 @@ public: ~WKCACFLayerRenderer(); static bool acceleratedCompositingAvailable(); - static void didFlushContext(CACFContextRef); + static void didFlushContext(WKCACFContext*); void setRootContents(CGImageRef); void setRootContentsAndDisplay(CGImageRef); @@ -104,9 +102,7 @@ private: COMPtr<IDirect3DDevice9> m_d3dDevice; RefPtr<WKCACFRootLayer> m_rootLayer; RefPtr<WKCACFLayer> m_rootChildLayer; - RetainPtr<CACFContextRef> m_context; - CARenderContext* m_renderContext; - CARenderOGLContext* m_renderer; + WKCACFContext* m_context; HWND m_hostWindow; Timer<WKCACFLayerRenderer> m_renderTimer; bool m_backingStoreDirty; diff --git a/WebCore/platform/graphics/win/WebLayer.cpp b/WebCore/platform/graphics/win/WebLayer.cpp index 70a522d..ecda294 100644 --- a/WebCore/platform/graphics/win/WebLayer.cpp +++ b/WebCore/platform/graphics/win/WebLayer.cpp @@ -94,7 +94,7 @@ void WebLayer::drawInContext(PlatformGraphicsContext* context) #endif if (m_owner->showRepaintCounter()) { - String text = String::format("%d", m_owner->incrementRepaintCount());; + String text = String::number(m_owner->incrementRepaintCount()); CGContextSaveGState(context); @@ -129,7 +129,7 @@ void WebLayer::drawInContext(PlatformGraphicsContext* context) font.update(0); GraphicsContext cg(context); - cg.setFillColor(Color::black, DeviceColorSpace); + cg.setFillColor(Color::black, ColorSpaceDeviceRGB); cg.drawText(font, TextRun(text), IntPoint(aBounds.origin.x + 5, aBounds.origin.y + 17)); CGContextRestoreGState(context); diff --git a/WebCore/platform/graphics/win/WebTiledLayer.cpp b/WebCore/platform/graphics/win/WebTiledLayer.cpp index 01dd6ae..4705033 100644 --- a/WebCore/platform/graphics/win/WebTiledLayer.cpp +++ b/WebCore/platform/graphics/win/WebTiledLayer.cpp @@ -201,7 +201,7 @@ void WebTiledLayer::addTile() CACFLayerInsertSublayer(m_tileParent.get(), newLayer.get(), sublayers ? CFArrayGetCount(sublayers) : 0); if (m_owner->showDebugBorders()) { - CGColorRef borderColor = createCGColor(Color(128, 0, 128, 180)); + CGColorRef borderColor = CGColorCreateGenericRGB(0.5, 0, 0.5, 0.7); CACFLayerSetBorderColor(newLayer.get(), borderColor); CGColorRelease(borderColor); CACFLayerSetBorderWidth(newLayer.get(), 2); diff --git a/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp b/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp index a91b988..a0c10fc 100644 --- a/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp +++ b/WebCore/platform/graphics/wince/GraphicsContextWinCE.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2007-2009 Torch Mobile Inc. + * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,6 +25,7 @@ #include "AffineTransform.h" #include "CharacterNames.h" #include "Font.h" +#include "GDIExtras.h" #include "GlyphBuffer.h" #include "Gradient.h" #include "GraphicsContextPrivate.h" @@ -322,8 +324,7 @@ public: if (hdc == m_dc) return; -#if !defined(NO_ALPHABLEND) - if (alphaPaint == AlphaPaintOther) { + if (alphaPaint == AlphaPaintOther && hasAlphaBlendSupport()) { ASSERT(bmp && bmp->bytes() && bmp->is32bit()); unsigned* pixels = (unsigned*)bmp->bytes(); const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels(); @@ -332,13 +333,13 @@ public: ++pixels; } } - if (m_opacity < 1. || alphaPaint == AlphaPaintOther) { + if ((m_opacity < 1. || alphaPaint == AlphaPaintOther) && hasAlphaBlendSupport()) { const BLENDFUNCTION blend = { AC_SRC_OVER, 0 , m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255) , alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA }; - AlphaBlend(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend); + bool success = alphaBlendIfSupported(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend); + ASSERT_UNUSED(success, success); } else -#endif StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY); } @@ -347,7 +348,7 @@ public: Vector<GraphicsContextPlatformPrivateData> m_backupData; }; -static HPEN createPen(const Color& col, double fWidth, StrokeStyle style) +static PassOwnPtr<HPEN> createPen(const Color& col, double fWidth, StrokeStyle style) { int width = stableRound(fWidth); if (width < 1) @@ -367,12 +368,12 @@ static HPEN createPen(const Color& col, double fWidth, StrokeStyle style) break; } - return CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue())); + return adoptPtr(CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue()))); } -static inline HGDIOBJ createBrush(const Color& col) +static inline PassOwnPtr<HBRUSH> createBrush(const Color& col) { - return CreateSolidBrush(RGB(col.red(), col.green(), col.blue())); + return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue()))); } template <typename PixelType, bool Is16bit> static void _rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform) @@ -644,41 +645,33 @@ void GraphicsContext::drawRect(const IntRect& rect) return; trRect.move(transparentDC.toShift()); - HGDIOBJ brush = 0; + OwnPtr<HBRUSH> brush; HGDIOBJ oldBrush; if (fillColor().alpha()) { brush = createBrush(fillColor()); - oldBrush = SelectObject(dc, brush); + oldBrush = SelectObject(dc, brush.get()); } else - SelectObject(dc, GetStockObject(NULL_BRUSH)); + oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); - HGDIOBJ pen = 0; + OwnPtr<HPEN> pen; HGDIOBJ oldPen; if (strokeStyle() != NoStroke) { pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); - oldPen = SelectObject(dc, pen); + oldPen = SelectObject(dc, pen.get()); } else - SelectObject(dc, GetStockObject(NULL_PEN)); + oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); - if (!brush && !pen) - return; - - if (trRect.width() <= 0) - trRect.setWidth(1); - if (trRect.height() <= 0) - trRect.setHeight(1); - - Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + if (brush || pen) { + if (trRect.width() <= 0) + trRect.setWidth(1); + if (trRect.height() <= 0) + trRect.setHeight(1); - if (pen) { - SelectObject(dc, oldPen); - DeleteObject(pen); + Rectangle(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); } - if (brush) { - SelectObject(dc, oldBrush); - DeleteObject(brush); - } + SelectObject(dc, oldPen); + SelectObject(dc, oldBrush); } void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) @@ -702,14 +695,13 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) trPoint1 += transparentDC.toShift(); trPoint2 += transparentDC.toShift(); - HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); - HGDIOBJ oldPen = SelectObject(dc, pen); + OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); MoveToEx(dc, trPoint1.x(), trPoint1.y(), 0); LineTo(dc, trPoint2.x(), trPoint2.y()); SelectObject(dc, oldPen); - DeleteObject(pen); } void GraphicsContext::drawEllipse(const IntRect& rect) @@ -728,32 +720,27 @@ void GraphicsContext::drawEllipse(const IntRect& rect) return; trRect.move(transparentDC.toShift()); - HGDIOBJ brush = 0; + OwnPtr<HBRUSH> brush; HGDIOBJ oldBrush; if (fillColor().alpha()) { brush = createBrush(fillColor()); - oldBrush = SelectObject(dc, brush); + oldBrush = SelectObject(dc, brush.get()); } else - SelectObject(dc, GetStockObject(NULL_BRUSH)); - HGDIOBJ pen = 0; - HGDIOBJ oldPen; + oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); + + OwnPtr<HPEN> pen; + HGDIOBJ oldPen = 0; if (strokeStyle() != NoStroke) { pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); - oldPen = SelectObject(dc, pen); + oldPen = SelectObject(dc, pen.get()); } else - SelectObject(dc, GetStockObject(NULL_PEN)); - - Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); + oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); - if (pen) { - SelectObject(dc, oldPen); - DeleteObject(pen); - } + if (brush || pen) + Ellipse(dc, trRect.x(), trRect.y(), trRect.right(), trRect.bottom()); - if (brush) { - SelectObject(dc, oldBrush); - DeleteObject(brush); - } + SelectObject(dc, oldPen); + SelectObject(dc, oldBrush); } static inline bool equalAngle(double a, double b) @@ -815,8 +802,8 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp return; trRect.move(transparentDC.toShift()); - HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); - HGDIOBJ oldPen = SelectObject(dc, pen); + OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); double a = trRect.width() * 0.5; double b = trRect.height() * 0.5; @@ -872,7 +859,6 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp SelectClipRgn(dc, clipRgn.get()); SelectObject(dc, oldPen); - DeleteObject(pen); } void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) @@ -916,36 +902,27 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points winPoints[i].y += transparentDC.toShift().height(); } - HGDIOBJ brush = 0; + OwnPtr<HBRUSH> brush; HGDIOBJ oldBrush; if (fillColor().alpha()) { brush = createBrush(fillColor()); - oldBrush = SelectObject(dc, brush); + oldBrush = SelectObject(dc, brush.get()); } else - SelectObject(dc, GetStockObject(NULL_BRUSH)); + oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH)); - HGDIOBJ pen = 0; + OwnPtr<HPEN> pen; HGDIOBJ oldPen; if (strokeStyle() != NoStroke) { pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); - oldPen = SelectObject(dc, pen); + oldPen = SelectObject(dc, pen.get()); } else - SelectObject(dc, GetStockObject(NULL_PEN)); - - if (!brush && !pen) - return; - - Polygon(dc, winPoints.data(), npoints); + oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); - if (pen) { - SelectObject(dc, oldPen); - DeleteObject(pen); - } + if (brush || pen) + Polygon(dc, winPoints.data(), npoints); - if (brush) { - SelectObject(dc, oldBrush); - DeleteObject(brush); - } + SelectObject(dc, oldPen); + SelectObject(dc, oldBrush); } void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased) @@ -1104,7 +1081,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) return; } - fillRect(rect, Color(Color::white), DeviceColorSpace); + fillRect(rect, Color(Color::white), ColorSpaceDeviceRGB); } void GraphicsContext::strokeRect(const FloatRect& rect, float width) @@ -1124,8 +1101,8 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width) return; trRect.move(transparentDC.toShift()); - HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); - HGDIOBJ oldPen = SelectObject(dc, pen); + OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); int right = trRect.right() - 1; int bottom = trRect.bottom() - 1; @@ -1141,7 +1118,6 @@ void GraphicsContext::strokeRect(const FloatRect& rect, float width) Polyline(dc, intPoints, 5); SelectObject(dc, oldPen); - DeleteObject(pen); } void GraphicsContext::beginTransparencyLayer(float opacity) @@ -1286,9 +1262,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& to RECT rectWin = dstRect; - HGDIOBJ brush = createBrush(shadowColor); - HGDIOBJ oldBrush = SelectObject(dc, brush); - + OwnPtr<HBRUSH> brush = createBrush(shadowColor); + HGDIOBJ oldBrush = SelectObject(dc, brush.get()); + SelectObject(dc, GetStockObject(NULL_PEN)); IntPoint centerPoint = rectCenterPoint(rectWin); @@ -1324,7 +1300,6 @@ void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& to drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2)); SelectObject(dc, oldBrush); - DeleteObject(brush); } @@ -1382,8 +1357,9 @@ void GraphicsContext::fillPath() if (!m_data->m_dc) return; + OwnPtr<HBRUSH> brush = createBrush(c); + if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { - HGDIOBJ brush = createBrush(c); for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) { IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect())); trRect.inflate(1); @@ -1396,19 +1372,16 @@ void GraphicsContext::fillPath() tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); SelectObject(dc, GetStockObject(NULL_PEN)); - HGDIOBJ oldBrush = SelectObject(dc, brush); + HGDIOBJ oldBrush = SelectObject(dc, brush.get()); i->platformPath()->fillPath(dc, &tr); SelectObject(dc, oldBrush); } - DeleteObject(brush); } else { SelectObject(m_data->m_dc, GetStockObject(NULL_PEN)); - HGDIOBJ brush = createBrush(c); - HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush); + HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get()); for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) i->platformPath()->fillPath(m_data->m_dc, &m_data->m_transform); SelectObject(m_data->m_dc, oldBrush); - DeleteObject(brush); } } @@ -1422,8 +1395,9 @@ void GraphicsContext::strokePath() if (!m_data->m_dc) return; + OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); + if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) { - HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) { IntRect trRect = enclosingIntRect(m_data->mapRect(i->boundingRect())); trRect.inflate(1); @@ -1436,19 +1410,16 @@ void GraphicsContext::strokePath() tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height()); SelectObject(dc, GetStockObject(NULL_BRUSH)); - HGDIOBJ oldPen = SelectObject(dc, pen); + HGDIOBJ oldPen = SelectObject(dc, pen.get()); i->platformPath()->strokePath(dc, &tr); SelectObject(dc, oldPen); } - DeleteObject(pen); } else { SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH)); - HGDIOBJ pen = createPen(strokeColor(), strokeThickness(), strokeStyle()); - HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen); + HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get()); for (Vector<Path>::const_iterator i = m_data->m_paths.begin(); i != m_data->m_paths.end(); ++i) i->platformPath()->strokePath(m_data->m_dc, &m_data->m_transform); SelectObject(m_data->m_dc, oldPen); - DeleteObject(pen); } } @@ -1465,7 +1436,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, DeviceColorSpace); + fillRect(r, color, ColorSpaceDeviceRGB); return; } @@ -1555,7 +1526,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (m_common->state.fillGradient) fillRect(rect, m_common->state.fillGradient.get()); else - fillRect(rect, fillColor(), DeviceColorSpace); + fillRect(rect, fillColor(), ColorSpaceDeviceRGB); restorePlatformState(); } diff --git a/WebCore/platform/graphics/wince/ImageWinCE.cpp b/WebCore/platform/graphics/wince/ImageWinCE.cpp index 61ec954..53b9b68 100644 --- a/WebCore/platform/graphics/wince/ImageWinCE.cpp +++ b/WebCore/platform/graphics/wince/ImageWinCE.cpp @@ -82,9 +82,9 @@ bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) IntSize imageSize = BitmapImage::size(); if (size) - drawFrameMatchingSourceSize(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), DeviceColorSpace, CompositeCopy); + drawFrameMatchingSourceSize(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), IntSize(*size), ColorSpaceDeviceRGB, CompositeCopy); else - draw(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0, 0, imageSize.width(), imageSize.height()), DeviceColorSpace, CompositeCopy); + draw(&gc, FloatRect(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0, 0, imageSize.width(), imageSize.height()), ColorSpaceDeviceRGB, CompositeCopy); } SelectObject(hdc.get(), hOldBmp); diff --git a/WebCore/platform/graphics/wince/PathWinCE.cpp b/WebCore/platform/graphics/wince/PathWinCE.cpp index 4f0195c..fa4c8fb 100644 --- a/WebCore/platform/graphics/wince/PathWinCE.cpp +++ b/WebCore/platform/graphics/wince/PathWinCE.cpp @@ -123,11 +123,6 @@ bool Path::isEmpty() const return m_path->isEmpty(); } -String Path::debugString() const -{ - return m_path->debugString(); -} - void Path::apply(void* info, PathApplierFunction function) const { m_path->apply(info, function); diff --git a/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp b/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp index 80e01a9..8534f89 100644 --- a/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp +++ b/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp @@ -754,43 +754,6 @@ void PlatformPath::addEllipse(const FloatRect& r) addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true); } -String PlatformPath::debugString() const -{ - String ret; - for (PlatformPathElements::const_iterator i(m_elements.begin()); i != m_elements.end(); ++i) { - switch (i->platformType()) { - case PlatformPathElement::PathMoveTo: - case PlatformPathElement::PathLineTo: - ret += String::format("M %f %f\n", i->pointAt(0).m_x, i->pointAt(0).m_y); - break; - case PlatformPathElement::PathArcTo: - ret += String::format("A %f %f %f %f %f %f %c\n" - , i->arcTo().m_end.m_x, i->arcTo().m_end.m_y - , i->arcTo().m_center.m_x, i->arcTo().m_center.m_y - , i->arcTo().m_radius.m_x, i->arcTo().m_radius.m_y - , i->arcTo().m_clockwise? 'Y' : 'N'); - break; - case PlatformPathElement::PathQuadCurveTo: - ret += String::format("Q %f %f %f %f\n" - , i->pointAt(0).m_x, i->pointAt(0).m_y - , i->pointAt(1).m_x, i->pointAt(1).m_y); - break; - case PlatformPathElement::PathBezierCurveTo: - ret += String::format("B %f %f %f %f %f %f\n" - , i->pointAt(0).m_x, i->pointAt(0).m_y - , i->pointAt(1).m_x, i->pointAt(1).m_y - , i->pointAt(2).m_x, i->pointAt(2).m_y); - break; - default: - ASSERT(i->platformType() == PlatformPathElement::PathCloseSubpath); - ret += "S\n"; - break; - } - } - - return ret; -} - void PlatformPath::apply(void* info, PathApplierFunction function) const { PathElement pelement; diff --git a/WebCore/platform/graphics/wince/PlatformPathWinCE.h b/WebCore/platform/graphics/wince/PlatformPathWinCE.h index 3414b04..4c86fc3 100644 --- a/WebCore/platform/graphics/wince/PlatformPathWinCE.h +++ b/WebCore/platform/graphics/wince/PlatformPathWinCE.h @@ -164,7 +164,6 @@ namespace WebCore { void addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise); void addRect(const FloatRect& r); void addEllipse(const FloatRect& r); - String debugString() const; void apply(void* info, PathApplierFunction function) const; private: diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index a39404a..30daa67 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -120,8 +120,8 @@ GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) setPaintingDisabled(!context); if (context) { // Make sure the context starts in sync with our state. - setPlatformFillColor(fillColor(), DeviceColorSpace); - setPlatformStrokeColor(strokeColor(), DeviceColorSpace); + setPlatformFillColor(fillColor(), ColorSpaceDeviceRGB); + setPlatformStrokeColor(strokeColor(), ColorSpaceDeviceRGB); } #if USE(WXGC) m_data->context = (wxGCDC*)context; diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp index 3006e27..f5355f2 100644 --- a/WebCore/platform/graphics/wx/PathWx.cpp +++ b/WebCore/platform/graphics/wx/PathWx.cpp @@ -117,12 +117,6 @@ bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const return false; } -String Path::debugString() const -{ - notImplemented(); - return String(); -} - Path& Path::operator=(const Path& path) { *m_path = *path.platformPath(); |