Scale image prior to draw it's pattern to enhance performance
authorKyungjin Kim <gen.kim@samsung.com>
Thu, 28 Mar 2013 03:50:02 +0000 (12:50 +0900)
committerKyungjin Kim <gen.kim@samsung.com>
Fri, 5 Apr 2013 02:21:40 +0000 (11:21 +0900)
[Title] Scale image prior to draw it's pattern to enhance performance
[Issue#] N/A
[Problem] Browsermark2 2d transform scores 1200
[Cause] Drawing an image to cairo context with scaling is very slow
[Solution] scale image first then draw the pattern to the context so scores 1800

Change-Id: Ia35ed86631dc24e9b6ac55e7117f9e31ec4a9eee

Source/WTF/wtf/Platform.h [changed mode: 0755->0644]
Source/WebCore/platform/graphics/cairo/CairoUtilities.cpp

old mode 100755 (executable)
new mode 100644 (file)
index 79ecee9..6391601
 #define ENABLE_TIZEN_LAYOUTSTATE_NULL_CHECKING_WORKAROUND 1 /* Jaehun Lim(ljaehun.lim@samsung.com) : Add null checking for LayoutState, LayoutState can be null while push and pop */
 #define ENABLE_TIZEN_DONT_DISPATCH_FAKEMOUSEMOVEEVENT_WHEN_SCROLLING_ON_TOUCH_DEVICES 1 /* Jaehun Lim (ljaehun.lim@samsung.com) : Don't dispatch fake mouse move events on touch devices for fixing hover problem */
 #define ENABLE_TIZEN_LOAD_HTML_STRING_AS_UTF8 1 /* KwangYong Choi (ky0.choi@samsung.com) : Use UTF-8 instead of UTF-16 when the page is loaded by WebPage::loadHTMLString() */
+#define ENABLE_TIZEN_DRAW_SCALED_PATTERN 1 /* Kyungjin Kim(gen.kim@samsung.com) : Scale image prior to draw it's pattern to enhance performance */
 
 /* Download Patches */
 #define ENABLE_TIZEN_DOWNLOAD 1 /* Keunsoon Lee(keunsoon.lee@samsung.com) : */
index 9e1a910..57adcb3 100644 (file)
@@ -275,8 +275,7 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz
         if (cairo_surface_status(sourceImageSurface.get()) != CAIRO_STATUS_SUCCESS)
             return;
         image = sourceImageSurface.get();
-    }
-    else if (cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_GL && cairo_surface_get_type(image) == CAIRO_SURFACE_TYPE_IMAGE) {
+    } else if (cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_GL && cairo_surface_get_type(image) == CAIRO_SURFACE_TYPE_IMAGE) {
         RefPtr<cairo_surface_t> snapshot = adoptRef((cairo_surface_t *) cairo_surface_get_user_data(image, (const cairo_user_data_key_t *)image));
         if (snapshot && cairo_surface_get_type(snapshot.get()) != CAIRO_SURFACE_TYPE_GL) {
             cairo_surface_set_user_data(image, (const cairo_user_data_key_t *)image, 0, 0);
@@ -294,12 +293,9 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz
                 RefPtr<cairo_t> snapshotContext = adoptRef(cairo_create(snapshot.get()));
                 cairo_set_source_surface(snapshotContext.get(), image, 0, 0);
                 cairo_paint(snapshotContext.get());
-                cairo_surface_set_user_data(image, (const cairo_user_data_key_t *)image,
-                                    (void *)snapshot.get(), destroyCachedCairoSurface);
-            } else {
+                cairo_surface_set_user_data(image, (const cairo_user_data_key_t *)image, (void *)snapshot.get(), destroyCachedCairoSurface);
+            } else
                 snapshot = 0;
-                // re-consider : this can be image-surface for oversized buffer.
-            }
         }
 
         if(snapshot)
@@ -324,17 +320,91 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz
         image = clippedImageSurface.get();
     }
 
+#if ENABLE(TIZEN_DRAW_SCALED_PATTERN)
+    // Images bigger than this in all directions will be scaled because width or height could be 0 by the ctm.
+    const int kImageSizeThreshold = 1;
+    // The value of repetitionX * repetitionY smaller than this is considered inefficient source and will not be replaced by scaled pattern.
+    // FIXME: Need to figure out the optimum value.
+    const float kRepetitionThreshold = 2;
+
+#if ENABLE(TIZEN_CAIROGLES_IMAGE_CACHE)
+    int imageWidth, imageHeight;
+    if (cairo_surface_get_type(image) == CAIRO_SURFACE_TYPE_GL) {
+        imageWidth = cairo_gl_surface_get_width(image);
+        imageHeight = cairo_gl_surface_get_height(image);
+    } else {
+        imageWidth = cairo_image_surface_get_width(image);
+        imageHeight = cairo_image_surface_get_height(image);
+    }
+#else
+    int imageWidth = cairo_image_surface_get_width(image);
+    int imageHeight = cairo_image_surface_get_height(image);
+#endif
+    if (!imageWidth || !imageHeight)
+        return;
+
+    cairo_matrix_t ctm;
+    cairo_get_matrix(cr, &ctm);
+    cairo_matrix_t matrix = cairo_matrix_t(patternTransform);
+    cairo_matrix_t totalMatrix;
+    cairo_matrix_multiply(&totalMatrix, &ctm, &matrix);
+
+    double scaleX = ctm.xx ? ctm.xx : 1;
+    double scaleY = ctm.yy ? ctm.yy : 1;
+    int destBitmapWidth = imageWidth * totalMatrix.xx;
+    int destBitmapHeight = imageHeight * totalMatrix.yy;
+    float repetitionX = destRect.width() / destBitmapWidth;
+    float repetitionY = destRect.height() / destBitmapHeight;
+
+    bool shouldScalePattern = false;
+    if (scaleX != 1 && scaleY != 1 && totalMatrix.xx != 1 && totalMatrix.yy != 1 && destBitmapWidth && destBitmapHeight
+        && imageWidth > kImageSizeThreshold && imageHeight > kImageSizeThreshold && repetitionX * repetitionY > kRepetitionThreshold)
+        shouldScalePattern = true;
+
+    RefPtr<cairo_surface_t> scaledImageSurface = 0;
+    if (shouldScalePattern) {
+#if ENABLE(TIZEN_CAIROGLES_IMAGE_CACHE)
+        if (cairo_surface_get_type(image) == CAIRO_SURFACE_TYPE_GL)
+            scaledImageSurface = adoptRef(cairo_surface_create_similar(image, CAIRO_CONTENT_COLOR_ALPHA, destBitmapWidth, destBitmapHeight));
+        else
+            scaledImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, destBitmapWidth, destBitmapHeight));
+#else
+        scaledImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, destBitmapWidth, destBitmapHeight));
+#endif
+        RefPtr<cairo_t> scaledImageContext = adoptRef(cairo_create(scaledImageSurface.get()));
+        cairo_set_operator(scaledImageContext.get(), CAIRO_OPERATOR_SOURCE);
+        cairo_scale(scaledImageContext.get(), totalMatrix.xx, totalMatrix.yy);
+        cairo_set_source_surface(scaledImageContext.get(), image, 0, 0);
+        cairo_paint(scaledImageContext.get());
+        image = scaledImageSurface.get();
+    }
+#endif
+
     cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
     cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
 
+#if ENABLE(TIZEN_DRAW_SCALED_PATTERN)
+    cairo_matrix_t combined;
+    if (shouldScalePattern)
+        cairo_matrix_init(&combined, 1 / scaleX, 0, 0, 1 / scaleY, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d());
+    else {
+        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_multiply(&combined, &patternMatrix, &phaseMatrix);
+    }
+#else
     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);
+#endif
     cairo_matrix_invert(&combined);
 
 #if ENABLE(TIZEN_ADJUST_PATTERN_MATRIX)
-    adjustPatternMatrixForPixelAlign(cr, pattern, &combined,  destRect.x(), destRect.y(), destRect.width(), destRect.height());
+#if ENABLE(TIZEN_DRAW_SCALED_PATTERN)
+    if (!shouldScalePattern)
+#endif
+    adjustPatternMatrixForPixelAlign(cr, pattern, &combined, destRect.x(), destRect.y(), destRect.width(), destRect.height());
 #endif
     cairo_pattern_set_matrix(pattern, &combined);
 
@@ -345,7 +415,7 @@ void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSiz
     cairo_fill(cr);
 
 #if ENABLE(TIZEN_CAIROGLES_IMAGE_CACHE)
-    if(clippedImageSurface && sourceImageSurface)
+    if (sourceImageSurface)
         cairo_surface_unmap_image(original_image, sourceImageSurface.get());
 #endif