layout/xul/nsScrollBoxObject.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsCOMPtr.h"
michael@0 7 #include "nsIScrollBoxObject.h"
michael@0 8 #include "nsBoxObject.h"
michael@0 9 #include "nsIPresShell.h"
michael@0 10 #include "nsIContent.h"
michael@0 11 #include "nsIDOMElement.h"
michael@0 12 #include "nsPresContext.h"
michael@0 13 #include "nsIFrame.h"
michael@0 14 #include "nsIScrollableFrame.h"
michael@0 15
michael@0 16 using namespace mozilla;
michael@0 17
michael@0 18 class nsScrollBoxObject : public nsIScrollBoxObject, public nsBoxObject
michael@0 19 {
michael@0 20 public:
michael@0 21 NS_DECL_ISUPPORTS_INHERITED
michael@0 22 NS_DECL_NSISCROLLBOXOBJECT
michael@0 23
michael@0 24 nsScrollBoxObject();
michael@0 25 virtual ~nsScrollBoxObject();
michael@0 26
michael@0 27 virtual nsIScrollableFrame* GetScrollFrame() {
michael@0 28 return do_QueryFrame(GetFrame(false));
michael@0 29 }
michael@0 30
michael@0 31 /* additional members */
michael@0 32 };
michael@0 33
michael@0 34 /* Implementation file */
michael@0 35
michael@0 36 NS_INTERFACE_MAP_BEGIN(nsScrollBoxObject)
michael@0 37 NS_INTERFACE_MAP_ENTRY(nsIScrollBoxObject)
michael@0 38 NS_INTERFACE_MAP_END_INHERITING(nsBoxObject)
michael@0 39
michael@0 40 NS_IMPL_ADDREF_INHERITED(nsScrollBoxObject, nsBoxObject)
michael@0 41 NS_IMPL_RELEASE_INHERITED(nsScrollBoxObject, nsBoxObject)
michael@0 42
michael@0 43 nsScrollBoxObject::nsScrollBoxObject()
michael@0 44 {
michael@0 45 /* member initializers and constructor code */
michael@0 46 }
michael@0 47
michael@0 48 nsScrollBoxObject::~nsScrollBoxObject()
michael@0 49 {
michael@0 50 /* destructor code */
michael@0 51 }
michael@0 52
michael@0 53 /* void scrollTo (in long x, in long y); */
michael@0 54 NS_IMETHODIMP nsScrollBoxObject::ScrollTo(int32_t x, int32_t y)
michael@0 55 {
michael@0 56 nsIScrollableFrame* sf = GetScrollFrame();
michael@0 57 if (!sf)
michael@0 58 return NS_ERROR_FAILURE;
michael@0 59 sf->ScrollToCSSPixels(CSSIntPoint(x, y));
michael@0 60 return NS_OK;
michael@0 61 }
michael@0 62
michael@0 63 /* void scrollBy (in long dx, in long dy); */
michael@0 64 NS_IMETHODIMP nsScrollBoxObject::ScrollBy(int32_t dx, int32_t dy)
michael@0 65 {
michael@0 66 int32_t x, y;
michael@0 67 nsresult rv = GetPosition(&x, &y);
michael@0 68 if (NS_FAILED(rv))
michael@0 69 return rv;
michael@0 70
michael@0 71 return ScrollTo(x + dx, y + dy);
michael@0 72 }
michael@0 73
michael@0 74 /* void scrollByLine (in long dlines); */
michael@0 75 NS_IMETHODIMP nsScrollBoxObject::ScrollByLine(int32_t dlines)
michael@0 76 {
michael@0 77 nsIScrollableFrame* sf = GetScrollFrame();
michael@0 78 if (!sf)
michael@0 79 return NS_ERROR_FAILURE;
michael@0 80
michael@0 81 sf->ScrollBy(nsIntPoint(0, dlines), nsIScrollableFrame::LINES,
michael@0 82 nsIScrollableFrame::SMOOTH);
michael@0 83 return NS_OK;
michael@0 84 }
michael@0 85
michael@0 86 // XUL <scrollbox> elements have a single box child element.
michael@0 87 // Get a pointer to that box.
michael@0 88 // Note that now that the <scrollbox> is just a regular box
michael@0 89 // with 'overflow:hidden', the boxobject's frame is an nsXULScrollFrame,
michael@0 90 // the <scrollbox>'s box frame is the scrollframe's "scrolled frame", and
michael@0 91 // the <scrollbox>'s child box is a child of that.
michael@0 92 static nsIFrame* GetScrolledBox(nsBoxObject* aScrollBox) {
michael@0 93 nsIFrame* frame = aScrollBox->GetFrame(false);
michael@0 94 if (!frame)
michael@0 95 return nullptr;
michael@0 96 nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
michael@0 97 if (!scrollFrame) {
michael@0 98 NS_WARNING("nsIScrollBoxObject attached to something that's not a scroll frame!");
michael@0 99 return nullptr;
michael@0 100 }
michael@0 101 nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
michael@0 102 if (!scrolledFrame)
michael@0 103 return nullptr;
michael@0 104 return scrolledFrame->GetChildBox();
michael@0 105 }
michael@0 106
michael@0 107 /* void scrollByIndex (in long dindexes); */
michael@0 108 NS_IMETHODIMP nsScrollBoxObject::ScrollByIndex(int32_t dindexes)
michael@0 109 {
michael@0 110 nsIScrollableFrame* sf = GetScrollFrame();
michael@0 111 if (!sf)
michael@0 112 return NS_ERROR_FAILURE;
michael@0 113 nsIFrame* scrolledBox = GetScrolledBox(this);
michael@0 114 if (!scrolledBox)
michael@0 115 return NS_ERROR_FAILURE;
michael@0 116
michael@0 117 nsRect rect;
michael@0 118
michael@0 119 // now get the scrolled boxes first child.
michael@0 120 nsIFrame* child = scrolledBox->GetChildBox();
michael@0 121
michael@0 122 bool horiz = scrolledBox->IsHorizontal();
michael@0 123 nsPoint cp = sf->GetScrollPosition();
michael@0 124 nscoord diff = 0;
michael@0 125 int32_t curIndex = 0;
michael@0 126 bool isLTR = scrolledBox->IsNormalDirection();
michael@0 127
michael@0 128 int32_t frameWidth = 0;
michael@0 129 if (!isLTR && horiz) {
michael@0 130 GetWidth(&frameWidth);
michael@0 131 nsCOMPtr<nsIPresShell> shell = GetPresShell(false);
michael@0 132 if (!shell) {
michael@0 133 return NS_ERROR_UNEXPECTED;
michael@0 134 }
michael@0 135 frameWidth = nsPresContext::CSSPixelsToAppUnits(frameWidth);
michael@0 136 }
michael@0 137
michael@0 138 // first find out what index we are currently at
michael@0 139 while(child) {
michael@0 140 rect = child->GetRect();
michael@0 141 if (horiz) {
michael@0 142 // In the left-to-right case we break from the loop when the center of
michael@0 143 // the current child rect is greater than the scrolled position of
michael@0 144 // the left edge of the scrollbox
michael@0 145 // In the right-to-left case we break when the center of the current
michael@0 146 // child rect is less than the scrolled position of the right edge of
michael@0 147 // the scrollbox.
michael@0 148 diff = rect.x + rect.width/2; // use the center, to avoid rounding errors
michael@0 149 if ((isLTR && diff > cp.x) ||
michael@0 150 (!isLTR && diff < cp.x + frameWidth)) {
michael@0 151 break;
michael@0 152 }
michael@0 153 } else {
michael@0 154 diff = rect.y + rect.height/2;// use the center, to avoid rounding errors
michael@0 155 if (diff > cp.y) {
michael@0 156 break;
michael@0 157 }
michael@0 158 }
michael@0 159 child = child->GetNextBox();
michael@0 160 curIndex++;
michael@0 161 }
michael@0 162
michael@0 163 int32_t count = 0;
michael@0 164
michael@0 165 if (dindexes == 0)
michael@0 166 return NS_OK;
michael@0 167
michael@0 168 if (dindexes > 0) {
michael@0 169 while(child) {
michael@0 170 child = child->GetNextBox();
michael@0 171 if (child)
michael@0 172 rect = child->GetRect();
michael@0 173 count++;
michael@0 174 if (count >= dindexes)
michael@0 175 break;
michael@0 176 }
michael@0 177
michael@0 178 } else if (dindexes < 0) {
michael@0 179 child = scrolledBox->GetChildBox();
michael@0 180 while(child) {
michael@0 181 rect = child->GetRect();
michael@0 182 if (count >= curIndex + dindexes)
michael@0 183 break;
michael@0 184
michael@0 185 count++;
michael@0 186 child = child->GetNextBox();
michael@0 187
michael@0 188 }
michael@0 189 }
michael@0 190
michael@0 191 nscoord csspixel = nsPresContext::CSSPixelsToAppUnits(1);
michael@0 192 if (horiz) {
michael@0 193 // In the left-to-right case we scroll so that the left edge of the
michael@0 194 // selected child is scrolled to the left edge of the scrollbox.
michael@0 195 // In the right-to-left case we scroll so that the right edge of the
michael@0 196 // selected child is scrolled to the right edge of the scrollbox.
michael@0 197
michael@0 198 nsPoint pt(isLTR ? rect.x : rect.x + rect.width - frameWidth,
michael@0 199 cp.y);
michael@0 200
michael@0 201 // Use a destination range that ensures the left edge (or right edge,
michael@0 202 // for RTL) will indeed be visible. Also ensure that the top edge
michael@0 203 // is visible.
michael@0 204 nsRect range(pt.x, pt.y, csspixel, 0);
michael@0 205 if (isLTR) {
michael@0 206 range.x -= csspixel;
michael@0 207 }
michael@0 208 sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
michael@0 209 } else {
michael@0 210 // Use a destination range that ensures the top edge will be visible.
michael@0 211 nsRect range(cp.x, rect.y - csspixel, 0, csspixel);
michael@0 212 sf->ScrollTo(nsPoint(cp.x, rect.y), nsIScrollableFrame::INSTANT, &range);
michael@0 213 }
michael@0 214
michael@0 215 return NS_OK;
michael@0 216 }
michael@0 217
michael@0 218 /* void scrollToLine (in long line); */
michael@0 219 NS_IMETHODIMP nsScrollBoxObject::ScrollToLine(int32_t line)
michael@0 220 {
michael@0 221 nsIScrollableFrame* sf = GetScrollFrame();
michael@0 222 if (!sf)
michael@0 223 return NS_ERROR_FAILURE;
michael@0 224
michael@0 225 nscoord y = sf->GetLineScrollAmount().height * line;
michael@0 226 nsRect range(0, y - nsPresContext::CSSPixelsToAppUnits(1),
michael@0 227 0, nsPresContext::CSSPixelsToAppUnits(1));
michael@0 228 sf->ScrollTo(nsPoint(0, y), nsIScrollableFrame::INSTANT, &range);
michael@0 229 return NS_OK;
michael@0 230 }
michael@0 231
michael@0 232 /* void scrollToElement (in nsIDOMElement child); */
michael@0 233 NS_IMETHODIMP nsScrollBoxObject::ScrollToElement(nsIDOMElement *child)
michael@0 234 {
michael@0 235 NS_ENSURE_ARG_POINTER(child);
michael@0 236
michael@0 237 nsCOMPtr<nsIPresShell> shell = GetPresShell(false);
michael@0 238 if (!shell) {
michael@0 239 return NS_ERROR_UNEXPECTED;
michael@0 240 }
michael@0 241
michael@0 242 nsCOMPtr<nsIContent> content = do_QueryInterface(child);
michael@0 243 shell->ScrollContentIntoView(content,
michael@0 244 nsIPresShell::ScrollAxis(
michael@0 245 nsIPresShell::SCROLL_TOP,
michael@0 246 nsIPresShell::SCROLL_ALWAYS),
michael@0 247 nsIPresShell::ScrollAxis(
michael@0 248 nsIPresShell::SCROLL_LEFT,
michael@0 249 nsIPresShell::SCROLL_ALWAYS),
michael@0 250 nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
michael@0 251 nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
michael@0 252 return NS_OK;
michael@0 253 }
michael@0 254
michael@0 255 /* void scrollToIndex (in long index); */
michael@0 256 NS_IMETHODIMP nsScrollBoxObject::ScrollToIndex(int32_t index)
michael@0 257 {
michael@0 258 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 259 }
michael@0 260
michael@0 261 /* void getPosition (out long x, out long y); */
michael@0 262 NS_IMETHODIMP nsScrollBoxObject::GetPosition(int32_t *x, int32_t *y)
michael@0 263 {
michael@0 264 nsIScrollableFrame* sf = GetScrollFrame();
michael@0 265 if (!sf)
michael@0 266 return NS_ERROR_FAILURE;
michael@0 267
michael@0 268 CSSIntPoint pt = sf->GetScrollPositionCSSPixels();
michael@0 269 *x = pt.x;
michael@0 270 *y = pt.y;
michael@0 271
michael@0 272 return NS_OK;
michael@0 273 }
michael@0 274
michael@0 275 /* void getScrolledSize (out long width, out long height); */
michael@0 276 NS_IMETHODIMP nsScrollBoxObject::GetScrolledSize(int32_t *width, int32_t *height)
michael@0 277 {
michael@0 278 nsIFrame* scrolledBox = GetScrolledBox(this);
michael@0 279 if (!scrolledBox)
michael@0 280 return NS_ERROR_FAILURE;
michael@0 281
michael@0 282 nsRect scrollRect = scrolledBox->GetRect();
michael@0 283
michael@0 284 *width = nsPresContext::AppUnitsToIntCSSPixels(scrollRect.width);
michael@0 285 *height = nsPresContext::AppUnitsToIntCSSPixels(scrollRect.height);
michael@0 286
michael@0 287 return NS_OK;
michael@0 288 }
michael@0 289
michael@0 290 /* void ensureElementIsVisible (in nsIDOMElement child); */
michael@0 291 NS_IMETHODIMP nsScrollBoxObject::EnsureElementIsVisible(nsIDOMElement *child)
michael@0 292 {
michael@0 293 NS_ENSURE_ARG_POINTER(child);
michael@0 294
michael@0 295 nsCOMPtr<nsIPresShell> shell = GetPresShell(false);
michael@0 296 if (!shell) {
michael@0 297 return NS_ERROR_UNEXPECTED;
michael@0 298 }
michael@0 299
michael@0 300 nsCOMPtr<nsIContent> content = do_QueryInterface(child);
michael@0 301 shell->ScrollContentIntoView(content,
michael@0 302 nsIPresShell::ScrollAxis(),
michael@0 303 nsIPresShell::ScrollAxis(),
michael@0 304 nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY |
michael@0 305 nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
michael@0 306 return NS_OK;
michael@0 307 }
michael@0 308
michael@0 309 /* void ensureIndexIsVisible (in long index); */
michael@0 310 NS_IMETHODIMP nsScrollBoxObject::EnsureIndexIsVisible(int32_t index)
michael@0 311 {
michael@0 312 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 313 }
michael@0 314
michael@0 315 /* void ensureLineIsVisible (in long line); */
michael@0 316 NS_IMETHODIMP nsScrollBoxObject::EnsureLineIsVisible(int32_t line)
michael@0 317 {
michael@0 318 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 319 }
michael@0 320
michael@0 321 nsresult
michael@0 322 NS_NewScrollBoxObject(nsIBoxObject** aResult)
michael@0 323 {
michael@0 324 *aResult = new nsScrollBoxObject;
michael@0 325 if (!*aResult)
michael@0 326 return NS_ERROR_OUT_OF_MEMORY;
michael@0 327 NS_ADDREF(*aResult);
michael@0 328 return NS_OK;
michael@0 329 }
michael@0 330

mercurial