1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsScrollBoxObject.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,330 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsCOMPtr.h" 1.10 +#include "nsIScrollBoxObject.h" 1.11 +#include "nsBoxObject.h" 1.12 +#include "nsIPresShell.h" 1.13 +#include "nsIContent.h" 1.14 +#include "nsIDOMElement.h" 1.15 +#include "nsPresContext.h" 1.16 +#include "nsIFrame.h" 1.17 +#include "nsIScrollableFrame.h" 1.18 + 1.19 +using namespace mozilla; 1.20 + 1.21 +class nsScrollBoxObject : public nsIScrollBoxObject, public nsBoxObject 1.22 +{ 1.23 +public: 1.24 + NS_DECL_ISUPPORTS_INHERITED 1.25 + NS_DECL_NSISCROLLBOXOBJECT 1.26 + 1.27 + nsScrollBoxObject(); 1.28 + virtual ~nsScrollBoxObject(); 1.29 + 1.30 + virtual nsIScrollableFrame* GetScrollFrame() { 1.31 + return do_QueryFrame(GetFrame(false)); 1.32 + } 1.33 + 1.34 + /* additional members */ 1.35 +}; 1.36 + 1.37 +/* Implementation file */ 1.38 + 1.39 +NS_INTERFACE_MAP_BEGIN(nsScrollBoxObject) 1.40 + NS_INTERFACE_MAP_ENTRY(nsIScrollBoxObject) 1.41 +NS_INTERFACE_MAP_END_INHERITING(nsBoxObject) 1.42 + 1.43 +NS_IMPL_ADDREF_INHERITED(nsScrollBoxObject, nsBoxObject) 1.44 +NS_IMPL_RELEASE_INHERITED(nsScrollBoxObject, nsBoxObject) 1.45 + 1.46 +nsScrollBoxObject::nsScrollBoxObject() 1.47 +{ 1.48 + /* member initializers and constructor code */ 1.49 +} 1.50 + 1.51 +nsScrollBoxObject::~nsScrollBoxObject() 1.52 +{ 1.53 + /* destructor code */ 1.54 +} 1.55 + 1.56 +/* void scrollTo (in long x, in long y); */ 1.57 +NS_IMETHODIMP nsScrollBoxObject::ScrollTo(int32_t x, int32_t y) 1.58 +{ 1.59 + nsIScrollableFrame* sf = GetScrollFrame(); 1.60 + if (!sf) 1.61 + return NS_ERROR_FAILURE; 1.62 + sf->ScrollToCSSPixels(CSSIntPoint(x, y)); 1.63 + return NS_OK; 1.64 +} 1.65 + 1.66 +/* void scrollBy (in long dx, in long dy); */ 1.67 +NS_IMETHODIMP nsScrollBoxObject::ScrollBy(int32_t dx, int32_t dy) 1.68 +{ 1.69 + int32_t x, y; 1.70 + nsresult rv = GetPosition(&x, &y); 1.71 + if (NS_FAILED(rv)) 1.72 + return rv; 1.73 + 1.74 + return ScrollTo(x + dx, y + dy); 1.75 +} 1.76 + 1.77 +/* void scrollByLine (in long dlines); */ 1.78 +NS_IMETHODIMP nsScrollBoxObject::ScrollByLine(int32_t dlines) 1.79 +{ 1.80 + nsIScrollableFrame* sf = GetScrollFrame(); 1.81 + if (!sf) 1.82 + return NS_ERROR_FAILURE; 1.83 + 1.84 + sf->ScrollBy(nsIntPoint(0, dlines), nsIScrollableFrame::LINES, 1.85 + nsIScrollableFrame::SMOOTH); 1.86 + return NS_OK; 1.87 +} 1.88 + 1.89 +// XUL <scrollbox> elements have a single box child element. 1.90 +// Get a pointer to that box. 1.91 +// Note that now that the <scrollbox> is just a regular box 1.92 +// with 'overflow:hidden', the boxobject's frame is an nsXULScrollFrame, 1.93 +// the <scrollbox>'s box frame is the scrollframe's "scrolled frame", and 1.94 +// the <scrollbox>'s child box is a child of that. 1.95 +static nsIFrame* GetScrolledBox(nsBoxObject* aScrollBox) { 1.96 + nsIFrame* frame = aScrollBox->GetFrame(false); 1.97 + if (!frame) 1.98 + return nullptr; 1.99 + nsIScrollableFrame* scrollFrame = do_QueryFrame(frame); 1.100 + if (!scrollFrame) { 1.101 + NS_WARNING("nsIScrollBoxObject attached to something that's not a scroll frame!"); 1.102 + return nullptr; 1.103 + } 1.104 + nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame(); 1.105 + if (!scrolledFrame) 1.106 + return nullptr; 1.107 + return scrolledFrame->GetChildBox(); 1.108 +} 1.109 + 1.110 +/* void scrollByIndex (in long dindexes); */ 1.111 +NS_IMETHODIMP nsScrollBoxObject::ScrollByIndex(int32_t dindexes) 1.112 +{ 1.113 + nsIScrollableFrame* sf = GetScrollFrame(); 1.114 + if (!sf) 1.115 + return NS_ERROR_FAILURE; 1.116 + nsIFrame* scrolledBox = GetScrolledBox(this); 1.117 + if (!scrolledBox) 1.118 + return NS_ERROR_FAILURE; 1.119 + 1.120 + nsRect rect; 1.121 + 1.122 + // now get the scrolled boxes first child. 1.123 + nsIFrame* child = scrolledBox->GetChildBox(); 1.124 + 1.125 + bool horiz = scrolledBox->IsHorizontal(); 1.126 + nsPoint cp = sf->GetScrollPosition(); 1.127 + nscoord diff = 0; 1.128 + int32_t curIndex = 0; 1.129 + bool isLTR = scrolledBox->IsNormalDirection(); 1.130 + 1.131 + int32_t frameWidth = 0; 1.132 + if (!isLTR && horiz) { 1.133 + GetWidth(&frameWidth); 1.134 + nsCOMPtr<nsIPresShell> shell = GetPresShell(false); 1.135 + if (!shell) { 1.136 + return NS_ERROR_UNEXPECTED; 1.137 + } 1.138 + frameWidth = nsPresContext::CSSPixelsToAppUnits(frameWidth); 1.139 + } 1.140 + 1.141 + // first find out what index we are currently at 1.142 + while(child) { 1.143 + rect = child->GetRect(); 1.144 + if (horiz) { 1.145 + // In the left-to-right case we break from the loop when the center of 1.146 + // the current child rect is greater than the scrolled position of 1.147 + // the left edge of the scrollbox 1.148 + // In the right-to-left case we break when the center of the current 1.149 + // child rect is less than the scrolled position of the right edge of 1.150 + // the scrollbox. 1.151 + diff = rect.x + rect.width/2; // use the center, to avoid rounding errors 1.152 + if ((isLTR && diff > cp.x) || 1.153 + (!isLTR && diff < cp.x + frameWidth)) { 1.154 + break; 1.155 + } 1.156 + } else { 1.157 + diff = rect.y + rect.height/2;// use the center, to avoid rounding errors 1.158 + if (diff > cp.y) { 1.159 + break; 1.160 + } 1.161 + } 1.162 + child = child->GetNextBox(); 1.163 + curIndex++; 1.164 + } 1.165 + 1.166 + int32_t count = 0; 1.167 + 1.168 + if (dindexes == 0) 1.169 + return NS_OK; 1.170 + 1.171 + if (dindexes > 0) { 1.172 + while(child) { 1.173 + child = child->GetNextBox(); 1.174 + if (child) 1.175 + rect = child->GetRect(); 1.176 + count++; 1.177 + if (count >= dindexes) 1.178 + break; 1.179 + } 1.180 + 1.181 + } else if (dindexes < 0) { 1.182 + child = scrolledBox->GetChildBox(); 1.183 + while(child) { 1.184 + rect = child->GetRect(); 1.185 + if (count >= curIndex + dindexes) 1.186 + break; 1.187 + 1.188 + count++; 1.189 + child = child->GetNextBox(); 1.190 + 1.191 + } 1.192 + } 1.193 + 1.194 + nscoord csspixel = nsPresContext::CSSPixelsToAppUnits(1); 1.195 + if (horiz) { 1.196 + // In the left-to-right case we scroll so that the left edge of the 1.197 + // selected child is scrolled to the left edge of the scrollbox. 1.198 + // In the right-to-left case we scroll so that the right edge of the 1.199 + // selected child is scrolled to the right edge of the scrollbox. 1.200 + 1.201 + nsPoint pt(isLTR ? rect.x : rect.x + rect.width - frameWidth, 1.202 + cp.y); 1.203 + 1.204 + // Use a destination range that ensures the left edge (or right edge, 1.205 + // for RTL) will indeed be visible. Also ensure that the top edge 1.206 + // is visible. 1.207 + nsRect range(pt.x, pt.y, csspixel, 0); 1.208 + if (isLTR) { 1.209 + range.x -= csspixel; 1.210 + } 1.211 + sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range); 1.212 + } else { 1.213 + // Use a destination range that ensures the top edge will be visible. 1.214 + nsRect range(cp.x, rect.y - csspixel, 0, csspixel); 1.215 + sf->ScrollTo(nsPoint(cp.x, rect.y), nsIScrollableFrame::INSTANT, &range); 1.216 + } 1.217 + 1.218 + return NS_OK; 1.219 +} 1.220 + 1.221 +/* void scrollToLine (in long line); */ 1.222 +NS_IMETHODIMP nsScrollBoxObject::ScrollToLine(int32_t line) 1.223 +{ 1.224 + nsIScrollableFrame* sf = GetScrollFrame(); 1.225 + if (!sf) 1.226 + return NS_ERROR_FAILURE; 1.227 + 1.228 + nscoord y = sf->GetLineScrollAmount().height * line; 1.229 + nsRect range(0, y - nsPresContext::CSSPixelsToAppUnits(1), 1.230 + 0, nsPresContext::CSSPixelsToAppUnits(1)); 1.231 + sf->ScrollTo(nsPoint(0, y), nsIScrollableFrame::INSTANT, &range); 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +/* void scrollToElement (in nsIDOMElement child); */ 1.236 +NS_IMETHODIMP nsScrollBoxObject::ScrollToElement(nsIDOMElement *child) 1.237 +{ 1.238 + NS_ENSURE_ARG_POINTER(child); 1.239 + 1.240 + nsCOMPtr<nsIPresShell> shell = GetPresShell(false); 1.241 + if (!shell) { 1.242 + return NS_ERROR_UNEXPECTED; 1.243 + } 1.244 + 1.245 + nsCOMPtr<nsIContent> content = do_QueryInterface(child); 1.246 + shell->ScrollContentIntoView(content, 1.247 + nsIPresShell::ScrollAxis( 1.248 + nsIPresShell::SCROLL_TOP, 1.249 + nsIPresShell::SCROLL_ALWAYS), 1.250 + nsIPresShell::ScrollAxis( 1.251 + nsIPresShell::SCROLL_LEFT, 1.252 + nsIPresShell::SCROLL_ALWAYS), 1.253 + nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY | 1.254 + nsIPresShell::SCROLL_OVERFLOW_HIDDEN); 1.255 + return NS_OK; 1.256 +} 1.257 + 1.258 +/* void scrollToIndex (in long index); */ 1.259 +NS_IMETHODIMP nsScrollBoxObject::ScrollToIndex(int32_t index) 1.260 +{ 1.261 + return NS_ERROR_NOT_IMPLEMENTED; 1.262 +} 1.263 + 1.264 +/* void getPosition (out long x, out long y); */ 1.265 +NS_IMETHODIMP nsScrollBoxObject::GetPosition(int32_t *x, int32_t *y) 1.266 +{ 1.267 + nsIScrollableFrame* sf = GetScrollFrame(); 1.268 + if (!sf) 1.269 + return NS_ERROR_FAILURE; 1.270 + 1.271 + CSSIntPoint pt = sf->GetScrollPositionCSSPixels(); 1.272 + *x = pt.x; 1.273 + *y = pt.y; 1.274 + 1.275 + return NS_OK; 1.276 +} 1.277 + 1.278 +/* void getScrolledSize (out long width, out long height); */ 1.279 +NS_IMETHODIMP nsScrollBoxObject::GetScrolledSize(int32_t *width, int32_t *height) 1.280 +{ 1.281 + nsIFrame* scrolledBox = GetScrolledBox(this); 1.282 + if (!scrolledBox) 1.283 + return NS_ERROR_FAILURE; 1.284 + 1.285 + nsRect scrollRect = scrolledBox->GetRect(); 1.286 + 1.287 + *width = nsPresContext::AppUnitsToIntCSSPixels(scrollRect.width); 1.288 + *height = nsPresContext::AppUnitsToIntCSSPixels(scrollRect.height); 1.289 + 1.290 + return NS_OK; 1.291 +} 1.292 + 1.293 +/* void ensureElementIsVisible (in nsIDOMElement child); */ 1.294 +NS_IMETHODIMP nsScrollBoxObject::EnsureElementIsVisible(nsIDOMElement *child) 1.295 +{ 1.296 + NS_ENSURE_ARG_POINTER(child); 1.297 + 1.298 + nsCOMPtr<nsIPresShell> shell = GetPresShell(false); 1.299 + if (!shell) { 1.300 + return NS_ERROR_UNEXPECTED; 1.301 + } 1.302 + 1.303 + nsCOMPtr<nsIContent> content = do_QueryInterface(child); 1.304 + shell->ScrollContentIntoView(content, 1.305 + nsIPresShell::ScrollAxis(), 1.306 + nsIPresShell::ScrollAxis(), 1.307 + nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY | 1.308 + nsIPresShell::SCROLL_OVERFLOW_HIDDEN); 1.309 + return NS_OK; 1.310 +} 1.311 + 1.312 +/* void ensureIndexIsVisible (in long index); */ 1.313 +NS_IMETHODIMP nsScrollBoxObject::EnsureIndexIsVisible(int32_t index) 1.314 +{ 1.315 + return NS_ERROR_NOT_IMPLEMENTED; 1.316 +} 1.317 + 1.318 +/* void ensureLineIsVisible (in long line); */ 1.319 +NS_IMETHODIMP nsScrollBoxObject::EnsureLineIsVisible(int32_t line) 1.320 +{ 1.321 + return NS_ERROR_NOT_IMPLEMENTED; 1.322 +} 1.323 + 1.324 +nsresult 1.325 +NS_NewScrollBoxObject(nsIBoxObject** aResult) 1.326 +{ 1.327 + *aResult = new nsScrollBoxObject; 1.328 + if (!*aResult) 1.329 + return NS_ERROR_OUT_OF_MEMORY; 1.330 + NS_ADDREF(*aResult); 1.331 + return NS_OK; 1.332 +} 1.333 +