Implement the HTML5 canvas tainting rules to prevent potential data leakage
[WebKit-https.git] / WebCore / html / CanvasPattern.cpp
index 4e42ea57b7fcc410973e1e0d126620be752b312b..2cda91783103a484649b9d4cb9cb889b2cfb2d00 100644 (file)
@@ -63,23 +63,41 @@ void CanvasPattern::parseRepetitionType(const String& type, bool& repeatX, bool&
     ec = SYNTAX_ERR;
 }
 
-#if __APPLE__
+#if PLATFORM(CG)
 
-CanvasPattern::CanvasPattern(CGImageRef image, bool repeatX, bool repeatY)
-    : m_platformImage(image)
+CanvasPattern::CanvasPattern(CGImageRef image, bool repeatX, bool repeatY, bool originClean)
+    : RefCounted<CanvasPattern>(0)
+    , m_platformImage(image)
     , m_cachedImage(0)
     , m_repeatX(repeatX)
     , m_repeatY(repeatY)
+    , m_originClean(originClean)
+{
+}
+
+#elif PLATFORM(CAIRO)
+
+CanvasPattern::CanvasPattern(cairo_surface_t* surface, bool repeatX, bool repeatY, bool originClean)
+    : RefCounted<CanvasPattern>(0)
+    , m_platformImage(cairo_surface_reference(surface))
+    , m_cachedImage(0)
+    , m_repeatX(repeatX)
+    , m_repeatY(repeatY)
+    , m_originClean(originClean)
 {
 }
 
 #endif
 
-CanvasPattern::CanvasPattern(CachedImage* cachedImage, bool repeatX, bool repeatY)
-    : m_platformImage(0)
+CanvasPattern::CanvasPattern(CachedImage* cachedImage, bool repeatX, bool repeatY, bool originClean)
+    : RefCounted<CanvasPattern>(0)
+#if PLATFORM(CG) || PLATFORM(CAIRO)
+    , m_platformImage(0)
+#endif
     , m_cachedImage(cachedImage)
     , m_repeatX(repeatX)
     , m_repeatY(repeatY)
+    , m_originClean(originClean)
 {
     if (cachedImage)
         cachedImage->ref(this);
@@ -87,20 +105,22 @@ CanvasPattern::CanvasPattern(CachedImage* cachedImage, bool repeatX, bool repeat
 
 CanvasPattern::~CanvasPattern()
 {
-#if __APPLE__
-    CGImageRelease(m_platformImage);
+#if PLATFORM(CAIRO)
+    if (m_platformImage)
+        cairo_surface_destroy(m_platformImage);
 #endif
     if (m_cachedImage)
         m_cachedImage->deref(this);
 }
 
-#if __APPLE__
+#if PLATFORM(CG)
 
 static void patternCallback(void* info, CGContextRef context)
 {
     CGImageRef platformImage = static_cast<CanvasPattern*>(info)->platformImage();
     if (platformImage) {
-        CGRect rect = CGRectMake(0, 0, CGImageGetWidth(platformImage), CGImageGetHeight(platformImage));
+        CGRect rect = GraphicsContext(context).roundToDevicePixels(
+            FloatRect(0, 0, CGImageGetWidth(platformImage), CGImageGetHeight(platformImage)));
         CGContextDrawImage(context, rect, platformImage);
         return;
     }
@@ -112,16 +132,18 @@ static void patternCallback(void* info, CGContextRef context)
     if (!image)
         return;
 
-    FloatRect rect = image->rect();
+    FloatRect rect = GraphicsContext(context).roundToDevicePixels(image->rect());
 
     if (image->getCGImageRef()) {
         CGContextDrawImage(context, rect, image->getCGImageRef());
+        // FIXME: We should refactor this code to use the platform-independent 
+        // drawing API in all cases. Then, this didDraw call will happen 
+        // automatically, and we can remove it.
+        cachedImage->didDraw(image);
         return;
     }
 
-    // FIXME: Won't handle text flipping right for image types that include text
-    // since we just pass false for the context's flipped state.
-    GraphicsContext(context, false, false).drawImage(image, rect);
+    GraphicsContext(context).drawImage(image, rect);
 }
 
 static void patternReleaseCallback(void* info)
@@ -135,8 +157,8 @@ CGPatternRef CanvasPattern::createPattern(const CGAffineTransform& transform)
     rect.origin.x = 0;
     rect.origin.y = 0;
     if (m_platformImage) {
-        rect.size.width = CGImageGetWidth(m_platformImage);
-        rect.size.height = CGImageGetHeight(m_platformImage);
+        rect.size.width = CGImageGetWidth(m_platformImage.get());
+        rect.size.height = CGImageGetHeight(m_platformImage.get());
     } else {
         if (!m_cachedImage)
             return 0;
@@ -156,7 +178,7 @@ CGPatternRef CanvasPattern::createPattern(const CGAffineTransform& transform)
     // INT_MAX is almost correct, but there seems to be some number wrapping occuring making the fill
     // pattern is not filled correctly. 
     // So, just pick a really large number that works. 
-    float yStep = m_repeatY ? rect.size.height : (100000000.0);
+    float yStep = m_repeatY ? rect.size.height : (100000000.0f);
 
     const CGPatternCallbacks patternCallbacks = { 0, patternCallback, patternReleaseCallback };
     ref();
@@ -164,6 +186,32 @@ CGPatternRef CanvasPattern::createPattern(const CGAffineTransform& transform)
         kCGPatternTilingConstantSpacing, TRUE, &patternCallbacks);
 }
 
+#elif PLATFORM(CAIRO)
+
+cairo_pattern_t* CanvasPattern::createPattern(const cairo_matrix_t& m)
+{
+    cairo_surface_t* surface = 0;
+    if (m_platformImage) {
+        surface = m_platformImage;
+    } else {
+        if (!m_cachedImage)
+            return 0;
+        Image* image = m_cachedImage->image();
+        if (!image)
+            return 0;
+        surface = image->nativeImageForCurrentFrame();
+    }
+
+    if (!surface)
+        return 0;
+
+    cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
+    cairo_pattern_set_matrix(pattern, &m);
+    if (m_repeatX || m_repeatY)
+        cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
+    return pattern;
+}
+
 #endif
 
 }