1/* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "RenderScrollbarPart.h" 28 29#include "PaintInfo.h" 30#include "RenderScrollbar.h" 31#include "RenderScrollbarTheme.h" 32#include "RenderView.h" 33#include <wtf/StackStats.h> 34 35namespace WebCore { 36 37RenderScrollbarPart::RenderScrollbarPart(Document& document, PassRef<RenderStyle> style, RenderScrollbar* scrollbar, ScrollbarPart part) 38 : RenderBlock(document, WTF::move(style), 0) 39 , m_scrollbar(scrollbar) 40 , m_part(part) 41{ 42} 43 44RenderScrollbarPart::~RenderScrollbarPart() 45{ 46} 47 48void RenderScrollbarPart::layout() 49{ 50 StackStats::LayoutCheckPoint layoutCheckPoint; 51 setLocation(LayoutPoint()); // We don't worry about positioning ourselves. We're just determining our minimum width/height. 52 if (m_scrollbar->orientation() == HorizontalScrollbar) 53 layoutHorizontalPart(); 54 else 55 layoutVerticalPart(); 56 57 clearNeedsLayout(); 58} 59 60void RenderScrollbarPart::layoutHorizontalPart() 61{ 62 if (m_part == ScrollbarBGPart) { 63 setWidth(m_scrollbar->width()); 64 computeScrollbarHeight(); 65 } else { 66 computeScrollbarWidth(); 67 setHeight(m_scrollbar->height()); 68 } 69} 70 71void RenderScrollbarPart::layoutVerticalPart() 72{ 73 if (m_part == ScrollbarBGPart) { 74 computeScrollbarWidth(); 75 setHeight(m_scrollbar->height()); 76 } else { 77 setWidth(m_scrollbar->width()); 78 computeScrollbarHeight(); 79 } 80} 81 82static int calcScrollbarThicknessUsing(SizeType sizeType, const Length& length, int containingLength) 83{ 84 if (!length.isIntrinsicOrAuto() || (sizeType == MinSize && length.isAuto())) 85 return minimumValueForLength(length, containingLength); 86 return ScrollbarTheme::theme()->scrollbarThickness(); 87} 88 89void RenderScrollbarPart::computeScrollbarWidth() 90{ 91 if (!m_scrollbar->owningRenderer()) 92 return; 93 // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. 94 // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. 95 int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->style().borderLeftWidth() - m_scrollbar->owningRenderer()->style().borderRightWidth(); 96 int w = calcScrollbarThicknessUsing(MainOrPreferredSize, style().width(), visibleSize); 97 int minWidth = calcScrollbarThicknessUsing(MinSize, style().minWidth(), visibleSize); 98 int maxWidth = style().maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(MaxSize, style().maxWidth(), visibleSize); 99 setWidth(std::max(minWidth, std::min(maxWidth, w))); 100 101 // Buttons and track pieces can all have margins along the axis of the scrollbar. 102 m_marginBox.setLeft(minimumValueForLength(style().marginLeft(), visibleSize)); 103 m_marginBox.setRight(minimumValueForLength(style().marginRight(), visibleSize)); 104} 105 106void RenderScrollbarPart::computeScrollbarHeight() 107{ 108 if (!m_scrollbar->owningRenderer()) 109 return; 110 // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. 111 // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. 112 int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->style().borderTopWidth() - m_scrollbar->owningRenderer()->style().borderBottomWidth(); 113 int h = calcScrollbarThicknessUsing(MainOrPreferredSize, style().height(), visibleSize); 114 int minHeight = calcScrollbarThicknessUsing(MinSize, style().minHeight(), visibleSize); 115 int maxHeight = style().maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(MaxSize, style().maxHeight(), visibleSize); 116 setHeight(std::max(minHeight, std::min(maxHeight, h))); 117 118 // Buttons and track pieces can all have margins along the axis of the scrollbar. 119 m_marginBox.setTop(minimumValueForLength(style().marginTop(), visibleSize)); 120 m_marginBox.setBottom(minimumValueForLength(style().marginBottom(), visibleSize)); 121} 122 123void RenderScrollbarPart::computePreferredLogicalWidths() 124{ 125 if (!preferredLogicalWidthsDirty()) 126 return; 127 128 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0; 129 130 setPreferredLogicalWidthsDirty(false); 131} 132 133void RenderScrollbarPart::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 134{ 135 RenderBlock::styleDidChange(diff, oldStyle); 136 setInline(false); 137 clearPositionedState(); 138 setFloating(false); 139 setHasOverflowClip(false); 140 if (oldStyle && m_scrollbar && m_part != NoPart && diff >= StyleDifferenceRepaint) 141 m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part); 142} 143 144void RenderScrollbarPart::imageChanged(WrappedImagePtr image, const IntRect* rect) 145{ 146 if (m_scrollbar && m_part != NoPart) 147 m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part); 148 else { 149 if (view().frameView().isFrameViewScrollCorner(this)) { 150 view().frameView().invalidateScrollCorner(view().frameView().scrollCornerRect()); 151 return; 152 } 153 154 RenderBlock::imageChanged(image, rect); 155 } 156} 157 158void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, const LayoutRect& rect) 159{ 160 // Make sure our dimensions match the rect. 161 setLocation(rect.location() - toLayoutSize(paintOffset)); 162 setWidth(rect.width()); 163 setHeight(rect.height()); 164 165 if (graphicsContext->paintingDisabled() || !style().opacity()) 166 return; 167 168 // We don't use RenderLayers for scrollbar parts, so we need to handle opacity here. 169 // Opacity for ScrollbarBGPart is handled by RenderScrollbarTheme::willPaintScrollbar(). 170 bool needsTransparencyLayer = m_part != ScrollbarBGPart && style().opacity() < 1; 171 if (needsTransparencyLayer) { 172 graphicsContext->save(); 173 graphicsContext->clip(rect); 174 graphicsContext->beginTransparencyLayer(style().opacity()); 175 } 176 177 // Now do the paint. 178 PaintInfo paintInfo(graphicsContext, pixelSnappedIntRect(rect), PaintPhaseBlockBackground, PaintBehaviorNormal); 179 paint(paintInfo, paintOffset); 180 paintInfo.phase = PaintPhaseChildBlockBackgrounds; 181 paint(paintInfo, paintOffset); 182 paintInfo.phase = PaintPhaseFloat; 183 paint(paintInfo, paintOffset); 184 paintInfo.phase = PaintPhaseForeground; 185 paint(paintInfo, paintOffset); 186 paintInfo.phase = PaintPhaseOutline; 187 paint(paintInfo, paintOffset); 188 189 if (needsTransparencyLayer) { 190 graphicsContext->endTransparencyLayer(); 191 graphicsContext->restore(); 192 } 193} 194 195RenderBox* RenderScrollbarPart::rendererOwningScrollbar() const 196{ 197 if (!m_scrollbar) 198 return nullptr; 199 return m_scrollbar->owningRenderer(); 200} 201 202} 203