#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;
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);
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;
}
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);
return time / 2000.;
}
-static double getScreenDPI()
+double RenderThemeGtk::getScreenDPI()
{
// FIXME: Really this should be the widget's screen.
GdkScreen* screen = gdk_screen_get_default();
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;
}
{
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
}