OSDN Git Service

Merge WebKit at r84325: Initial merge by git.
[android-x86/external-webkit.git] / Source / WebCore / platform / gtk / RenderThemeGtk.cpp
index 97c966d..9b11c27 100644 (file)
@@ -34,6 +34,7 @@
 #include "HTMLNames.h"
 #include "MediaControlElements.h"
 #include "PaintInfo.h"
+#include "PlatformContextCairo.h"
 #include "RenderBox.h"
 #include "RenderObject.h"
 #include "TimeRanges.h"
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
 
+#if ENABLE(PROGRESS_TAG)
+#include "RenderProgress.h"
+#endif
+
 namespace WebCore {
 
 using namespace HTMLNames;
@@ -220,15 +225,47 @@ bool RenderThemeGtk::paintTextArea(RenderObject* o, const PaintInfo& i, const In
     return paintTextField(o, i, r);
 }
 
-static void paintGdkPixbuf(GraphicsContext* context, const GdkPixbuf* icon, const IntPoint& iconPoint)
+static void paintGdkPixbuf(GraphicsContext* context, const GdkPixbuf* icon, const IntRect& iconRect)
 {
-    cairo_t* cr = context->platformContext();
+    IntSize iconSize(gdk_pixbuf_get_width(icon), gdk_pixbuf_get_height(icon));
+    if (iconRect.size() != iconSize) {
+        // We could use cairo_scale() here but cairo/pixman downscale quality is quite bad.
+        GRefPtr<GdkPixbuf> scaledIcon = gdk_pixbuf_scale_simple(icon, iconRect.width(), iconRect.height(),
+                                                                GDK_INTERP_BILINEAR);
+        icon = scaledIcon.get();
+    }
+
+    cairo_t* cr = context->platformContext()->cr();
     cairo_save(cr);
-    gdk_cairo_set_source_pixbuf(cr, icon, iconPoint.x(), iconPoint.y());
+    gdk_cairo_set_source_pixbuf(cr, icon, iconRect.x(), iconRect.y());
     cairo_paint(cr);
     cairo_restore(cr);
 }
 
+// Defined in GTK+ (gtk/gtkiconfactory.c)
+static const gint gtkIconSizeMenu = 16;
+static const gint gtkIconSizeSmallToolbar = 18;
+static const gint gtkIconSizeButton = 20;
+static const gint gtkIconSizeLargeToolbar = 24;
+static const gint gtkIconSizeDnd = 32;
+static const gint gtkIconSizeDialog = 48;
+
+static GtkIconSize getIconSizeForPixelSize(gint pixelSize)
+{
+    if (pixelSize < gtkIconSizeSmallToolbar)
+        return GTK_ICON_SIZE_MENU;
+    if (pixelSize >= gtkIconSizeSmallToolbar && pixelSize < gtkIconSizeButton)
+        return GTK_ICON_SIZE_SMALL_TOOLBAR;
+    if (pixelSize >= gtkIconSizeButton && pixelSize < gtkIconSizeLargeToolbar)
+        return GTK_ICON_SIZE_BUTTON;
+    if (pixelSize >= gtkIconSizeLargeToolbar && pixelSize < gtkIconSizeDnd)
+        return GTK_ICON_SIZE_LARGE_TOOLBAR;
+    if (pixelSize >= gtkIconSizeDnd && pixelSize < gtkIconSizeDialog)
+        return GTK_ICON_SIZE_DND;
+
+    return GTK_ICON_SIZE_DIALOG;
+}
+
 void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
 {
     adjustSearchFieldCancelButtonStyle(selector, style, e);
@@ -239,57 +276,77 @@ bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const PaintI
     return paintSearchFieldResultsDecoration(o, i, rect);
 }
 
-void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+static void adjustSearchFieldIconStyle(RenderStyle* style)
 {
     style->resetBorder();
     style->resetPadding();
 
+    // Get the icon size based on the font size.
+    int fontSize = style->fontSize();
+    if (fontSize < gtkIconSizeMenu) {
+        style->setWidth(Length(fontSize, Fixed));
+        style->setHeight(Length(fontSize, Fixed));
+        return;
+    }
     gint width = 0, height = 0;
-    gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
+    gtk_icon_size_lookup(getIconSizeForPixelSize(fontSize), &width, &height);
     style->setWidth(Length(width, Fixed));
     style->setHeight(Length(height, Fixed));
 }
 
-static IntPoint centerRectVerticallyInParentInputElement(RenderObject* object, const IntRect& rect)
+void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+    adjustSearchFieldIconStyle(style);
+}
+
+static IntRect centerRectVerticallyInParentInputElement(RenderObject* renderObject, const IntRect& rect)
 {
-    Node* input = object->node()->shadowAncestorNode(); // Get the renderer of <input> element.
+    // Get the renderer of <input> element.
+    Node* input = renderObject->node()->shadowAncestorNode();
     if (!input->renderer()->isBox())
-        return rect.topLeft();
+        return IntRect();
 
     // If possible center the y-coordinate of the rect vertically in the parent input element.
     // We also add one pixel here to ensure that the y coordinate is rounded up for box heights
     // that are even, which looks in relation to the box text.
     IntRect inputContentBox = toRenderBox(input->renderer())->absoluteContentBox();
 
-    return IntPoint(rect.x(), inputContentBox.y() + (inputContentBox.height() - rect.height() + 1) / 2);
+    // Make sure the scaled decoration stays square and will fit in its parent's box.
+    int iconSize = std::min(inputContentBox.width(), std::min(inputContentBox.height(), rect.height()));
+    IntRect scaledRect(rect.x(), inputContentBox.y() + (inputContentBox.height() - iconSize + 1) / 2, iconSize, iconSize);
+    return scaledRect;
 }
 
 bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
 {
+    IntRect iconRect = centerRectVerticallyInParentInputElement(renderObject, rect);
+    if (iconRect.isEmpty())
+        return false;
+
     GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_FIND,
                                            gtkTextDirection(renderObject->style()->direction()),
-                                           gtkIconState(this, renderObject), GTK_ICON_SIZE_MENU);
-    paintGdkPixbuf(paintInfo.context, icon.get(), centerRectVerticallyInParentInputElement(renderObject, rect));
+                                           gtkIconState(this, renderObject),
+                                           getIconSizeForPixelSize(rect.height()));
+    paintGdkPixbuf(paintInfo.context, icon.get(), iconRect);
     return false;
 }
 
 void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
 {
-    style->resetBorder();
-    style->resetPadding();
-
-    gint width = 0, height = 0;
-    gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
-    style->setWidth(Length(width, Fixed));
-    style->setHeight(Length(height, Fixed));
+    adjustSearchFieldIconStyle(style);
 }
 
 bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
 {
+    IntRect iconRect = centerRectVerticallyInParentInputElement(renderObject, rect);
+    if (iconRect.isEmpty())
+        return false;
+
     GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_CLEAR,
                                            gtkTextDirection(renderObject->style()->direction()),
-                                           gtkIconState(this, renderObject), GTK_ICON_SIZE_MENU);
-    paintGdkPixbuf(paintInfo.context, icon.get(), centerRectVerticallyInParentInputElement(renderObject, rect));
+                                           gtkIconState(this, renderObject),
+                                           getIconSizeForPixelSize(rect.height()));
+    paintGdkPixbuf(paintInfo.context, icon.get(), iconRect);
     return false;
 }
 
@@ -305,6 +362,31 @@ bool RenderThemeGtk::paintSearchField(RenderObject* o, const PaintInfo& i, const
     return paintTextField(o, i, rect);
 }
 
+bool RenderThemeGtk::paintCapsLockIndicator(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+    // The other paint methods don't need to check whether painting is disabled because RenderTheme already checks it
+    // before calling them, but paintCapsLockIndicator() is called by RenderTextControlSingleLine which doesn't check it.
+    if (paintInfo.context->paintingDisabled())
+        return true;
+
+    int iconSize = std::min(rect.width(), rect.height());
+    GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_CAPS_LOCK_WARNING,
+                                           gtkTextDirection(renderObject->style()->direction()),
+                                           0, getIconSizeForPixelSize(iconSize));
+
+    // Only re-scale the icon when it's smaller than the minimum icon size.
+    if (iconSize >= gtkIconSizeMenu)
+        iconSize = gdk_pixbuf_get_height(icon.get());
+
+    // GTK+ locates the icon right aligned in the entry. The given rectangle is already
+    // centered vertically by RenderTextControlSingleLine.
+    IntRect iconRect(rect.x() + rect.width() - iconSize,
+                     rect.y() + (rect.height() - iconSize) / 2,
+                     iconSize, iconSize);
+    paintGdkPixbuf(paintInfo.context, icon.get(), iconRect);
+    return true;
+}
+
 void RenderThemeGtk::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
 {
     style->setBoxShadow(0);
@@ -330,7 +412,7 @@ double RenderThemeGtk::caretBlinkInterval() const
     return time / 2000.;
 }
 
-static double getScreenDPI()
+double RenderThemeGtk::getScreenDPI()
 {
     // FIXME: Really this should be the widget's screen.
     GdkScreen* screen = gdk_screen_get_default();
@@ -399,10 +481,11 @@ bool RenderThemeGtk::paintMediaButton(RenderObject* renderObject, GraphicsContex
                                            gtkTextDirection(renderObject->style()->direction()),
                                            gtkIconState(this, renderObject),
                                            getMediaButtonIconSize(m_mediaIconSize));
-    IntPoint iconPoint(rect.x() + (rect.width() - m_mediaIconSize) / 2,
-                       rect.y() + (rect.height() - m_mediaIconSize) / 2);
+    IntRect iconRect(rect.x() + (rect.width() - m_mediaIconSize) / 2,
+                     rect.y() + (rect.height() - m_mediaIconSize) / 2,
+                     m_mediaIconSize, m_mediaIconSize);
     context->fillRect(FloatRect(rect), m_panelColor, ColorSpaceDeviceRGB);
-    paintGdkPixbuf(context, icon.get(), iconPoint);
+    paintGdkPixbuf(context, icon.get(), iconRect);
     return false;
 }
 
@@ -543,6 +626,50 @@ void RenderThemeGtk::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* styl
 {
     style->setBoxShadow(0);
 }
+
+// These values have been copied from RenderThemeChromiumSkia.cpp
+static const int progressActivityBlocks = 5;
+static const int progressAnimationFrames = 10;
+static const double progressAnimationInterval = 0.125;
+double RenderThemeGtk::animationRepeatIntervalForProgressBar(RenderProgress*) const
+{
+    return progressAnimationInterval;
+}
+
+double RenderThemeGtk::animationDurationForProgressBar(RenderProgress*) const
+{
+    return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth;
+}
+
+IntRect RenderThemeGtk::calculateProgressRect(RenderObject* renderObject, const IntRect& fullBarRect)
+{
+    IntRect progressRect(fullBarRect);
+    RenderProgress* renderProgress = toRenderProgress(renderObject);
+    if (renderProgress->isDeterminate()) {
+        int progressWidth = progressRect.width() * renderProgress->position();
+        if (renderObject->style()->direction() == RTL)
+            progressRect.setX(progressRect.x() + progressRect.width() - progressWidth);
+        progressRect.setWidth(progressWidth);
+        return progressRect;
+    }
+
+    double animationProgress = renderProgress->animationProgress();
+
+    // Never let the progress rect shrink smaller than 2 pixels.
+    int newWidth = max(2, progressRect.width() / progressActivityBlocks);
+    int movableWidth = progressRect.width() - newWidth;
+    progressRect.setWidth(newWidth);
+
+    // We want the first 0.5 units of the animation progress to represent the
+    // forward motion and the second 0.5 units to represent the backward motion,
+    // thus we multiply by two here to get the full sweep of the progress bar with
+    // each direction.
+    if (animationProgress < 0.5)
+        progressRect.setX(progressRect.x() + (animationProgress * 2 * movableWidth));
+    else
+        progressRect.setX(progressRect.x() + ((1.0 - animationProgress) * 2 * movableWidth));
+    return progressRect;
+}
 #endif
 
 }