layout/xul/nsScrollBoxObject.cpp

changeset 0
6474c204b198
     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 +

mercurial