[cherrypick] Prevent sampling outside source boundaries, by
authorDevdatta Deshpande <d.deshpande@partner.samsung.com>
Fri, 16 Aug 2013 05:41:33 +0000 (11:11 +0530)
committerHurnjoo Lee <hurnjoo.lee@samsung.com>
Tue, 3 Sep 2013 02:36:26 +0000 (11:36 +0900)
             creating subsurfaces from source surfaces.
[Title]    White line appears in Sensor ball app
[Issue#]   P130806-1683
[Problem]  A white line appears at specific locations in
           Sensor ball app when the ball is moved slowly
           at some particular locations in the app
[Cause]    The view port is divided into several tiles by
           Backing store. When the ball is on the edge of
           any tile the paint rect is divided between two
           tiles. Due to this division and various other
           parameters like scale factor etc. the height is
           converted into a float. Since cairo does not
           handle floats properly a white line appears.
[Solution] In latest opensource code this scenario is
           already taken care of by expanding the float
           rect to an int rect.
           Cherry-picked the change from
           http://trac.webkit.org/changeset/148681

Change-Id: Ibcd73ffaae360042b209ed92929673d560537376

Source/WebCore/platform/graphics/cairo/PlatformContextCairo.cpp

index bff8c29..fa33de8 100644 (file)
@@ -165,7 +165,7 @@ static void drawPatternToCairoContext(cairo_t* cr, cairo_pattern_t* pattern, con
         cairo_fill(cr);
 }
 
-void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const FloatRect& destRect, const FloatRect& srcRect, GraphicsContext* context)
+void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const FloatRect& destRect, const FloatRect& originalSrcRect, GraphicsContext* context)
 {
 #if ENABLE(TIZEN_USE_XPIXMAP_DECODED_IMAGESOURCE)
     cairo_surface_type_t surfaceType = cairo_surface_get_type(cairo_get_target (cr()));
@@ -259,9 +259,21 @@ void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const
     }
 #endif
 
-    // If we're drawing a sub portion of the image or scaling then create
-    // a pattern transformation on the image and draw the transformed pattern.
-    // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+    FloatRect srcRect = originalSrcRect;
+
+    // We need to account for negative source dimensions by flipping the rectangle.
+    if (originalSrcRect.width() < 0) {
+        srcRect.setX(originalSrcRect.x() + originalSrcRect.width());
+        srcRect.setWidth(std::fabs(originalSrcRect.width()));
+    }
+    if (originalSrcRect.height() < 0) {
+        srcRect.setY(originalSrcRect.y() + originalSrcRect.height());
+        srcRect.setHeight(std::fabs(originalSrcRect.height()));
+    }
+
+    // Cairo subsurfaces don't support floating point boundaries well, so we expand the rectangle.
+    IntRect expandedSrcRect(enclosingIntRect(srcRect));
+
 #if ENABLE(TIZEN_ATLAS_IMAGE_BUG_FIX)
 #if ENABLE(TIZEN_CAIROGLES_IMAGE_CACHE)
     RefPtr<cairo_pattern_t> pattern;
@@ -276,7 +288,7 @@ void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const
             && (srcRect.x() >= 0 && srcRect.x() < imageWidth && srcRect.y() >= 0 && srcRect.y() < imageHeight)
             && floor(srcRect.x() + srcRect.width()) - ceil(srcRect.x()) >= 1
             && floor(srcRect.y() + srcRect.height()) - ceil(srcRect.y()) >= 1) {
-            subSurface = cairo_surface_create_for_rectangle(surface, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
+            subSurface = cairo_surface_create_for_rectangle(surface, expandedSrcRect.x(), expandedSrcRect.y(), expandedSrcRect.width(), expandedSrcRect.height());
             pattern = adoptRef(cairo_pattern_create_for_surface(subSurface));
             cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, 0, 0 };
             cairo_pattern_set_matrix(pattern.get(), &matrix);
@@ -309,7 +321,7 @@ void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const
             && (srcRect.x() >= 0 && srcRect.x() < imageWidth && srcRect.y() >= 0 && srcRect.y() < imageHeight)
             && floor(srcRect.x() + srcRect.width()) - ceil(srcRect.x()) >= 1
             && floor(srcRect.y() + srcRect.height()) - ceil(srcRect.y()) >= 1) {
-            subSurface = cairo_surface_create_for_rectangle(surface, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
+            subSurface = cairo_surface_create_for_rectangle(surface, expandedSrcRect.x(), expandedSrcRect.y(), expandedSrcRect.width(), expandedSrcRect.height());
             pattern = adoptRef(cairo_pattern_create_for_surface(subSurface));
             cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, 0, 0 };
             cairo_pattern_set_matrix(pattern.get(), &matrix);
@@ -358,28 +370,30 @@ void PlatformContextCairo::drawSurfaceToContext(cairo_surface_t* surface, const
     }
     cairo_pattern_set_extend(pattern.get(), CAIRO_EXTEND_PAD);
 
+    float leftPadding = static_cast<float>(expandedSrcRect.x()) - floorf(srcRect.x());
+    float topPadding = static_cast<float>(expandedSrcRect.y()) - floorf(srcRect.y());
 #if !ENABLE(TIZEN_ATLAS_IMAGE_BUG_FIX)
-    float scaleX = srcRect.width() / destRect.width();
-    float scaleY = srcRect.height() / destRect.height();
+    float scaleX = std::fabs(srcRect.width() / destRect.width());
+    float scaleY = std::fabs(srcRect.height() / destRect.height());
 #if ENABLE(TIZEN_CAIROGLES_IMAGE_AUTOSCALE)
     float scaleWidth = (float)original_width/current_width;
     float scaleHeight = (float)original_height/current_height;
-    cairo_matrix_t matrix = { scaleX/scaleWidth, 0, 0, scaleY/scaleHeight, srcRect.x()/scaleWidth, srcRect.y()/scaleHeight };
+    cairo_matrix_t matrix = { scaleX/scaleWidth, 0, 0, scaleY/scaleHeight, leftPadding/scaleWidth, topPadding/scaleHeight };
 #else
-    cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() };
+    cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, leftPadding, topPadding };
 #endif
     cairo_pattern_set_matrix(pattern.get(), &matrix);
 #else
 #if ENABLE(TIZEN_CAIROGLES_IMAGE_CACHE) ||ENABLE(TIZEN_USE_XPIXMAP_DECODED_IMAGESOURCE)
     if (surfaceType == CAIRO_SURFACE_TYPE_GL) {
-        float scaleX = srcRect.width() / destRect.width();
-        float scaleY = srcRect.height() / destRect.height();
+        float scaleX = std::fabs(srcRect.width() / destRect.width());
+        float scaleY = std::fabs(srcRect.height() / destRect.height());
     #if ENABLE(TIZEN_CAIROGLES_IMAGE_AUTOSCALE)
         float scaleWidth = (float)original_width/current_width;
         float scaleHeight = (float)original_height/current_height;
-        cairo_matrix_t matrix = { scaleX/scaleWidth, 0, 0, scaleY/scaleHeight, srcRect.x()/scaleWidth, srcRect.y()/scaleHeight };
+        cairo_matrix_t matrix = { scaleX/scaleWidth, 0, 0, scaleY/scaleHeight,leftPadding/scaleWidth, topPadding/scaleHeight };
     #else
-        cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, srcRect.x(), srcRect.y() };
+        cairo_matrix_t matrix = { scaleX, 0, 0, scaleY, leftPadding, topPadding };
     #endif
         cairo_pattern_set_matrix(pattern.get(), &matrix);
     }