diff options
author | Kristian Monsen <kristianm@google.com> | 2010-09-08 12:18:00 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2010-09-11 12:08:58 +0100 |
commit | 5ddde30071f639962dd557c453f2ad01f8f0fd00 (patch) | |
tree | 775803c4ab35af50aa5f5472cd1fb95fe9d5152d /WebCore/platform/gtk/ScrollbarThemeGtk.cpp | |
parent | 3e63d9b33b753ca86d0765d1b3d711114ba9e34f (diff) | |
download | external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.zip external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.tar.gz external_webkit-5ddde30071f639962dd557c453f2ad01f8f0fd00.tar.bz2 |
Merge WebKit at r66666 : Initial merge by git.
Change-Id: I57dedeb49859adc9c539e760f0e749768c66626f
Diffstat (limited to 'WebCore/platform/gtk/ScrollbarThemeGtk.cpp')
-rw-r--r-- | WebCore/platform/gtk/ScrollbarThemeGtk.cpp | 323 |
1 files changed, 316 insertions, 7 deletions
diff --git a/WebCore/platform/gtk/ScrollbarThemeGtk.cpp b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp index fee2c70..b6efe54 100644 --- a/WebCore/platform/gtk/ScrollbarThemeGtk.cpp +++ b/WebCore/platform/gtk/ScrollbarThemeGtk.cpp @@ -26,30 +26,339 @@ #include "config.h" #include "ScrollbarThemeGtk.h" +#include "PlatformMouseEvent.h" +#include "RenderThemeGtk.h" +#include "ScrollView.h" +#include "Scrollbar.h" #include "gtkdrawing.h" #include <gtk/gtk.h> namespace WebCore { +static HashSet<Scrollbar*>* gScrollbars; +static void gtkStyleSetCallback(GtkWidget*, GtkStyle*, ScrollbarThemeGtk*); + ScrollbarTheme* ScrollbarTheme::nativeTheme() { static ScrollbarThemeGtk theme; return &theme; } +ScrollbarThemeGtk::ScrollbarThemeGtk() +{ + updateThemeProperties(); + g_signal_connect(static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->gtkScrollbar(), + "style-set", G_CALLBACK(gtkStyleSetCallback), this); +} + ScrollbarThemeGtk::~ScrollbarThemeGtk() { } -int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize controlSize) +void ScrollbarThemeGtk::registerScrollbar(Scrollbar* scrollbar) +{ + if (!gScrollbars) + gScrollbars = new HashSet<Scrollbar*>; + gScrollbars->add(scrollbar); +} + +void ScrollbarThemeGtk::unregisterScrollbar(Scrollbar* scrollbar) +{ + gScrollbars->remove(scrollbar); + if (gScrollbars->isEmpty()) { + delete gScrollbars; + gScrollbars = 0; + } +} + +void ScrollbarThemeGtk::updateThemeProperties() +{ + MozGtkScrollbarMetrics metrics; + moz_gtk_get_scrollbar_metrics(&metrics); + + m_thumbFatness = metrics.slider_width; + m_troughBorderWidth = metrics.trough_border; + m_stepperSize = metrics.stepper_size; + m_stepperSpacing = metrics.stepper_spacing; + m_minThumbLength = metrics.min_slider_size; + m_troughUnderSteppers = metrics.trough_under_steppers; + + if (!gScrollbars) + return; + + // Update the thickness of every interior frame scrollbar widget. The + // platform-independent scrollbar them code isn't yet smart enough to get + // this information when it paints. + HashSet<Scrollbar*>::iterator end = gScrollbars->end(); + for (HashSet<Scrollbar*>::iterator it = gScrollbars->begin(); it != end; ++it) { + Scrollbar* scrollbar = (*it); + + // Top-level scrollbar i.e. scrollbars who have a parent ScrollView + // with no parent are native, and thus do not need to be resized. + if (!scrollbar->parent() || !scrollbar->parent()->parent()) + return; + + int thickness = scrollbarThickness(scrollbar->controlSize()); + if (scrollbar->orientation() == HorizontalScrollbar) + scrollbar->setFrameRect(IntRect(0, scrollbar->parent()->height() - thickness, scrollbar->width(), thickness)); + else + scrollbar->setFrameRect(IntRect(scrollbar->parent()->width() - thickness, 0, thickness, scrollbar->height())); + } +} + +static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, ScrollbarThemeGtk* scrollbarTheme) +{ + scrollbarTheme->updateThemeProperties(); +} + +bool ScrollbarThemeGtk::hasThumb(Scrollbar* scrollbar) +{ + // This method is just called as a paint-time optimization to see if + // painting the thumb can be skipped. We don't have to be exact here. + return thumbLength(scrollbar) > 0; +} + +IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + // We do not support multiple steppers per end yet. + if (part == BackButtonEndPart) + return IntRect(); + + IntSize size = buttonSize(scrollbar); + return IntRect(scrollbar->x() + m_troughBorderWidth, scrollbar->y() + m_troughBorderWidth, size.width(), size.height()); +} + +IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + // We do not support multiple steppers per end yet. + if (part == ForwardButtonStartPart) + return IntRect(); + + IntSize size = buttonSize(scrollbar); + int x, y; + if (scrollbar->orientation() == HorizontalScrollbar) { + x = scrollbar->x() + scrollbar->width() - size.width() - m_troughBorderWidth; + y = scrollbar->y() + m_troughBorderWidth; + } else { + x = scrollbar->x() + m_troughBorderWidth; + y = scrollbar->y() + scrollbar->height() - size.height() - m_troughBorderWidth; + } + return IntRect(x, y, size.width(), size.height()); +} + +IntRect ScrollbarThemeGtk::trackRect(Scrollbar* scrollbar, bool) +{ + // The padding along the thumb movement axis (from outside to in) + // is the size of trough border plus the size of the stepper (button) + // plus the size of stepper spacing (the space between the stepper and + // the place where the thumb stops). There is often no stepper spacing. + int movementAxisPadding = m_troughBorderWidth + m_stepperSize + m_stepperSpacing; + + // The fatness of the scrollbar on the non-movement axis. + int thickness = scrollbarThickness(scrollbar->controlSize()); + + if (scrollbar->orientation() == HorizontalScrollbar) { + // Once the scrollbar becomes smaller than the natural size of the + // two buttons, the track disappears. + if (scrollbar->width() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x() + movementAxisPadding, scrollbar->y(), scrollbar->width() - (2 * movementAxisPadding), thickness); + } + + if (scrollbar->height() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x(), scrollbar->y() + movementAxisPadding, thickness, scrollbar->height() - (2 * movementAxisPadding)); +} + +void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) +{ + GtkWidgetState state; + state.focused = FALSE; + state.isDefault = FALSE; + state.canDefault = FALSE; + state.disabled = FALSE; + state.active = FALSE; + state.inHover = FALSE; + + // Paint the track background. If the trough-under-steppers property is true, this + // should be the full size of the scrollbar, but if is false, it should only be the + // track rect. + IntRect fullScrollbarRect = rect; + if (m_troughUnderSteppers) + fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); + + GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_TRACK_VERTICAL : MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL; + static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->paintMozillaGtkWidget(type, context, fullScrollbarRect, &state, 0); +} + +void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar) +{ + GtkWidgetState state; + state.focused = FALSE; + state.isDefault = FALSE; + state.canDefault = FALSE; + state.disabled = FALSE; + state.active = TRUE; + state.inHover = FALSE; + + IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); + static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->paintMozillaGtkWidget(MOZ_GTK_SCROLLED_WINDOW, context, fullScrollbarRect, &state, 0); +} + +void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) +{ + GtkWidgetState state; + state.focused = FALSE; + state.isDefault = FALSE; + state.canDefault = FALSE; + state.disabled = FALSE; + state.active = scrollbar->pressedPart() == ThumbPart; + state.inHover = scrollbar->hoveredPart() == ThumbPart; + state.maxpos = scrollbar->maximum(); + state.curpos = scrollbar->currentPos(); + + GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_THUMB_VERTICAL : MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL; + static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->paintMozillaGtkWidget(type, context, rect, &state, 0); +} + +IntRect ScrollbarThemeGtk::thumbRect(Scrollbar* scrollbar, const IntRect& unconstrainedTrackRect) +{ + IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, unconstrainedTrackRect); + int thumbPos = thumbPosition(scrollbar); + if (scrollbar->orientation() == HorizontalScrollbar) + return IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - m_thumbFatness) / 2, thumbLength(scrollbar), m_thumbFatness); + + // VerticalScrollbar + return IntRect(trackRect.x() + (trackRect.width() - m_thumbFatness) / 2, trackRect.y() + thumbPos, m_thumbFatness, thumbLength(scrollbar)); +} + +bool ScrollbarThemeGtk::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect) { - static int size; - if (!size) { - MozGtkScrollbarMetrics metrics; - moz_gtk_get_scrollbar_metrics(&metrics); - size = metrics.slider_width; + // Create the ScrollbarControlPartMask based on the damageRect + ScrollbarControlPartMask scrollMask = NoPart; + + IntRect backButtonStartPaintRect; + IntRect backButtonEndPaintRect; + IntRect forwardButtonStartPaintRect; + IntRect forwardButtonEndPaintRect; + if (hasButtons(scrollbar)) { + backButtonStartPaintRect = backButtonRect(scrollbar, BackButtonStartPart, true); + if (damageRect.intersects(backButtonStartPaintRect)) + scrollMask |= BackButtonStartPart; + backButtonEndPaintRect = backButtonRect(scrollbar, BackButtonEndPart, true); + if (damageRect.intersects(backButtonEndPaintRect)) + scrollMask |= BackButtonEndPart; + forwardButtonStartPaintRect = forwardButtonRect(scrollbar, ForwardButtonStartPart, true); + if (damageRect.intersects(forwardButtonStartPaintRect)) + scrollMask |= ForwardButtonStartPart; + forwardButtonEndPaintRect = forwardButtonRect(scrollbar, ForwardButtonEndPart, true); + if (damageRect.intersects(forwardButtonEndPaintRect)) + scrollMask |= ForwardButtonEndPart; + } + + IntRect trackPaintRect = trackRect(scrollbar, true); + if (damageRect.intersects(trackPaintRect)) + scrollMask |= TrackBGPart; + + if (m_troughUnderSteppers && (scrollMask & BackButtonStartPart + || scrollMask & BackButtonEndPart + || scrollMask & ForwardButtonStartPart + || scrollMask & ForwardButtonEndPart)) + scrollMask |= TrackBGPart; + + bool thumbPresent = hasThumb(scrollbar); + IntRect currentThumbRect; + if (thumbPresent) { + IntRect track = trackRect(scrollbar, false); + currentThumbRect = thumbRect(scrollbar, track); + if (damageRect.intersects(currentThumbRect)) + scrollMask |= ThumbPart; } - return size; + + // Paint the scrollbar background (only used by custom CSS scrollbars). + paintScrollbarBackground(graphicsContext, scrollbar); + + if (scrollMask & TrackBGPart) + paintTrackBackground(graphicsContext, scrollbar, trackPaintRect); + + // Paint the back and forward buttons. + if (scrollMask & BackButtonStartPart) + paintButton(graphicsContext, scrollbar, backButtonStartPaintRect, BackButtonStartPart); + if (scrollMask & BackButtonEndPart) + paintButton(graphicsContext, scrollbar, backButtonEndPaintRect, BackButtonEndPart); + if (scrollMask & ForwardButtonStartPart) + paintButton(graphicsContext, scrollbar, forwardButtonStartPaintRect, ForwardButtonStartPart); + if (scrollMask & ForwardButtonEndPart) + paintButton(graphicsContext, scrollbar, forwardButtonEndPaintRect, ForwardButtonEndPart); + + // Paint the thumb. + if (scrollMask & ThumbPart) + paintThumb(graphicsContext, scrollbar, currentThumbRect); + + return true; +} + +void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) +{ + int flags = 0; + if (scrollbar->orientation() == VerticalScrollbar) + flags |= MOZ_GTK_STEPPER_VERTICAL; + + if (part == ForwardButtonEndPart) { + flags |= MOZ_GTK_STEPPER_DOWN; + flags |= MOZ_GTK_STEPPER_BOTTOM; + } + + GtkWidgetState state; + state.focused = TRUE; + state.isDefault = TRUE; + state.canDefault = TRUE; + + if ((BackButtonStartPart == part && scrollbar->currentPos()) + || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())) { + state.disabled = FALSE; + state.active = part == scrollbar->pressedPart(); + state.inHover = part == scrollbar->hoveredPart(); + } else { + state.disabled = TRUE; + state.active = FALSE; + state.inHover = FALSE; + } + + static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->paintMozillaGtkWidget(MOZ_GTK_SCROLLBAR_BUTTON, context, rect, &state, flags); +} + +void ScrollbarThemeGtk::paintScrollCorner(ScrollView* view, GraphicsContext* context, const IntRect& cornerRect) +{ + // ScrollbarThemeComposite::paintScrollCorner incorrectly assumes that the + // ScrollView is a FrameView (see FramelessScrollView), so we cannot let + // that code run. For FrameView's this is correct since we don't do custom + // scrollbar corner rendering, which ScrollbarThemeComposite supports. + ScrollbarTheme::paintScrollCorner(view, context, cornerRect); +} + +bool ScrollbarThemeGtk::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& event) +{ + return (event.shiftKey() && event.button() == LeftButton) || (event.button() == MiddleButton); +} + +int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize) +{ + return m_thumbFatness + (m_troughBorderWidth * 2); +} + +IntSize ScrollbarThemeGtk::buttonSize(Scrollbar* scrollbar) +{ + if (scrollbar->orientation() == VerticalScrollbar) + return IntSize(m_thumbFatness, m_stepperSize); + + // HorizontalScrollbar + return IntSize(m_stepperSize, m_thumbFatness); +} + +int ScrollbarThemeGtk::minimumThumbLength(Scrollbar* scrollbar) +{ + return m_minThumbLength; } } |