IntRect ScrollbarThemeSafari::trackRect(Scrollbar& scrollbar, bool painting)
{
    if (painting || !hasButtons(scrollbar))
        return scrollbar.frameRect();
    
    IntRect result;
    int thickness = scrollbarThickness(scrollbar.controlSize());
    if (scrollbar.orientation() == HorizontalScrollbar) 
        return IntRect(scrollbar.x() + cButtonLength[scrollbar.controlSize()], scrollbar.y(), scrollbar.width() - 2 * cButtonLength[scrollbar.controlSize()], thickness);
    return IntRect(scrollbar.x(), scrollbar.y() + cButtonLength[scrollbar.controlSize()], thickness, scrollbar.height() - 2 * cButtonLength[scrollbar.controlSize()]);
}
IntRect ScrollbarThemeSafari::forwardButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool painting)
{
    IntRect result;
    
    // Windows just has single arrows.
    if (part == ForwardButtonStartPart)
        return result;

    int thickness = scrollbarThickness(scrollbar.controlSize());
    if (scrollbar.orientation() == HorizontalScrollbar)
        result = IntRect(scrollbar.x() + scrollbar.width() - cButtonLength[scrollbar.controlSize()], scrollbar.y(), cButtonLength[scrollbar.controlSize()], thickness);
    else
        result = IntRect(scrollbar.x(), scrollbar.y() + scrollbar.height() - cButtonLength[scrollbar.controlSize()], thickness, cButtonLength[scrollbar.controlSize()]);
    if (painting)
        return buttonRepaintRect(result, scrollbar.orientation(), scrollbar.controlSize(), false);
    return result;
}
IntRect ScrollbarThemeSafari::backButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool painting)
{
    IntRect result;

    // Windows just has single arrows.
    if (part == BackButtonEndPart)
        return result;

    int thickness = scrollbarThickness(scrollbar.controlSize());
    if (scrollbar.orientation() == HorizontalScrollbar)
        result = IntRect(scrollbar.x(), scrollbar.y(), cButtonLength[scrollbar.controlSize()], thickness);
    else
        result = IntRect(scrollbar.x(), scrollbar.y(), thickness, cButtonLength[scrollbar.controlSize()]);
    if (painting)
        return buttonRepaintRect(result, scrollbar.orientation(), scrollbar.controlSize(), true);
    return result;
}
void ScrollbarThemeSafari::paintTrackBackground(GraphicsContext& graphicsContext, Scrollbar& scrollbar, const IntRect& trackRect)
{
    if (!SafariThemeLibrary())
        return;
    NSControlSize size = scrollbar.controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize;
    ThemeControlState state = 0;
    if (scrollbar.isScrollableAreaActive())
        state |= ActiveState;
    if (hasButtons(scrollbar))
        state |= EnabledState;
    paintThemePart(scrollbar.orientation() == VerticalScrollbar ? VScrollTrackPart : HScrollTrackPart, graphicsContext.platformContext(), trackRect, size, state); 
}
bool ScrollbarThemeWin::shouldSnapBackToDragOrigin(Scrollbar& scrollbar, const PlatformMouseEvent& evt)
{
    // Find the rect within which we shouldn't snap, by expanding the track rect
    // in both dimensions.
    IntRect rect = trackRect(scrollbar);
    const bool horz = scrollbar.orientation() == HorizontalScrollbar;
    const int thickness = scrollbarThickness(scrollbar.controlSize());
    rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness);
    rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness);

    // Convert the event to local coordinates.
    IntPoint mousePosition = scrollbar.convertFromContainingWindow(evt.position());
    mousePosition.move(scrollbar.x(), scrollbar.y());

    // We should snap iff the event is outside our calculated rect.
    return !rect.contains(mousePosition);
}
void ScrollbarThemeSafari::paintButton(GraphicsContext& graphicsContext, Scrollbar& scrollbar, const IntRect& buttonRect, ScrollbarPart part)
{
    if (!SafariThemeLibrary())
        return;
    NSControlSize size = scrollbar.controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize;
    ThemeControlState state = 0;
    if (scrollbar.isScrollableAreaActive())
        state |= ActiveState;
    if (hasButtons(scrollbar))
        state |= EnabledState;
    if (scrollbar.pressedPart() == part)
        state |= PressedState;
    if (part == BackButtonStartPart)
        paintThemePart(scrollbar.orientation() == VerticalScrollbar ? ScrollUpArrowPart : ScrollLeftArrowPart, graphicsContext.platformContext(),
                       buttonRect, size, state);
    else if (part == ForwardButtonEndPart)
        paintThemePart(scrollbar.orientation() == VerticalScrollbar ? ScrollDownArrowPart : ScrollRightArrowPart, graphicsContext.platformContext(),
                       buttonRect, size, state);
}
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;
    m_hasForwardButtonStartPart = metrics.has_secondary_forward_stepper;
    m_hasBackButtonEndPart = metrics.has_secondary_backward_stepper;

    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()));
    }
}
int ScrollbarThemeSafari::minimumThumbLength(Scrollbar& scrollbar)
{
    return cThumbMinLength[scrollbar.controlSize()];
}
bool ScrollbarThemeSafari::hasThumb(Scrollbar& scrollbar)
{
    return scrollbar.enabled() && (scrollbar.orientation() == HorizontalScrollbar ? 
             scrollbar.width() : 
             scrollbar.height()) >= 2 * cButtonInset[scrollbar.controlSize()] + cThumbMinLength[scrollbar.controlSize()] + 1;
}
bool ScrollbarThemeSafari::hasButtons(Scrollbar& scrollbar)
{
    return scrollbar.enabled() && (scrollbar.orientation() == HorizontalScrollbar ? 
             scrollbar.width() : 
             scrollbar.height()) >= 2 * (cRealButtonLength[scrollbar.controlSize()] - cButtonHitInset[scrollbar.controlSize()]);
}