Example #1
1
void CZoominTool::OnMouseMove(_CVIEW* pView, UINT nFlags, CPoint& point)
{
	::SetCursor(AfxGetApp()->LoadCursor(IDC_ZOOMIN));
	CDC* pDC = NULL;
	pDC = pView->GetDC();
	if (pDC == NULL) return;
	if (!c_bDown)
	{
		DeleteDC(pDC->m_hDC);
		return;
	}

	CRect oldRect(c_PtDown,c_PtOld);
	CRect newRect(c_PtDown,point);
	//CRect TrackRect;
	//	TrackRect.SetRect(m_StartPoint,point);
	CPen Pen;
	if (!Pen.CreatePen(PS_SOLID, 1, RGB(0,0,0)))
	return;
	CPen *pOldPen = pDC->SelectObject(&Pen);
	//int oldDrawMode = m_pDC->SetROP2(R2_XORPEN);
	int oldDrawMode = pDC->SetROP2(R2_NOT);
	pDC->SelectStockObject(NULL_BRUSH);
	pDC->Rectangle(oldRect);
	pDC->Rectangle(newRect);
	pDC->SetROP2(oldDrawMode);
	pDC->SelectObject(pOldPen);
	Pen.DeleteObject();
	DeleteDC(pDC->m_hDC);
	CDrawTool::OnMouseMove(pView, nFlags, point);
}
Example #2
0
void AnnotationInterface::UpdateAnnotationRect(bool reset)
{
   // compute current image rectangle for annotation text and leader
   // also compute its union and rectangle for invalidation (union of old and new rectangles)
   if (view != 0)
   {
      // flag whether leader is to be shown
      bool showLeader = leaderPlaced && instance.annotationShowLeader;

      // get view image window
      ImageWindow w = view->Window();

      // store actual rectangles - we'll need them for invalidate rectangle
      Rect oldRect( totalRect );

      // get annotation font
      pcl::Font f = AnnotationRenderer::GetAnnotationFont( instance );

      // compute current text rectangle
      textRect = Rect( f.Width( instance.annotationText ) + 1, f.Height() + 1 );
      textRect.MoveBy( instance.annotationPositionX, instance.annotationPositionY );

      // compute leader rectangle if needed
      if ( showLeader )
      {
         leaderRect = Rect( 11, 11 );
         leaderRect.MoveBy( instance.annotationLeaderPositionX - 5, instance.annotationLeaderPositionY - 5 );
      }

      // compute total rectangle (text and leader) using annotation renderer
      int relPosX, relPosY, dummy3, dummy4;
      totalRect = AnnotationRenderer::GetBoundingRectangle(instance, relPosX, relPosY, dummy3, dummy4);
      totalRect.MoveBy(instance.annotationPositionX-relPosX, instance.annotationPositionY-relPosY);

      // if oldRect is not valid, don't take it into account when computing invalidate rectangle
      if ( reset )
      {
         invalidateRect = totalRect;
      }
      // otherwise make invalidate rectangle union of old and new rectangles
      else
      {
         invalidateRect = totalRect.Union( oldRect );
      }
   }
}
Example #3
0
bool cgGdiplusRender::PushClipRect( const cgRectF& clipRect )
{
	Gdiplus::Rect kOregionRect;
	m_pkGraphics->GetClipBounds(&kOregionRect);

	cgRectF oldRect(kOregionRect.X, kOregionRect.Y, kOregionRect.Width, kOregionRect.Height);
	cgRectF finalRect;
	if (cgXGetIntersectRect(oldRect, clipRect, finalRect))
	{
		Gdiplus::Rect kNewRect(finalRect.x, finalRect.y, finalRect.w, finalRect.h);
		m_pkGraphics->SetClip(kNewRect);

		m_kClipRectStack.push(kOregionRect);

		return true;
	}

	return false;
}
Example #4
0
NS_IMETHODIMP
nsStackLayout::Layout(nsIBox* aBox, nsBoxLayoutState& aState)
{
  nsRect clientRect;
  aBox->GetClientRect(clientRect);

  PRBool grow;

  do {
    nsIBox* child = aBox->GetChildBox();
    grow = PR_FALSE;

    while (child) 
    {  
      nsMargin margin;
      child->GetMargin(margin);
      nsRect childRect(clientRect);
      childRect.Deflate(margin);

      if (childRect.width < 0)
        childRect.width = 0;

      if (childRect.height < 0)
        childRect.height = 0;

      nsRect oldRect(child->GetRect());
      PRBool sizeChanged = (oldRect != childRect);

      // only lay out dirty children or children whose sizes have changed
      if (sizeChanged || NS_SUBTREE_DIRTY(child)) {
          // add in the child's margin
          nsMargin margin;
          child->GetMargin(margin);

          // obtain our offset from the top left border of the stack's content box.
          nsSize offset(0,0);
          PRBool offsetSpecified = AddOffset(aState, child, offset);

          // Correct the child's x/y position by adding in both the margins
          // and the left/top offset.
          childRect.x = clientRect.x + offset.width + margin.left;
          childRect.y = clientRect.y + offset.height + margin.top;
          
          // If we have an offset, we don't stretch the child.  Just use
          // its preferred size.
          if (offsetSpecified) {
            nsSize pref = child->GetPrefSize(aState);
            childRect.width = pref.width;
            childRect.height = pref.height;
          }

          // Now place the child.
          child->SetBounds(aState, childRect);

          // Flow the child.
          child->Layout(aState);

          // Get the child's new rect.
          nsRect childRectNoMargin;
          childRectNoMargin = childRect = child->GetRect();
          childRect.Inflate(margin);

          // Did the child push back on us and get bigger?
          if (offset.width + childRect.width > clientRect.width) {
            clientRect.width = childRect.width + offset.width;
            grow = PR_TRUE;
          }

          if (offset.height + childRect.height > clientRect.height) {
            clientRect.height = childRect.height + offset.height;
            grow = PR_TRUE;
          }

          if (childRectNoMargin != oldRect)
          {
            // redraw the new and old positions if the 
            // child moved or resized.
            // if the new and old rect intersect meaning we just moved a little
            // then just redraw the union. If they don't intersect (meaning
            // we moved a good distance) redraw both separately.
            if (childRectNoMargin.Intersects(oldRect)) {
              nsRect u;
              u.UnionRect(oldRect, childRectNoMargin);
              aBox->Redraw(aState, &u);
            } else {
              aBox->Redraw(aState, &oldRect);
              aBox->Redraw(aState, &childRectNoMargin);
            }
          }
       }

       child = child->GetNextBox();
     }
   } while (grow);
   
   // if some HTML inside us got bigger we need to force ourselves to
   // get bigger
   nsRect bounds(aBox->GetRect());
   nsMargin bp;
   aBox->GetBorderAndPadding(bp);
   clientRect.Inflate(bp);

   if (clientRect.width > bounds.width || clientRect.height > bounds.height)
   {
     if (clientRect.width > bounds.width)
       bounds.width = clientRect.width;
     if (clientRect.height > bounds.height)
       bounds.height = clientRect.height;

     aBox->SetBounds(aState, bounds);
   }

   return NS_OK;
}
Example #5
0
template<class T> void HTMLElementDisplay<T>::Notify(Notifier *who, NotifyEvent *what)
{
	if (what && (who == mpHtmlElement))
	{
		const WebRect * tmpRect = 	&(((DisplayElement *)(this))->mRect);
		switch (what->event)
		{
		case NOTIFY_PARENT_STYLE_CHANGE:  // intentional fall-through
		case NOTIFY_FORMAT_STYLE_CHANGE:  // intentional fall-through
		case NOTIFY_STYLE_CHANGE:
		{
			WEBC_BOOL invalidated = WEBC_FALSE;
			PresetWebRect oldRect(tmpRect);
			if (SetElementStyle())
			{
				oldRect.Or(tmpRect);
				T::InvalidateRect(&oldRect);
				invalidated = WEBC_TRUE;
			}

			WEBC_UINT16 visible = GetVisibility();
			WEBC_UINT16 display = GetUnitType();
			WEBC_UINT16 position = GetPosition();

			if (InvalidateTUMirror())
			{
				if (!invalidated)
				{
					T::Invalidate();
					invalidated = WEBC_TRUE;
				}

				// GetHTMLParentDisplay will work even if we happen to be
				//  disconnected from the display tree at the moment.
				DisplayElement *parent = GetHTMLParentDisplay();
				if (parent)
				{
					NotifyEvent what(NOTIFIER_TYPE_TEXT_UNIT, NOTIFY_STYLE_CHANGE);
					what.data.oldStyle.display = display;
					what.data.oldStyle.position = position;
					parent->Notify((TextUnit *) this, &what);
				}
			}

			if (!invalidated)
			{
				if (visible != GetVisibility())
				{
					T::Invalidate();
					invalidated = WEBC_TRUE;
				}
			}
			break;
		}

		case NOTIFY_PARENT_DISPLAY_STYLE_CHANGE:  // intentional fall-through
		case NOTIFY_DISPLAY_STYLE_CHANGE:
		{
			WEBC_BOOL invalidated = WEBC_FALSE;
			PresetWebRect oldRect(tmpRect);
			if (SetElementStyle())
			{
				oldRect.Or(tmpRect);
				T::InvalidateRect(&oldRect);
				invalidated = WEBC_TRUE;
			}

			if (InvalidateVisibility())
			{
				if (!invalidated)
				{
					T::Invalidate();
					invalidated = WEBC_TRUE;
				}
			}

			if (InvalidateZIndex())
			{
				DisplayElement *parent = GetHTMLParentDisplay();
				if (parent)
				{
					NotifyEvent what(NOTIFIER_TYPE_TEXT_UNIT, NOTIFY_ZINDEX_CHANGE);
					parent->Notify((TextUnit*) this, &what);
				}

				if (!invalidated)
				{
					T::Invalidate();
					invalidated = WEBC_TRUE;
				}
			}
			break;
		}

		default:
			break;
		}
	}

	T::Notify(who, what);
}
Example #6
0
void DisplayManager::SetViewport (WebRect *pViewRect)
{
	if (!mViewRect.Equals(pViewRect))
	{
		PresetWebRect oldRect(&mViewRect);

		mViewportChanged = WEBC_TRUE;
		mViewRect.Set(pViewRect);

		CorrectViewportPosition();

	  #ifdef WEBC_BUFFER_SCROLLING
		if (mManagerFlags & MANAGER_FLAG_BUFFER_SCROLL)
		{
			WebGraphics* gc = this->GetGraphics();
			if (gc)
			{
				if (mScrollBuffer == 0)
				{
					mScrollBuffer = gc->CreateBuffer(mViewRect.Width() * 2, mViewRect.Height() * 2);
				}
				else
				{
					if (oldRect.Width() != mViewRect.Width() ||
					    oldRect.Height() != mViewRect.Height())
					{
						mScrollBuffer = gc->ResizeBuffer(mScrollBuffer, mViewRect.Width() * 2, mViewRect.Height() * 2);
						AddDirtyRect(&mViewRect);
						SetManagerFlag(MANAGER_FLAG_DIRTY);
						return;
					}
				}

				if (mScrollBuffer)
				{
					// find non-overlapping regions
					if (mViewRect.Overlaps(&oldRect))
					{
						PresetWebRect viewRect(&mViewRect);
						WebRect extraRect;

						int count = viewRect.Split(&oldRect, &extraRect);
						if (count > 0)
						{
							if (count > 1)
							{
								if (count > 2)
								{
									if (!extraRect.Empty())
									{
										AddDirtyRect(&extraRect);
									}
								}
								if (!oldRect.Empty())
								{
									AddDirtyRect(&oldRect);
								}
							}
							if (!viewRect.Empty())
							{
								AddDirtyRect(&viewRect);
							}
						}
					}
					else
					{
						AddDirtyRect(&mViewRect);
					}

					SetManagerFlag(MANAGER_FLAG_DIRTY);
				}
			}

		}
	  #endif
	}
}
Example #7
0
// More efficient: erase and redraw simultaneously if possible
bool wxGenericDragImage::RedrawImage(const wxPoint& oldPos,
                                     const wxPoint& newPos,
                                     bool eraseOld, bool drawNew)
{
    if (!m_windowDC)
        return false;

#ifdef wxHAS_NATIVE_OVERLAY
    wxUnusedVar(oldPos);

    wxDCOverlay dcoverlay( m_overlay, (wxWindowDC*) m_windowDC ) ;
    if ( eraseOld )
        dcoverlay.Clear() ;
    if (drawNew)
        DoDrawImage(*m_windowDC, newPos);
#else // !wxHAS_NATIVE_OVERLAY
    wxBitmap* backing = (m_pBackingBitmap ? m_pBackingBitmap : (wxBitmap*) & m_backingBitmap);
    if (!backing->IsOk())
        return false;

    wxRect oldRect(GetImageRect(oldPos));
    wxRect newRect(GetImageRect(newPos));

    wxRect fullRect;

    // Full rect: the combination of both rects
    if (eraseOld && drawNew)
    {
        int oldRight = oldRect.GetRight();
        int oldBottom = oldRect.GetBottom();
        int newRight = newRect.GetRight();
        int newBottom = newRect.GetBottom();

        wxPoint topLeft = wxPoint(wxMin(oldPos.x, newPos.x), wxMin(oldPos.y, newPos.y));
        wxPoint bottomRight = wxPoint(wxMax(oldRight, newRight), wxMax(oldBottom, newBottom));

        fullRect.x = topLeft.x; fullRect.y = topLeft.y;
        fullRect.SetRight(bottomRight.x);
        fullRect.SetBottom(bottomRight.y);
    }
    else if (eraseOld)
        fullRect = oldRect;
    else if (drawNew)
        fullRect = newRect;

    // Make the bitmap bigger than it need be, so we don't
    // keep reallocating all the time.
    int excess = 50;

    if (!m_repairBitmap.IsOk() || (m_repairBitmap.GetWidth() < fullRect.GetWidth() || m_repairBitmap.GetHeight() < fullRect.GetHeight()))
    {
        m_repairBitmap = wxBitmap(fullRect.GetWidth() + excess, fullRect.GetHeight() + excess);
    }

    wxMemoryDC memDC;
    memDC.SelectObject(* backing);

    wxMemoryDC memDCTemp;
    memDCTemp.SelectObject(m_repairBitmap);

    // Draw the backing bitmap onto the repair bitmap.
    // If full-screen, we may have specified the rect on the
    // screen that we're using for our backing bitmap.
    // So subtract this when we're blitting from the backing bitmap
    // (translate from screen to backing-bitmap coords).

    memDCTemp.Blit(0, 0, fullRect.GetWidth(), fullRect.GetHeight(), & memDC, fullRect.x - m_boundingRect.x, fullRect.y - m_boundingRect.y);

    // If drawing, draw the image onto the mem DC
    if (drawNew)
    {
        wxPoint pos(newPos.x - fullRect.x, newPos.y - fullRect.y) ;
        DoDrawImage(memDCTemp, pos);
    }

    // Now blit to the window
    // Finally, blit the temp mem DC to the window.
    m_windowDC->Blit(fullRect.x, fullRect.y, fullRect.width, fullRect.height, & memDCTemp, 0, 0);

    memDCTemp.SelectObject(wxNullBitmap);
    memDC.SelectObject(wxNullBitmap);
#endif // wxHAS_NATIVE_OVERLAY/!wxHAS_NATIVE_OVERLAY

    return true;
}
NS_IMETHODIMP
nsSprocketLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aState)
{
  // See if we are collapsed. If we are, then simply iterate over all our
  // children and give them a rect of 0 width and height.
  if (aBox->IsCollapsed()) {
    nsIFrame* child = nsBox::GetChildBox(aBox);
    while(child) 
    {
      nsBoxFrame::LayoutChildAt(aState, child, nsRect(0,0,0,0));  
      child = nsBox::GetNextBox(child);
    }
    return NS_OK;
  }

  nsBoxLayoutState::AutoReflowDepth depth(aState);
  mozilla::AutoStackArena arena;

  // ----- figure out our size ----------
  const nsSize originalSize = aBox->GetSize();

  // -- make sure we remove our border and padding  ----
  nsRect clientRect;
  aBox->GetClientRect(clientRect);

  // |originalClientRect| represents the rect of the entire box (excluding borders
  // and padding).  We store it here because we're going to use |clientRect| to hold
  // the required size for all our kids.  As an example, consider an hbox with a
  // specified width of 300.  If the kids total only 150 pixels of width, then
  // we have 150 pixels left over.  |clientRect| is going to hold a width of 150 and
  // is going to be adjusted based off the value of the PACK property.  If flexible
  // objects are in the box, then the two rects will match.
  nsRect originalClientRect(clientRect);

  // The frame state contains cached knowledge about our box, such as our orientation
  // and direction.
  nsFrameState frameState = nsFrameState(0);
  GetFrameState(aBox, frameState);

  // Build a list of our children's desired sizes and computed sizes
  nsBoxSize*         boxSizes = nullptr;
  nsComputedBoxSize* computedBoxSizes = nullptr;

  nscoord min = 0;
  nscoord max = 0;
  int32_t flexes = 0;
  PopulateBoxSizes(aBox, aState, boxSizes, min, max, flexes);
  
  // The |size| variable will hold the total size of children along the axis of
  // the box.  Continuing with the example begun in the comment above, size would
  // be 150 pixels.
  nscoord size = clientRect.width;
  if (!IsHorizontal(aBox))
    size = clientRect.height;
  ComputeChildSizes(aBox, aState, size, boxSizes, computedBoxSizes);

  // After the call to ComputeChildSizes, the |size| variable contains the
  // total required size of all the children.  We adjust our clientRect in the
  // appropriate dimension to match this size.  In our example, we now assign
  // 150 pixels into the clientRect.width.
  //
  // The variables |min| and |max| hold the minimum required size box must be 
  // in the OPPOSITE orientation, e.g., for a horizontal box, |min| is the minimum
  // height we require to enclose our children, and |max| is the maximum height
  // required to enclose our children.
  if (IsHorizontal(aBox)) {
    clientRect.width = size;
    if (clientRect.height < min)
      clientRect.height = min;

    if (frameState & NS_STATE_AUTO_STRETCH) {
      if (clientRect.height > max)
        clientRect.height = max;
    }
  } else {
    clientRect.height = size;
    if (clientRect.width < min)
      clientRect.width = min;

    if (frameState & NS_STATE_AUTO_STRETCH) {
      if (clientRect.width > max)
        clientRect.width = max;
    }
  }

  // With the sizes computed, now it's time to lay out our children.
  bool finished;
  nscoord passes = 0;

  // We flow children at their preferred locations (along with the appropriate computed flex).  
  // After we flow a child, it is possible that the child will change its size.  If/when this happens,
  // we have to do another pass.  Typically only 2 passes are required, but the code is prepared to
  // do as many passes as are necessary to achieve equilibrium.
  nscoord x = 0;
  nscoord y = 0;
  nscoord origX = 0;
  nscoord origY = 0;

  // |childResized| lets us know if a child changed its size after we attempted to lay it out at
  // the specified size.  If this happens, we usually have to do another pass.
  bool childResized = false;

  // |passes| stores our number of passes.  If for any reason we end up doing more than, say, 10
  // passes, we assert to indicate that something is seriously screwed up.
  passes = 0;
  do 
  { 
#ifdef DEBUG_REFLOW
    if (passes > 0) {
      AddIndents();
      printf("ChildResized doing pass: %d\n", passes);
    }
#endif 

    // Always assume that we're done.  This will change if, for example, children don't stay
    // the same size after being flowed.
    finished = true;

    // Handle box packing.
    HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);

    // Now that packing is taken care of we set up a few additional
    // tracking variables.
    origX = x;
    origY = y;

    // Now we iterate over our box children and our box size lists in 
    // parallel.  For each child, we look at its sizes and figure out
    // where to place it.
    nsComputedBoxSize* childComputedBoxSize = computedBoxSizes;
    nsBoxSize* childBoxSize                 = boxSizes;

    nsIFrame* child = nsBox::GetChildBox(aBox);

    int32_t count = 0;
    while (child || (childBoxSize && childBoxSize->bogus))
    { 
      // If for some reason, our lists are not the same length, we guard
      // by bailing out of the loop.
      if (childBoxSize == nullptr) {
        NS_NOTREACHED("Lists not the same length.");
        break;
      }
        
      nscoord width = clientRect.width;
      nscoord height = clientRect.height;

      if (!childBoxSize->bogus) {
        // We have a valid box size entry.  This entry already contains information about our
        // sizes along the axis of the box (e.g., widths in a horizontal box).  If our default
        // ALIGN is not stretch, however, then we also need to know the child's size along the
        // opposite axis.
        if (!(frameState & NS_STATE_AUTO_STRETCH)) {
           nsSize prefSize = child->GetPrefSize(aState);
           nsSize minSize = child->GetMinSize(aState);
           nsSize maxSize = child->GetMaxSize(aState);
           prefSize = nsBox::BoundsCheck(minSize, prefSize, maxSize);
       
           AddMargin(child, prefSize);
           width = std::min(prefSize.width, originalClientRect.width);
           height = std::min(prefSize.height, originalClientRect.height);
        }
      }

      // Obtain the computed size along the axis of the box for this child from the computedBoxSize entry.  
      // We store the result in |width| for horizontal boxes and |height| for vertical boxes.
      if (frameState & NS_STATE_IS_HORIZONTAL)
        width = childComputedBoxSize->size;
      else
        height = childComputedBoxSize->size;
      
      // Adjust our x/y for the left/right spacing.
      if (frameState & NS_STATE_IS_HORIZONTAL) {
        if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
          x += (childBoxSize->left);
        else
          x -= (childBoxSize->right);
      } else {
        if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
          y += (childBoxSize->left);
        else
          y -= (childBoxSize->right);
      }

      // Now we build a child rect.
      nscoord rectX = x;
      nscoord rectY = y;
      if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
        if (frameState & NS_STATE_IS_HORIZONTAL)
          rectX -= width;
        else
          rectY -= height;
      }

      // We now create an accurate child rect based off our computed size information.
      nsRect childRect(rectX, rectY, width, height);

      // Sanity check against our clientRect.  It is possible that a child specified
      // a size that is too large to fit.  If that happens, then we have to grow
      // our client rect.  Remember, clientRect is not the total rect of the enclosing
      // box.  It currently holds our perception of how big the children needed to
      // be.
      if (childRect.width > clientRect.width)
        clientRect.width = childRect.width;

      if (childRect.height > clientRect.height)
        clientRect.height = childRect.height;
    
      // Either |nextX| or |nextY| is updated by this function call, according
      // to our axis.
      nscoord nextX = x;
      nscoord nextY = y;

      ComputeChildsNextPosition(aBox, x, y, nextX, nextY, childRect);

      // Now we further update our nextX/Y along our axis.
      // We also set childRect.y/x along the opposite axis appropriately for a
      // stretch alignment.  (Non-stretch alignment is handled below.)
      if (frameState & NS_STATE_IS_HORIZONTAL) {
        if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
          nextX += (childBoxSize->right);
        else
          nextX -= (childBoxSize->left);
        childRect.y = originalClientRect.y;
      }
      else {
        if (frameState & NS_STATE_IS_DIRECTION_NORMAL)
          nextY += (childBoxSize->right);
        else 
          nextY -= (childBoxSize->left);
        childRect.x = originalClientRect.x;
      }
      
      // If we encounter a completely bogus box size, we just leave this child completely
      // alone and continue through the loop to the next child.
      if (childBoxSize->bogus) 
      {
        childComputedBoxSize = childComputedBoxSize->next;
        childBoxSize = childBoxSize->next;
        count++;
        x = nextX;
        y = nextY;
        continue;
      }

      nsMargin margin(0,0,0,0);

      bool layout = true;

      // Deflate the rect of our child by its margin.
      child->GetMargin(margin);
      childRect.Deflate(margin);
      if (childRect.width < 0)
        childRect.width = 0;
      if (childRect.height < 0)
        childRect.height = 0;

      // Now we're trying to figure out if we have to lay out this child, i.e., to call
      // the child's Layout method.
      if (passes > 0) {
        layout = false;
      } else {
        // Always perform layout if we are dirty or have dirty children
        if (!NS_SUBTREE_DIRTY(child))
          layout = false;
      }

      nsRect oldRect(child->GetRect());

      // Non-stretch alignment will be handled in AlignChildren(), so don't
      // change child out-of-axis positions yet.
      if (!(frameState & NS_STATE_AUTO_STRETCH)) {
        if (frameState & NS_STATE_IS_HORIZONTAL) {
          childRect.y = oldRect.y;
        } else {
          childRect.x = oldRect.x;
        }
      }

      // We computed a childRect.  Now we want to set the bounds of the child to be that rect.
      // If our old rect is different, then we know our size changed and we cache that fact
      // in the |sizeChanged| variable.

      child->SetBounds(aState, childRect);
      bool sizeChanged = (childRect.width != oldRect.width ||
                            childRect.height != oldRect.height);

      if (sizeChanged) {
        // Our size is different.  Sanity check against our maximum allowed size to ensure
        // we didn't exceed it.
        nsSize minSize = child->GetMinSize(aState);
        nsSize maxSize = child->GetMaxSize(aState);
        maxSize = nsBox::BoundsCheckMinMax(minSize, maxSize);

        // make sure the size is in our max size.
        if (childRect.width > maxSize.width)
          childRect.width = maxSize.width;

        if (childRect.height > maxSize.height)
          childRect.height = maxSize.height;
           
        // set it again
        child->SetBounds(aState, childRect);
      }

      // If we already determined that layout was required or if our size has changed, then
      // we make sure to call layout on the child, since its children may need to be shifted
      // around as a result of the size change.
      if (layout || sizeChanged)
        child->Layout(aState);
      
      // If the child was a block or inline (e.g., HTML) it may have changed its rect *during* layout. 
      // We have to check for this.
      nsRect newChildRect(child->GetRect());

      if (!newChildRect.IsEqualInterior(childRect)) {
#ifdef DEBUG_GROW
        child->DumpBox(stdout);
        printf(" GREW from (%d,%d) -> (%d,%d)\n", childRect.width, childRect.height, newChildRect.width, newChildRect.height);
#endif
        newChildRect.Inflate(margin);
        childRect.Inflate(margin);

        // The child changed size during layout.  The ChildResized method handles this
        // scenario.
        ChildResized(aBox,
                     aState, 
                     child,
                     childBoxSize,
                     childComputedBoxSize,
                     boxSizes, 
                     computedBoxSizes, 
                     childRect,
                     newChildRect,
                     clientRect,
                     flexes,
                     finished);

        // We note that a child changed size, which means that another pass will be required.
        childResized = true;

        // Now that a child resized, it's entirely possible that OUR rect is too small.  Now we
        // ensure that |originalClientRect| is grown to accommodate the size of |clientRect|.
        if (clientRect.width > originalClientRect.width)
          originalClientRect.width = clientRect.width;

        if (clientRect.height > originalClientRect.height)
          originalClientRect.height = clientRect.height;

        if (!(frameState & NS_STATE_IS_DIRECTION_NORMAL)) {
          // Our childRect had its XMost() or YMost() (depending on our layout
          // direction), positioned at a certain point.  Ensure that the
          // newChildRect satisfies the same constraint.  Note that this is
          // just equivalent to adjusting the x/y by the difference in
          // width/height between childRect and newChildRect.  So we don't need
          // to reaccount for the left and right of the box layout state again.
          if (frameState & NS_STATE_IS_HORIZONTAL)
            newChildRect.x = childRect.XMost() - newChildRect.width;
          else
            newChildRect.y = childRect.YMost() - newChildRect.height;
        }

        // If the child resized then recompute its position.
        ComputeChildsNextPosition(aBox, x, y, nextX, nextY, newChildRect);

        if (newChildRect.width >= margin.left + margin.right && newChildRect.height >= margin.top + margin.bottom) 
          newChildRect.Deflate(margin);

        if (childRect.width >= margin.left + margin.right && childRect.height >= margin.top + margin.bottom) 
          childRect.Deflate(margin);
            
        child->SetBounds(aState, newChildRect);

        // If we are the first box that changed size, then we don't need to do a second pass
        if (count == 0)
          finished = true;
      }

      // Now update our x/y finally.
      x = nextX;
      y = nextY;
     
      // Move to the next child.
      childComputedBoxSize = childComputedBoxSize->next;
      childBoxSize = childBoxSize->next;

      child = nsBox::GetNextBox(child);
      count++;
    }

    // Sanity-checking code to ensure we don't do an infinite # of passes.
    passes++;
    NS_ASSERTION(passes < 10, "A Box's child is constantly growing!!!!!");
    if (passes > 10)
      break;
  } while (false == finished);

  // Get rid of our size lists.
  while(boxSizes)
  {
    nsBoxSize* toDelete = boxSizes;
    boxSizes = boxSizes->next;
    delete toDelete;
  }

  while(computedBoxSizes)
  {
    nsComputedBoxSize* toDelete = computedBoxSizes;
    computedBoxSizes = computedBoxSizes->next;
    delete toDelete;
  }

  if (childResized) {
    // See if one of our children forced us to get bigger
    nsRect tmpClientRect(originalClientRect);
    nsMargin bp(0,0,0,0);
    aBox->GetBorderAndPadding(bp);
    tmpClientRect.Inflate(bp);

    if (tmpClientRect.width > originalSize.width || tmpClientRect.height > originalSize.height)
    {
      // if it did reset our bounds.
      nsRect bounds(aBox->GetRect());
      if (tmpClientRect.width > originalSize.width)
        bounds.width = tmpClientRect.width;

      if (tmpClientRect.height > originalSize.height)
        bounds.height = tmpClientRect.height;

      aBox->SetBounds(aState, bounds);
    }
  }

  // Because our size grew, we now have to readjust because of box packing.  Repack
  // in order to update our x and y to the correct values.
  HandleBoxPack(aBox, frameState, x, y, originalClientRect, clientRect);

  // Compare against our original x and y and only worry about adjusting the children if
  // we really did have to change the positions because of packing (typically for 'center'
  // or 'end' pack values).
  if (x != origX || y != origY) {
    nsIFrame* child = nsBox::GetChildBox(aBox);

    // reposition all our children
    while (child) 
    {
      nsRect childRect(child->GetRect());
      childRect.x += (x - origX);
      childRect.y += (y - origY);
      child->SetBounds(aState, childRect);
      child = nsBox::GetNextBox(child);
    }
  }

  // Perform out-of-axis alignment for non-stretch alignments
  if (!(frameState & NS_STATE_AUTO_STRETCH)) {
    AlignChildren(aBox, aState);
  }
  
  // That's it!  If you made it this far without having a nervous breakdown, 
  // congratulations!  Go get yourself a beer.
  return NS_OK;
}
Example #9
0
void ScrollView::updateScrollbars(const IntSize& desiredOffset)
{
    // Don't allow re-entrancy into this function.
    if (m_data->m_inUpdateScrollbars)
        return;

    // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
    // In the end, FrameView should just merge with ScrollView.
    if (static_cast<const FrameView*>(this)->frame()->prohibitsScrolling())
        return;

    m_data->m_inUpdateScrollbars = true;

    bool hasVerticalScrollbar = m_data->m_vBar;
    bool hasHorizontalScrollbar = m_data->m_hBar;
    bool oldHasVertical = hasVerticalScrollbar;
    bool oldHasHorizontal = hasHorizontalScrollbar;
    ScrollbarMode hScroll = m_data->m_hScrollbarMode;
    ScrollbarMode vScroll = m_data->m_vScrollbarMode;
    
    const int cVerticalWidth = PlatformScrollbar::verticalScrollbarWidth();
    const int cHorizontalHeight = PlatformScrollbar::horizontalScrollbarHeight();

    for (int pass = 0; pass < 2; pass++) {
        bool scrollsVertically;
        bool scrollsHorizontally;

        if (!m_data->m_scrollbarsSuppressed && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) {
            // Do a layout if pending before checking if scrollbars are needed.
            if (hasVerticalScrollbar != oldHasVertical || hasHorizontalScrollbar != oldHasHorizontal)
                static_cast<FrameView*>(this)->layout();

            scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() > height());
            if (scrollsVertically)
                scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() + cVerticalWidth > width());
            else {
                scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() > width());
                if (scrollsHorizontally)
                    scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() + cHorizontalHeight > height());
            }
        }
        else {
            scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScrollbar : (hScroll == ScrollbarAlwaysOn);
            scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScrollbar : (vScroll == ScrollbarAlwaysOn);
        }
        
        if (hasVerticalScrollbar != scrollsVertically) {
            m_data->setHasVerticalScrollbar(scrollsVertically);
            hasVerticalScrollbar = scrollsVertically;
        }

        if (hasHorizontalScrollbar != scrollsHorizontally) {
            m_data->setHasHorizontalScrollbar(scrollsHorizontally);
            hasHorizontalScrollbar = scrollsHorizontally;
        }
    }
    
    // Set up the range (and page step/line step).
    IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
    IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
    scroll.clampNegativeToZero();
 
    if (m_data->m_hBar) {
        int clientWidth = visibleWidth();
        m_data->m_hBar->setEnabled(contentsWidth() > clientWidth);
        int pageStep = (clientWidth - PAGE_KEEP);
        if (pageStep < 0) pageStep = clientWidth;
        IntRect oldRect(m_data->m_hBar->frameGeometry());
        IntRect hBarRect = IntRect(0,
                                   height() - m_data->m_hBar->height(),
                                   width() - (m_data->m_vBar ? m_data->m_vBar->width() : 0),
                                   m_data->m_hBar->height());
        m_data->m_hBar->setRect(hBarRect);
        if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_hBar->frameGeometry())
            m_data->m_hBar->invalidate();

        if (m_data->m_scrollbarsSuppressed)
            m_data->m_hBar->setSuppressInvalidation(true);
        m_data->m_hBar->setSteps(LINE_STEP, pageStep);
        m_data->m_hBar->setProportion(clientWidth, contentsWidth());
        m_data->m_hBar->setValue(scroll.width());
        if (m_data->m_scrollbarsSuppressed)
            m_data->m_hBar->setSuppressInvalidation(false); 
    } 

    if (m_data->m_vBar) {
        int clientHeight = visibleHeight();
        m_data->m_vBar->setEnabled(contentsHeight() > clientHeight);
        int pageStep = (clientHeight - PAGE_KEEP);
        if (pageStep < 0) pageStep = clientHeight;
        IntRect oldRect(m_data->m_vBar->frameGeometry());
        IntRect vBarRect = IntRect(width() - m_data->m_vBar->width(), 
                                   0,
                                   m_data->m_vBar->width(),
                                   height() - (m_data->m_hBar ? m_data->m_hBar->height() : 0));
        m_data->m_vBar->setRect(vBarRect);
        if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_vBar->frameGeometry())
            m_data->m_vBar->invalidate();

        if (m_data->m_scrollbarsSuppressed)
            m_data->m_vBar->setSuppressInvalidation(true);
        m_data->m_vBar->setSteps(LINE_STEP, pageStep);
        m_data->m_vBar->setProportion(clientHeight, contentsHeight());
        m_data->m_vBar->setValue(scroll.height());
        if (m_data->m_scrollbarsSuppressed)
            m_data->m_vBar->setSuppressInvalidation(false);
    }

    if (oldHasVertical != (m_data->m_vBar != 0) || oldHasHorizontal != (m_data->m_hBar != 0))
        geometryChanged();

    // See if our offset has changed in a situation where we might not have scrollbars.
    // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
    // It can also happen when maximizing a window that has scrollbars (but the new maximized result
    // does not).
    IntSize scrollDelta = scroll - m_data->m_scrollOffset;
    if (scrollDelta != IntSize()) {
       m_data->m_scrollOffset = scroll;
       m_data->scrollBackingStore(scrollDelta);
    }

    m_data->m_inUpdateScrollbars = false;
}