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.

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

mercurial