void
nsSplitterFrameInner::EnsureOrient()
{
  bool isHorizontal = !(mParentBox->GetStateBits() & NS_STATE_IS_HORIZONTAL);
  if (isHorizontal)
    mOuter->mState |= NS_STATE_IS_HORIZONTAL;
  else
    mOuter->mState &= ~NS_STATE_IS_HORIZONTAL;
}
bool
PaintFrameCallback::operator()(gfxContext* aContext,
                               const gfxRect& aFillRect,
                               const gfxPattern::GraphicsFilter& aFilter,
                               const gfxMatrix& aTransform)
{
  if (mFrame->GetStateBits() & NS_FRAME_DRAWING_AS_PAINTSERVER)
    return false;

  mFrame->AddStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);

  nsRenderingContext context;
  context.Init(mFrame->PresContext()->DeviceContext(), aContext);
  aContext->Save();

  // Clip to aFillRect so that we don't paint outside.
  aContext->NewPath();
  aContext->Rectangle(aFillRect);
  aContext->Clip();
  gfxMatrix savedMatrix(aContext->CurrentMatrix());

  aContext->Multiply(gfxMatrix(aTransform).Invert());

  // nsLayoutUtils::PaintFrame will anchor its painting at mFrame. But we want
  // to have it anchored at the top left corner of the bounding box of all of
  // mFrame's continuations. So we add a translation transform.
  nsRect bbox = nsSVGIntegrationUtils::GetNonSVGUserSpace(mFrame);
  PRInt32 appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
  gfxPoint offset = gfxPoint(bbox.x, bbox.y) / appUnitsPerDevPixel;
  aContext->Multiply(gfxMatrix().Translate(-offset));

  gfxSize paintServerSize =
    gfxSize(mPaintServerSize.width, mPaintServerSize.height) /
      mFrame->PresContext()->AppUnitsPerDevPixel();

  // nsLayoutUtils::PaintFrame wants to render with paintServerSize, but we
  // want it to render with mRenderSize, so we need to set up a scale transform.
  gfxFloat scaleX = mRenderSize.width / paintServerSize.width;
  gfxFloat scaleY = mRenderSize.height / paintServerSize.height;
  gfxMatrix scaleMatrix = gfxMatrix().Scale(scaleX, scaleY);
  aContext->Multiply(scaleMatrix);

  // Draw.
  nsRect dirty(bbox.x, bbox.y, mPaintServerSize.width, mPaintServerSize.height);
  nsLayoutUtils::PaintFrame(&context, mFrame,
                            dirty, NS_RGBA(0, 0, 0, 0),
                            nsLayoutUtils::PAINT_IN_TRANSFORM |
                            nsLayoutUtils::PAINT_ALL_CONTINUATIONS);

  aContext->SetMatrix(savedMatrix);
  aContext->Restore();

  mFrame->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);

  return true;
}
bool
PaintFrameCallback::operator()(gfxContext* aContext,
                               const gfxRect& aFillRect,
                               const Filter& aFilter,
                               const gfxMatrix& aTransform)
{
  if (mFrame->GetStateBits() & NS_FRAME_DRAWING_AS_PAINTSERVER)
    return false;

  mFrame->AddStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);

  aContext->Save();

  // Clip to aFillRect so that we don't paint outside.
  aContext->NewPath();
  aContext->Rectangle(aFillRect);
  aContext->Clip();

  gfxMatrix invmatrix = aTransform;
  if (!invmatrix.Invert()) {
    return false;
  }
  aContext->Multiply(invmatrix);

  // nsLayoutUtils::PaintFrame will anchor its painting at mFrame. But we want
  // to have it anchored at the top left corner of the bounding box of all of
  // mFrame's continuations. So we add a translation transform.
  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
  nsPoint offset = GetOffsetToBoundingBox(mFrame);
  gfxPoint devPxOffset = gfxPoint(offset.x, offset.y) / appUnitsPerDevPixel;
  aContext->Multiply(gfxMatrix::Translation(devPxOffset));

  gfxSize paintServerSize =
    gfxSize(mPaintServerSize.width, mPaintServerSize.height) /
      mFrame->PresContext()->AppUnitsPerDevPixel();

  // nsLayoutUtils::PaintFrame wants to render with paintServerSize, but we
  // want it to render with mRenderSize, so we need to set up a scale transform.
  gfxFloat scaleX = mRenderSize.width / paintServerSize.width;
  gfxFloat scaleY = mRenderSize.height / paintServerSize.height;
  aContext->Multiply(gfxMatrix::Scaling(scaleX, scaleY));

  // Draw.
  nsRect dirty(-offset.x, -offset.y,
               mPaintServerSize.width, mPaintServerSize.height);

  uint32_t flags = nsLayoutUtils::PAINT_IN_TRANSFORM;
  if (mFlags & nsSVGIntegrationUtils::FLAG_SYNC_DECODE_IMAGES) {
    flags |= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES;
  }
  nsRenderingContext context(aContext);
  nsLayoutUtils::PaintFrame(&context, mFrame,
                            dirty, NS_RGBA(0, 0, 0, 0),
                            flags);

  nsIFrame* currentFrame = mFrame;
   while ((currentFrame = currentFrame->GetNextContinuation()) != nullptr) {
    offset = currentFrame->GetOffsetToCrossDoc(mFrame);
    devPxOffset = gfxPoint(offset.x, offset.y) / appUnitsPerDevPixel;

    aContext->Save();
    aContext->Multiply(gfxMatrix::Scaling(1/scaleX, 1/scaleY));
    aContext->Multiply(gfxMatrix::Translation(devPxOffset));
    aContext->Multiply(gfxMatrix::Scaling(scaleX, scaleY));

    nsLayoutUtils::PaintFrame(&context, currentFrame,
                              dirty - offset, NS_RGBA(0, 0, 0, 0),
                              flags);

    aContext->Restore();
  }

  aContext->Restore();

  mFrame->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);

  return true;
}
Esempio n. 4
0
NS_IMETHODIMP 
nsFieldSetFrame::Reflow(nsPresContext*           aPresContext,
                        nsHTMLReflowMetrics&     aDesiredSize,
                        const nsHTMLReflowState& aReflowState,
                        nsReflowStatus&          aStatus)
{
  DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame", aReflowState.reason);
  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);

  // Initialize OUT parameter
  aStatus = NS_FRAME_COMPLETE;

  // Should we create a space manager?
  nsAutoSpaceManager autoSpaceManager(NS_CONST_CAST(nsHTMLReflowState &, aReflowState));

  // XXXldb If we start storing the space manager in the frame rather
  // than keeping it around only during reflow then we should create it
  // only when there are actually floats to manage.  Otherwise things
  // like tables will gain significant bloat.
  if (NS_BLOCK_SPACE_MGR & mState)
    autoSpaceManager.CreateSpaceManagerFor(aPresContext, this);

  
  //------------ Handle Incremental Reflow -----------------
  PRBool reflowContent = PR_TRUE;
  PRBool reflowLegend = PR_TRUE;
  nsReflowReason reason = aReflowState.reason;

  if (reason == eReflowReason_Incremental) {
      nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand;

      // See if it's targeted at us
      if (command) {
        nsReflowType  reflowType;
        command->GetType(reflowType);

        switch (reflowType) {
          case eReflowType_StyleChanged:
            reason = eReflowReason_StyleChange;
            break;

          case eReflowType_ReflowDirty: 
            reason = eReflowReason_Dirty;
            break;

          default:
            NS_ERROR("Unexpected Reflow Type");
        }
      } else {
           reflowContent = PR_FALSE;
           reflowLegend = PR_FALSE;

           nsReflowPath::iterator iter = aReflowState.path->FirstChild();
           nsReflowPath::iterator end = aReflowState.path->EndChildren();

           for ( ; iter != end; ++iter) {
               if (*iter == mLegendFrame)
                   reflowLegend = PR_TRUE;
               else if (*iter == mContentFrame)
                   reflowContent = PR_TRUE;
           }
      }
  }

  if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
    reflowLegend = PR_TRUE;
    reflowContent = PR_TRUE;
  } else if (reason == eReflowReason_Dirty) {
    // if dirty then check dirty flags
    if (GetStateBits() & NS_FRAME_IS_DIRTY) {
      reflowLegend = PR_TRUE;
      reflowContent = PR_TRUE;
    } else {
      if (reflowContent) {
        reflowContent = mContentFrame ?
          (mContentFrame->GetStateBits()
           & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE;
      }

      if (reflowLegend) {
        reflowLegend = mLegendFrame ?
          (mLegendFrame->GetStateBits()
           & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0 : PR_FALSE;
      }
    }
  }

  // availSize could have unconstrained values, don't perform any addition on them
  nsSize availSize(aReflowState.mComputedWidth, aReflowState.availableHeight);

  // get our border and padding
  const nsMargin &borderPadding = aReflowState.mComputedBorderPadding;
  const nsMargin &padding       = aReflowState.mComputedPadding;
  nsMargin border = borderPadding - padding;
  if (aDesiredSize.mComputeMEW) {
    aDesiredSize.mMaxElementWidth = borderPadding.left + borderPadding.right;
  }
  

  // Figure out how big the legend is if there is one. 
  // get the legend's margin
  nsMargin legendMargin(0,0,0,0);
  // reflow the legend only if needed
  if (mLegendFrame) {
    const nsStyleMargin* marginStyle = mLegendFrame->GetStyleMargin();
    marginStyle->GetMargin(legendMargin);

    if (reflowLegend) {
      nsHTMLReflowState legendReflowState(aPresContext, aReflowState,
                                          mLegendFrame, nsSize(NS_INTRINSICSIZE,NS_INTRINSICSIZE),
                                          reason);

      // always give the legend as much size as it needs
      legendReflowState.mComputedWidth = NS_INTRINSICSIZE;
      legendReflowState.mComputedHeight = NS_INTRINSICSIZE;

      nsHTMLReflowMetrics legendDesiredSize(0,0);

      ReflowChild(mLegendFrame, aPresContext, legendDesiredSize, legendReflowState,
                  0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
#ifdef NOISY_REFLOW
      printf("  returned (%d, %d)\n", legendDesiredSize.width, legendDesiredSize.height);
      if (legendDesiredSize.mComputeMEW)
        printf("  and maxEW %d\n", 
               legendDesiredSize.mMaxElementWidth);
#endif
      // figure out the legend's rectangle
      mLegendRect.width  = legendDesiredSize.width + legendMargin.left + legendMargin.right;
      mLegendRect.height = legendDesiredSize.height + legendMargin.top + legendMargin.bottom;
      mLegendRect.x = borderPadding.left;
      mLegendRect.y = 0;

      nscoord oldSpace = mLegendSpace;
      mLegendSpace = 0;
      if (mLegendRect.height > border.top) {
        // center the border on the legend
        mLegendSpace = mLegendRect.height - border.top;
      } else {
        mLegendRect.y = (border.top - mLegendRect.height)/2;
      }

      // if the legend space changes then we need to reflow the 
      // content area as well.
      if (mLegendSpace != oldSpace) {
        if (reflowContent == PR_FALSE || reason == eReflowReason_Dirty) {
          reflowContent = PR_TRUE;
          reason = eReflowReason_Resize;
        }
      }

      // if we are contrained then remove the legend from our available height.
      if (NS_INTRINSICSIZE != availSize.height) {
        if (availSize.height >= mLegendSpace)
          availSize.height -= mLegendSpace;
      }
  
      // don't get any smaller than the legend
      if (NS_INTRINSICSIZE != availSize.width) {
        if (availSize.width < mLegendRect.width)
          availSize.width = mLegendRect.width;
      }

      FinishReflowChild(mLegendFrame, aPresContext, &legendReflowState, 
                        legendDesiredSize, 0, 0, NS_FRAME_NO_MOVE_FRAME);    

    }
  } else {
    mLegendRect.Empty();
    mLegendSpace = 0;
  }

  nsRect contentRect;

  // reflow the content frame only if needed
  if (mContentFrame) {
    if (reflowContent) {
      availSize.width = aReflowState.mComputedWidth;

      nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mContentFrame,
                                       availSize, reason);

      nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.mComputeMEW, aDesiredSize.mFlags);
      // Reflow the frame
      ReflowChild(mContentFrame, aPresContext, kidDesiredSize, kidReflowState,
                  borderPadding.left + kidReflowState.mComputedMargin.left,
                  borderPadding.top + mLegendSpace + kidReflowState.mComputedMargin.top,
                  0, aStatus);

      // set the rect. make sure we add the margin back in.
      contentRect.SetRect(borderPadding.left,borderPadding.top + mLegendSpace,kidDesiredSize.width ,kidDesiredSize.height);
      if (aReflowState.mComputedHeight != NS_INTRINSICSIZE &&
          borderPadding.top + mLegendSpace+kidDesiredSize.height > aReflowState.mComputedHeight) {
        kidDesiredSize.height = aReflowState.mComputedHeight-(borderPadding.top + mLegendSpace);
      }

      FinishReflowChild(mContentFrame, aPresContext, &kidReflowState, 
                        kidDesiredSize, contentRect.x, contentRect.y, 0);
      if (aDesiredSize.mComputeMEW) {
        aDesiredSize.mMaxElementWidth = kidDesiredSize.mMaxElementWidth;
        if (eStyleUnit_Coord == aReflowState.mStylePosition->mWidth.GetUnit() &&
            NS_INTRINSICSIZE != aReflowState.mComputedWidth)
          aDesiredSize.mMaxElementWidth = aReflowState.mComputedWidth;
        if (eStyleUnit_Percent == aReflowState.mStylePosition->mWidth.GetUnit())
          aDesiredSize.mMaxElementWidth = 0;
        aDesiredSize.mMaxElementWidth += borderPadding.left + borderPadding.right;
      }
      if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) {
        aDesiredSize.mMaximumWidth = kidDesiredSize.mMaximumWidth +
                                     borderPadding.left + borderPadding.right;
      }
      NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);

    } else {
      // if we don't need to reflow just get the old size
      contentRect = mContentFrame->GetRect();
      const nsStyleMargin* marginStyle = mContentFrame->GetStyleMargin();

      nsMargin m(0,0,0,0);
      marginStyle->GetMargin(m);
      contentRect.Inflate(m);
    }
  }

  // use the computed width if the inner content does not fill it
  if (aReflowState.mComputedWidth != NS_INTRINSICSIZE &&
      aReflowState.mComputedWidth > contentRect.width) {
    contentRect.width = aReflowState.mComputedWidth;
  }

  if (mLegendFrame) {
    // if the content rect is larger then the  legend we can align the legend
    if (contentRect.width > mLegendRect.width) {
      PRInt32 align = ((nsLegendFrame*)mLegendFrame)->GetAlign();

      switch(align) {
        case NS_STYLE_TEXT_ALIGN_RIGHT:
          mLegendRect.x = contentRect.width - mLegendRect.width + borderPadding.left;
          break;
        case NS_STYLE_TEXT_ALIGN_CENTER:
          float p2t;
          p2t = aPresContext->PixelsToTwips();
          mLegendRect.x = NSIntPixelsToTwips((nscoord) NSToIntRound((float)(contentRect.width/2 - mLegendRect.width/2 + borderPadding.left) / p2t),p2t);
          break;
      }
  
    } else {
      //otherwise make place for the legend
      contentRect.width = mLegendRect.width;
    }
    // place the legend
    nsRect actualLegendRect(mLegendRect);
    actualLegendRect.Deflate(legendMargin);

    nsPoint curOrigin = mLegendFrame->GetPosition();

    // only if the origin changed
    if ((curOrigin.x != mLegendRect.x) || (curOrigin.y != mLegendRect.y)) {
      mLegendFrame->SetPosition(nsPoint(actualLegendRect.x , actualLegendRect.y));
      nsContainerFrame::PositionFrameView(mLegendFrame);

      // We need to recursively process the legend frame's
      // children since we're moving the frame after Reflow.
      nsContainerFrame::PositionChildViews(mLegendFrame);
    }
  }

  // Return our size and our result
  if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) {
    aDesiredSize.height = mLegendSpace + 
                          borderPadding.top +
                          contentRect.height +
                          borderPadding.bottom;
  } else {
    nscoord min = borderPadding.top + borderPadding.bottom + mLegendRect.height;
    aDesiredSize.height = aReflowState.mComputedHeight + borderPadding.top + borderPadding.bottom;
    if (aDesiredSize.height < min)
      aDesiredSize.height = min;
  }
  aDesiredSize.width = contentRect.width + borderPadding.left + borderPadding.right;
  aDesiredSize.ascent  = aDesiredSize.height;
  aDesiredSize.descent = 0;
  if (aDesiredSize.mComputeMEW) {
    // if the legend is wider use it
    if (aDesiredSize.mMaxElementWidth < mLegendRect.width + borderPadding.left + borderPadding.right)
      aDesiredSize.mMaxElementWidth = mLegendRect.width + borderPadding.left + borderPadding.right;
  }
  aDesiredSize.mOverflowArea = nsRect(0, 0, aDesiredSize.width, aDesiredSize.height);
  // make the mMaximumWidth large enough if the legendframe determines the size
  if ((aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) && mLegendFrame) {
    aDesiredSize.mMaximumWidth = PR_MAX(aDesiredSize.mMaximumWidth, mLegendRect.width +
                                        borderPadding.left + borderPadding.right);
  }
  if (mLegendFrame)
    ConsiderChildOverflow(aDesiredSize.mOverflowArea, mLegendFrame);
  if (mContentFrame)
    ConsiderChildOverflow(aDesiredSize.mOverflowArea, mContentFrame);
  FinishAndStoreOverflow(&aDesiredSize);

  Invalidate(aDesiredSize.mOverflowArea);

  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  return NS_OK;
}