Пример #1
0
already_AddRefed<DOMRect>
PopupBoxObject::GetOuterScreenRect()
{
  nsRefPtr<DOMRect> rect = new DOMRect(mContent);

  // Return an empty rectangle if the popup is not open.
  nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(GetFrame(false));
  if (!menuPopupFrame || !menuPopupFrame->IsOpen()) {
    return rect.forget();
  }

  nsView* view = menuPopupFrame->GetView();
  if (view) {
    nsIWidget* widget = view->GetWidget();
    if (widget) {
      nsIntRect screenRect;
      widget->GetScreenBounds(screenRect);

      int32_t pp = menuPopupFrame->PresContext()->AppUnitsPerDevPixel();
      rect->SetLayoutRect(ToAppUnits(screenRect, pp));
    }
  }
  return rect.forget();
}
Пример #2
0
nsresult
nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
                              nsIFrame* aParent,
                              const gfxMatrix &aMatrix)
{
    // If the flag is set when we get here, it means this clipPath frame
    // has already been used painting the current clip, and the document
    // has a clip reference loop.
    if (mInUse) {
        NS_WARNING("Clip loop detected!");
        return NS_OK;
    }
    AutoClipPathReferencer clipRef(this);

    mClipParent = aParent;
    if (mClipParentMatrix) {
        *mClipParentMatrix = aMatrix;
    } else {
        mClipParentMatrix = new gfxMatrix(aMatrix);
    }

    bool isTrivial = IsTrivial();

    nsAutoSVGRenderMode mode(aContext,
                             isTrivial ? nsSVGRenderState::CLIP
                             : nsSVGRenderState::CLIP_MASK);


    gfxContext *gfx = aContext->GetGfxContext();

    nsSVGClipPathFrame *clipPathFrame =
        nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull);
    bool referencedClipIsTrivial;
    if (clipPathFrame) {
        referencedClipIsTrivial = clipPathFrame->IsTrivial();
        gfx->Save();
        if (referencedClipIsTrivial) {
            clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
        } else {
            gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
        }
    }

    for (nsIFrame* kid = mFrames.FirstChild(); kid;
            kid = kid->GetNextSibling()) {
        nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
        if (SVGFrame) {
            // The CTM of each frame referencing us can be different.
            SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
                                       nsISVGChildFrame::TRANSFORM_CHANGED);

            bool isOK = true;
            nsSVGClipPathFrame *clipPathFrame =
                nsSVGEffects::GetEffectProperties(kid).GetClipPathFrame(&isOK);
            if (!isOK) {
                continue;
            }

            bool isTrivial;

            if (clipPathFrame) {
                isTrivial = clipPathFrame->IsTrivial();
                gfx->Save();
                if (isTrivial) {
                    clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
                } else {
                    gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
                }
            }

            SVGFrame->PaintSVG(aContext, nsnull);

            if (clipPathFrame) {
                if (!isTrivial) {
                    gfx->PopGroupToSource();

                    nsRefPtr<gfxPattern> clipMaskSurface;
                    gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

                    clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
                    clipMaskSurface = gfx->PopGroup();

                    if (clipMaskSurface) {
                        gfx->Mask(clipMaskSurface);
                    }
                }
                gfx->Restore();
            }
        }
    }

    if (clipPathFrame) {
        if (!referencedClipIsTrivial) {
            gfx->PopGroupToSource();

            nsRefPtr<gfxPattern> clipMaskSurface;
            gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

            clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
            clipMaskSurface = gfx->PopGroup();

            if (clipMaskSurface) {
                gfx->Mask(clipMaskSurface);
            }
        }
        gfx->Restore();
    }

    if (isTrivial) {
        gfx->Clip();
        gfx->NewPath();
    }

    return NS_OK;
}
Пример #3
0
nsresult
nsTextControlFrame::CalcIntrinsicSize(nsRenderingContext* aRenderingContext,
                                      nsSize&              aIntrinsicSize)
{
  // Get leading and the Average/MaxAdvance char width 
  nscoord lineHeight  = 0;
  nscoord charWidth   = 0;
  nscoord charMaxAdvance  = 0;

  nsRefPtr<nsFontMetrics> fontMet;
  nsresult rv =
    nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet));
  NS_ENSURE_SUCCESS(rv, rv);
  aRenderingContext->SetFont(fontMet);

  lineHeight =
    nsHTMLReflowState::CalcLineHeight(GetStyleContext(), NS_AUTOHEIGHT);
  charWidth = fontMet->AveCharWidth();
  charMaxAdvance = fontMet->MaxAdvance();

  // Set the width equal to the width in characters
  PRInt32 cols = GetCols();
  aIntrinsicSize.width = cols * charWidth;

  // To better match IE, take the maximum character width(in twips) and remove
  // 4 pixels add this on as additional padding(internalPadding). But only do
  // this if charMaxAdvance != charWidth; if they are equal, this is almost
  // certainly a fixed-width font.
  if (charWidth != charMaxAdvance) {
    nscoord internalPadding = NS_MAX(0, charMaxAdvance -
                                        nsPresContext::CSSPixelsToAppUnits(4));
    nscoord t = nsPresContext::CSSPixelsToAppUnits(1); 
   // Round to a multiple of t
    nscoord rest = internalPadding % t; 
    if (rest < t - rest) {
      internalPadding -= rest;
    } else {
      internalPadding += t - rest;
    }
    // Now add the extra padding on (so that small input sizes work well)
    aIntrinsicSize.width += internalPadding;
  } else {
    // This is to account for the anonymous <br> having a 1 twip width
    // in Full Standards mode, see BRFrame::Reflow and bug 228752.
    if (PresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
      aIntrinsicSize.width += 1;
    }

    // Also add in the padding of our value div child.  Note that it hasn't
    // been reflowed yet, so we can't get its used padding, but it shouldn't be
    // using percentage padding anyway.
    nsMargin childPadding;
    nsIFrame* firstChild = GetFirstChild(nsnull);
    if (firstChild && firstChild->GetStylePadding()->GetPadding(childPadding)) {
      aIntrinsicSize.width += childPadding.LeftRight();
    } else {
      NS_ERROR("Percentage padding on value div?");
    }
  }

  // Increment width with cols * letter-spacing.
  {
    const nsStyleCoord& lsCoord = GetStyleText()->mLetterSpacing;
    if (eStyleUnit_Coord == lsCoord.GetUnit()) {
      nscoord letterSpacing = lsCoord.GetCoordValue();
      if (letterSpacing != 0) {
        aIntrinsicSize.width += cols * letterSpacing;
      }
    }
  }

  // Set the height equal to total number of rows (times the height of each
  // line, of course)
  aIntrinsicSize.height = lineHeight * GetRows();

  // Add in the size of the scrollbars for textarea
  if (IsTextArea()) {
    nsIFrame* first = GetFirstChild(nsnull);

    nsIScrollableFrame *scrollableFrame = do_QueryFrame(first);
    NS_ASSERTION(scrollableFrame, "Child must be scrollable");

    if (scrollableFrame) {
      nsMargin scrollbarSizes =
      scrollableFrame->GetDesiredScrollbarSizes(PresContext(), aRenderingContext);

      aIntrinsicSize.width  += scrollbarSizes.LeftRight();

      aIntrinsicSize.height += scrollbarSizes.TopBottom();;
    }
  }

  return NS_OK;
}
Пример #4
0
void
nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
                                              nsIFrame* aEffectsFrame,
                                              const nsRect& aDirtyRect,
                                              nsDisplayListBuilder* aBuilder,
                                              nsDisplayList* aInnerList)
{
#ifdef DEBUG
  nsISVGChildFrame *svgChildFrame = do_QueryFrame(aEffectsFrame);
  NS_ASSERTION(!svgChildFrame, "Should never be called on an SVG frame");
#endif

  float opacity = aEffectsFrame->GetStyleDisplay()->mOpacity;
  if (opacity == 0.0f)
    return;

  /* Properties are added lazily and may have been removed by a restyle,
     so make sure all applicable ones are set again. */
  nsIFrame* firstFrame =
    nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aEffectsFrame);
  nsSVGEffects::EffectProperties effectProperties =
    nsSVGEffects::GetEffectProperties(firstFrame);

  /* SVG defines the following rendering model:
   *
   *  1. Render geometry
   *  2. Apply filter
   *  3. Apply clipping, masking, group opacity
   *
   * We follow this, but perform a couple of optimizations:
   *
   * + Use cairo's clipPath when representable natively (single object
   *   clip region).
   *
   * + Merge opacity and masking if both used together.
   */

  PRBool isOK = PR_TRUE;
  nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
  nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
  nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);

  PRBool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : PR_TRUE;

  if (!isOK) {
    // Some resource is missing. We shouldn't paint anything.
    return;
  }

  gfxContext* gfx = aCtx->ThebesContext();
  gfxMatrix savedCTM = gfx->CurrentMatrix();
  nsSVGRenderState svgContext(aCtx);

  nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame) + aBuilder->ToReferenceFrame(firstFrame);
  PRInt32 appUnitsPerDevPixel = aEffectsFrame->PresContext()->AppUnitsPerDevPixel();
  userSpaceRect = userSpaceRect.ToNearestPixels(appUnitsPerDevPixel).ToAppUnits(appUnitsPerDevPixel);
  aCtx->Translate(userSpaceRect.TopLeft());

  gfxMatrix matrix = GetInitialMatrix(aEffectsFrame);

  PRBool complexEffects = PR_FALSE;
  /* Check if we need to do additional operations on this child's
   * rendering, which necessitates rendering into another surface. */
  if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
    complexEffects = PR_TRUE;
    gfx->Save();
    aCtx->IntersectClip(aEffectsFrame->GetVisualOverflowRect());
    gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
  }

  /* If this frame has only a trivial clipPath, set up cairo's clipping now so
   * we can just do normal painting and get it clipped appropriately.
   */
  if (clipPathFrame && isTrivialClip) {
    gfx->Save();
    clipPathFrame->ClipPaint(&svgContext, aEffectsFrame, matrix);
  }

  /* Paint the child */
  if (filterFrame) {
    RegularFramePaintCallback paint(aBuilder, aInnerList, aEffectsFrame,
                                    userSpaceRect.TopLeft());
    nsIntRect r = (aDirtyRect - userSpaceRect.TopLeft()).ToOutsidePixels(appUnitsPerDevPixel);
    filterFrame->FilterPaint(&svgContext, aEffectsFrame, &paint, &r);
  } else {
    gfx->SetMatrix(savedCTM);
    aInnerList->PaintForFrame(aBuilder, aCtx, aEffectsFrame,
                              nsDisplayList::PAINT_DEFAULT);
    aCtx->Translate(userSpaceRect.TopLeft());
  }

  if (clipPathFrame && isTrivialClip) {
    gfx->Restore();
  }

  /* No more effects, we're done. */
  if (!complexEffects) {
    gfx->SetMatrix(savedCTM);
    return;
  }

  gfx->PopGroupToSource();

  nsRefPtr<gfxPattern> maskSurface =
    maskFrame ? maskFrame->ComputeMaskAlpha(&svgContext, aEffectsFrame,
                                            matrix, opacity) : nsnull;

  nsRefPtr<gfxPattern> clipMaskSurface;
  if (clipPathFrame && !isTrivialClip) {
    gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);

    nsresult rv = clipPathFrame->ClipPaint(&svgContext, aEffectsFrame, matrix);
    clipMaskSurface = gfx->PopGroup();

    if (NS_SUCCEEDED(rv) && clipMaskSurface) {
      // Still more set after clipping, so clip to another surface
      if (maskSurface || opacity != 1.0f) {
        gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
        gfx->Mask(clipMaskSurface);
        gfx->PopGroupToSource();
      } else {
        gfx->Mask(clipMaskSurface);
      }
    }
  }

  if (maskSurface) {
    gfx->Mask(maskSurface);
  } else if (opacity != 1.0f) {
    gfx->Paint(opacity);
  }

  gfx->Restore();
  gfx->SetMatrix(savedCTM);
}
Пример #5
0
void
DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time)
{
    Element* root = nullptr;
    nsIFrame* rootFrame = nullptr;
    nsRect rootRect;

    if (mRoot) {
        root = mRoot;
        rootFrame = root->GetPrimaryFrame();
        if (rootFrame) {
            if (rootFrame->GetType() == nsGkAtoms::scrollFrame) {
                nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
                rootRect = nsLayoutUtils::TransformFrameRectToAncestor(
                               rootFrame,
                               rootFrame->GetContentRectRelativeToSelf(),
                               scrollFrame->GetScrolledFrame());
            } else {
                rootRect = nsLayoutUtils::GetAllInFlowRectsUnion(rootFrame,
                           nsLayoutUtils::GetContainingBlockForClientRect(rootFrame),
                           nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
            }
        }
    } else {
        nsCOMPtr<nsIPresShell> presShell = aDocument->GetShell();
        if (presShell) {
            rootFrame = presShell->GetRootScrollFrame();
            if (rootFrame) {
                nsPresContext* presContext = rootFrame->PresContext();
                while (!presContext->IsRootContentDocument()) {
                    presContext = presContext->GetParentPresContext();
                    if (!presContext) {
                        break;
                    }
                    rootFrame = presContext->PresShell()->GetRootScrollFrame();
                }
                root = rootFrame->GetContent()->AsElement();
                nsIScrollableFrame* scrollFrame = do_QueryFrame(rootFrame);
                rootRect = scrollFrame->GetScrollPortRect();
            }
        }
    }

    nsMargin rootMargin;
    NS_FOR_CSS_SIDES(side) {
        nscoord basis = side == eSideTop || side == eSideBottom ?
                        rootRect.height : rootRect.width;
        nsCSSValue value = mRootMargin.*nsCSSRect::sides[side];
        nsStyleCoord coord;
        if (value.IsPixelLengthUnit()) {
            coord.SetCoordValue(value.GetPixelLength());
        } else if (value.IsPercentLengthUnit()) {
            coord.SetPercentValue(value.GetPercentValue());
        } else {
            MOZ_ASSERT_UNREACHABLE("invalid length unit");
        }
        rootMargin.Side(side) = nsLayoutUtils::ComputeCBDependentValue(basis, coord);
    }

    for (auto iter = mObservationTargets.Iter(); !iter.Done(); iter.Next()) {
        Element* target = iter.Get()->GetKey();
        nsIFrame* targetFrame = target->GetPrimaryFrame();
        nsRect targetRect;
        Maybe<nsRect> intersectionRect;

        if (rootFrame && targetFrame) {
            // If mRoot is set we are testing intersection with a container element
            // instead of the implicit root.
            if (mRoot) {
                // Skip further processing of this target if it is not in the same
                // Document as the intersection root, e.g. if root is an element of
                // the main document and target an element from an embedded iframe.
                if (target->GetComposedDoc() != root->GetComposedDoc()) {
                    continue;
                }
                // Skip further processing of this target if is not a descendant of the
                // intersection root in the containing block chain. E.g. this would be
                // the case if the target is in a position:absolute element whose
                // containing block is an ancestor of root.
                if (!nsLayoutUtils::IsAncestorFrameCrossDoc(rootFrame, targetFrame)) {
                    continue;
                }
            }

            targetRect = nsLayoutUtils::GetAllInFlowRectsUnion(
                             targetFrame,
                             nsLayoutUtils::GetContainingBlockForClientRect(targetFrame),
                             nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS
                         );
            intersectionRect = Some(targetFrame->GetVisualOverflowRect());

            nsIFrame* containerFrame = nsLayoutUtils::GetCrossDocParentFrame(targetFrame);
            while (containerFrame && containerFrame != rootFrame) {
                if (containerFrame->GetType() == nsGkAtoms::scrollFrame) {
                    nsIScrollableFrame* scrollFrame = do_QueryFrame(containerFrame);
                    nsRect subFrameRect = scrollFrame->GetScrollPortRect();
                    nsRect intersectionRectRelativeToContainer =
                        nsLayoutUtils::TransformFrameRectToAncestor(targetFrame,
                                intersectionRect.value(),
                                containerFrame);
                    intersectionRect = EdgeInclusiveIntersection(intersectionRectRelativeToContainer,
                                       subFrameRect);
                    if (!intersectionRect) {
                        break;
                    }
                    targetFrame = containerFrame;
                }

                // TODO: Apply clip-path.

                containerFrame = nsLayoutUtils::GetCrossDocParentFrame(containerFrame);
            }
        }

        nsRect rootIntersectionRect = rootRect;
        bool isInSimilarOriginBrowsingContext = rootFrame && targetFrame &&
                                                CheckSimilarOrigin(root, target);

        if (isInSimilarOriginBrowsingContext) {
            rootIntersectionRect.Inflate(rootMargin);
        }

        if (intersectionRect.isSome()) {
            nsRect intersectionRectRelativeToRoot =
                nsLayoutUtils::TransformFrameRectToAncestor(
                    targetFrame,
                    intersectionRect.value(),
                    nsLayoutUtils::GetContainingBlockForClientRect(rootFrame)
                );
            intersectionRect = EdgeInclusiveIntersection(
                                   intersectionRectRelativeToRoot,
                                   rootIntersectionRect
                               );
            if (intersectionRect.isSome()) {
                intersectionRect = Some(nsLayoutUtils::TransformFrameRectToAncestor(
                                            nsLayoutUtils::GetContainingBlockForClientRect(rootFrame),
                                            intersectionRect.value(),
                                            targetFrame->PresContext()->PresShell()->GetRootScrollFrame()
                                        ));
            }
        }

        double targetArea = targetRect.width * targetRect.height;
        double intersectionArea = !intersectionRect ?
                                  0 : intersectionRect->width * intersectionRect->height;
        double intersectionRatio = targetArea > 0.0 ? intersectionArea / targetArea : 0.0;

        size_t threshold = -1;
        if (intersectionRatio > 0.0) {
            if (intersectionRatio >= 1.0) {
                intersectionRatio = 1.0;
                threshold = mThresholds.Length();
            } else {
                for (size_t k = 0; k < mThresholds.Length(); ++k) {
                    if (mThresholds[k] <= intersectionRatio) {
                        threshold = k + 1;
                    } else {
                        break;
                    }
                }
            }
        } else if (intersectionRect.isSome()) {
            threshold = 0;
        }

        if (target->UpdateIntersectionObservation(this, threshold)) {
            QueueIntersectionObserverEntry(
                target, time,
                isInSimilarOriginBrowsingContext ? Some(rootIntersectionRect) : Nothing(),
                targetRect, intersectionRect, intersectionRatio
            );
        }
    }
}
Пример #6
0
void nsHTMLComboboxAccessible::CacheChildren()
{
  if (!mWeakShell) {
    // This node has been shut down
    mAccChildCount = eChildCountUninitialized;
    return;
  }

  if (mAccChildCount == eChildCountUninitialized) {
    mAccChildCount = 0;
#ifdef COMBO_BOX_WITH_THREE_CHILDREN
    // We no longer create textfield and button accessible, in order to have
    // harmonization between IAccessible2, ATK/AT-SPI and OS X
    nsHTMLComboboxTextFieldAccessible* textFieldAccessible = 
      new nsHTMLComboboxTextFieldAccessible(this, mDOMNode, mWeakShell);
    SetFirstChild(textFieldAccessible);
    if (!textFieldAccessible) {
      return;
    }
    textFieldAccessible->SetParent(this);
    textFieldAccessible->Init();
    mAccChildCount = 1;  // Textfield accessible child successfully added

    nsHTMLComboboxButtonAccessible* buttonAccessible =
      new nsHTMLComboboxButtonAccessible(mParent, mDOMNode, mWeakShell);
    textFieldAccessible->SetNextSibling(buttonAccessible);
    if (!buttonAccessible) {
      return;
    }

    buttonAccessible->SetParent(this);
    buttonAccessible->Init();
    mAccChildCount = 2; // Button accessible child successfully added
#endif

    nsIFrame *frame = GetFrame();
    if (!frame) {
      return;
    }
    nsIComboboxControlFrame *comboFrame = do_QueryFrame(frame);
    if (!comboFrame) {
      return;
    }
    nsIFrame *listFrame = comboFrame->GetDropDown();
    if (!listFrame) {
      return;
    }

    if (!mListAccessible) {
      mListAccessible = 
        new nsHTMLComboboxListAccessible(mParent, mDOMNode, mWeakShell);
      if (!mListAccessible)
        return;

      mListAccessible->Init();
    }

#ifdef COMBO_BOX_WITH_THREE_CHILDREN
    buttonAccessible->SetNextSibling(mListAccessible);
#else
    SetFirstChild(mListAccessible);
#endif

    mListAccessible->SetParent(this);
    mListAccessible->SetNextSibling(nsnull);

    ++ mAccChildCount;  // List accessible child successfully added
  }
}
Пример #7
0
nsINode*
PopupBoxObject::GetTriggerNode() const
{
  nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr;
  return nsMenuPopupFrame::GetTriggerContent(menuPopupFrame);
}
Пример #8
0
void
APZEventState::ProcessAPZStateChange(const nsCOMPtr<nsIDocument>& aDocument,
                                     ViewID aViewId,
                                     APZStateChange aChange,
                                     int aArg)
{
  switch (aChange)
  {
  case APZStateChange::TransformBegin:
  {
    nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
    if (sf) {
      sf->SetTransformingByAPZ(true);
    }
    nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
    if (scrollbarMediator) {
      scrollbarMediator->ScrollbarActivityStarted();
    }

    if (aDocument && mActiveAPZTransforms == 0) {
      nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
      if (docshell && sf) {
        nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
        nsdocshell->NotifyAsyncPanZoomStarted();
      }
    }
    mActiveAPZTransforms++;
    break;
  }
  case APZStateChange::TransformEnd:
  {
    mActiveAPZTransforms--;
    nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
    if (sf) {
      sf->SetTransformingByAPZ(false);
    }
    nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
    if (scrollbarMediator) {
      scrollbarMediator->ScrollbarActivityStopped();
    }

    if (aDocument && mActiveAPZTransforms == 0) {
      nsCOMPtr<nsIDocShell> docshell(aDocument->GetDocShell());
      if (docshell && sf) {
        nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
        nsdocshell->NotifyAsyncPanZoomStopped();
      }
    }
    break;
  }
  case APZStateChange::StartTouch:
  {
    mActiveElementManager->HandleTouchStart(aArg);
    break;
  }
  case APZStateChange::StartPanning:
  {
    mActiveElementManager->HandlePanStart();
    break;
  }
  case APZStateChange::EndTouch:
  {
    mEndTouchIsClick = aArg;
    mActiveElementManager->HandleTouchEnd();
    break;
  }
  default:
    // APZStateChange has a 'sentinel' value, and the compiler complains
    // if an enumerator is not handled and there is no 'default' case.
    break;
  }
}
Пример #9
0
NS_IMETHODIMP
nsPopupSetFrame::DoLayout(nsBoxLayoutState& aState)
{
  // lay us out
  nsresult rv = nsBoxFrame::DoLayout(aState);

  // lay out all of our currently open popups.
  nsPopupFrameList* currEntry = mPopupList;
  while (currEntry) {
    nsMenuPopupFrame* popupChild = currEntry->mPopupFrame;
    if (popupChild && popupChild->IsOpen()) {
      // then get its preferred size
      nsSize prefSize = popupChild->GetPrefSize(aState);
      nsSize minSize = popupChild->GetMinSize(aState);
      nsSize maxSize = popupChild->GetMaxSize(aState);

      prefSize = BoundsCheck(minSize, prefSize, maxSize);

      popupChild->SetPreferredBounds(aState, nsRect(0,0,prefSize.width, prefSize.height));
      popupChild->SetPopupPosition(nsnull);

      // is the new size too small? Make sure we handle scrollbars correctly
      nsIBox* child = popupChild->GetChildBox();

      nsRect bounds(popupChild->GetRect());

      nsIScrollableFrame *scrollframe = do_QueryFrame(child);
      if (scrollframe &&
          scrollframe->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_AUTO) {
        // if our pref height
        if (bounds.height < prefSize.height) {
          // layout the child
          popupChild->Layout(aState);

          nsMargin scrollbars = scrollframe->GetActualScrollbarSizes();
          if (bounds.width < prefSize.width + scrollbars.left + scrollbars.right)
          {
            bounds.width += scrollbars.left + scrollbars.right;
            popupChild->SetBounds(aState, bounds);
          }
        }
      }

      // layout the child
      popupChild->Layout(aState);
      // if the width or height changed, readjust the popup position. This is a
      // special case for tooltips where the preferred height doesn't include the
      // real height for its inline element, but does once it is laid out.
      // This is bug 228673 which doesn't have a simple fix.
      if (popupChild->GetRect().width > bounds.width ||
          popupChild->GetRect().height > bounds.height) {
        // the size after layout was larger than the preferred size,
        // so set the preferred size accordingly
        popupChild->SetPreferredSize(popupChild->GetSize());
        popupChild->SetPopupPosition(nsnull);
      }
      popupChild->AdjustView();
    }

    currEntry = currEntry->mNextPopup;
  }

  return rv;
}
Пример #10
0
nsMenuFrame*
nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
{
  uint32_t charCode;
  aKeyEvent->GetCharCode(&charCode);

  nsAutoTArray<uint32_t, 10> accessKeys;
  nsEvent* nativeEvent = nsContentUtils::GetNativeEvent(aKeyEvent);
  nsKeyEvent* nativeKeyEvent = static_cast<nsKeyEvent*>(nativeEvent);
  if (nativeKeyEvent)
    nsContentUtils::GetAccessKeyCandidates(nativeKeyEvent, accessKeys);
  if (accessKeys.IsEmpty() && charCode)
    accessKeys.AppendElement(charCode);

  if (accessKeys.IsEmpty())
    return nullptr; // no character was pressed so just return

  // Enumerate over our list of frames.
  nsIFrame* immediateParent = nullptr;
  GetInsertionPoint(PresContext()->PresShell(), this, nullptr, &immediateParent);
  if (!immediateParent)
    immediateParent = this;

  // Find a most preferred accesskey which should be returned.
  nsIFrame* foundMenu = nullptr;
  uint32_t foundIndex = accessKeys.NoIndex;
  nsIFrame* currFrame = immediateParent->GetFirstPrincipalChild();

  while (currFrame) {
    nsIContent* current = currFrame->GetContent();

    // See if it's a menu item.
    if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, false)) {
      // Get the shortcut attribute.
      nsAutoString shortcutKey;
      current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, shortcutKey);
      if (!shortcutKey.IsEmpty()) {
        ToLowerCase(shortcutKey);
        const PRUnichar* start = shortcutKey.BeginReading();
        const PRUnichar* end = shortcutKey.EndReading();
        uint32_t ch = UTF16CharEnumerator::NextChar(&start, end);
        uint32_t index = accessKeys.IndexOf(ch);
        if (index != accessKeys.NoIndex &&
            (foundIndex == accessKeys.NoIndex || index < foundIndex)) {
          foundMenu = currFrame;
          foundIndex = index;
        }
      }
    }
    currFrame = currFrame->GetNextSibling();
  }
  if (foundMenu) {
    return do_QueryFrame(foundMenu);
  }

  // didn't find a matching menu item
#ifdef XP_WIN
  // behavior on Windows - this item is on the menu bar, beep and deactivate the menu bar
  if (mIsActive) {
    nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
    if (soundInterface)
      soundInterface->Beep();
  }

  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
  if (pm) {
    nsIFrame* popup = pm->GetTopPopup(ePopupTypeAny);
    if (popup)
      pm->HidePopup(popup->GetContent(), true, true, true);
  }

  SetCurrentMenuItem(nullptr);
  SetActive(false);

#endif  // #ifdef XP_WIN

  return nullptr;
}
nsSVGTextContainerFrame*
SVGTextContentElement::GetTextContainerFrame()
{
  return do_QueryFrame(GetPrimaryFrame(Flush_Layout));
}
gfxRect
nsSVGMarkerFrame::GetMarkBBoxContribution(const gfxMatrix &aToBBoxUserspace,
                                          PRUint32 aFlags,
                                          nsSVGPathGeometryFrame *aMarkedFrame,
                                          const nsSVGMark *aMark,
                                          float aStrokeWidth)
{
  // If the flag is set when we get here, it means this marker frame
  // has already been used in calculating the current mark bbox, and
  // the document has a marker reference loop.
  if (mInUse)
    return gfxRect();

  AutoMarkerReferencer markerRef(this, aMarkedFrame);

  nsSVGMarkerElement *content = static_cast<nsSVGMarkerElement*>(mContent);

  const nsSVGViewBoxRect viewBox = content->GetViewBoxRect();

  if (viewBox.width <= 0.0f || viewBox.height <= 0.0f) {
    return gfxRect();
  }

  mStrokeWidth = aStrokeWidth;
  mX = aMark->x;
  mY = aMark->y;
  mAutoAngle = aMark->angle;

  gfxMatrix markerTM =
    content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle);
  gfxMatrix viewBoxTM = content->GetViewBoxTransform();

  gfxMatrix tm = viewBoxTM * markerTM * aToBBoxUserspace;

  gfxRect bbox;
  bool firstChild = true;

  for (nsIFrame* kid = mFrames.FirstChild();
       kid;
       kid = kid->GetNextSibling()) {
    nsISVGChildFrame* child = do_QueryFrame(kid);
    if (child) {
      // When we're being called to obtain the invalidation area, we need to
      // pass down all the flags so that stroke is included. However, once DOM
      // getBBox() accepts flags, maybe we should strip some of those here?

      // We need to include zero width/height vertical/horizontal lines, so we have
      // to use UnionEdges, but we must special case the first bbox so that we don't
      // include the initial gfxRect(0,0,0,0).
      gfxRect childBBox = child->GetBBoxContribution(tm, aFlags);
      if (firstChild && (childBBox.Width() > 0 || childBBox.Height() > 0)) {
        bbox = childBBox;
        firstChild = false;
        continue;
      }
      bbox = bbox.UnionEdges(childBBox);
    }
  }

  return bbox;
}
Пример #13
0
void
APZEventState::ProcessAPZStateChange(ViewID aViewId,
                                     APZStateChange aChange,
                                     int aArg)
{
  switch (aChange)
  {
  case APZStateChange::eTransformBegin:
  {
    nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
    if (sf) {
      sf->SetTransformingByAPZ(true);
    }
    nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
    if (scrollbarMediator) {
      scrollbarMediator->ScrollbarActivityStarted();
    }

    nsIContent* content = nsLayoutUtils::FindContentFor(aViewId);
    nsIDocument* doc = content ? content->GetComposedDoc() : nullptr;
    nsCOMPtr<nsIDocShell> docshell(doc ? doc->GetDocShell() : nullptr);
    if (docshell && sf) {
      nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
      nsdocshell->NotifyAsyncPanZoomStarted();
    }
    break;
  }
  case APZStateChange::eTransformEnd:
  {
    nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
    if (sf) {
      sf->SetTransformingByAPZ(false);
    }
    nsIScrollbarMediator* scrollbarMediator = do_QueryFrame(sf);
    if (scrollbarMediator) {
      scrollbarMediator->ScrollbarActivityStopped();
    }

    nsIContent* content = nsLayoutUtils::FindContentFor(aViewId);
    nsIDocument* doc = content ? content->GetComposedDoc() : nullptr;
    nsCOMPtr<nsIDocShell> docshell(doc ? doc->GetDocShell() : nullptr);
    if (docshell && sf) {
      nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
      nsdocshell->NotifyAsyncPanZoomStopped();
    }
    break;
  }
  case APZStateChange::eStartTouch:
  {
    mActiveElementManager->HandleTouchStart(aArg);
    break;
  }
  case APZStateChange::eStartPanning:
  {
    // The user started to pan, so we don't want anything to be :active.
    mActiveElementManager->ClearActivation();
    break;
  }
  case APZStateChange::eEndTouch:
  {
    mEndTouchIsClick = aArg;
    mActiveElementManager->HandleTouchEnd();
    break;
  }
  case APZStateChange::eSentinel:
    // Should never happen, but we want this case branch to stop the compiler
    // whining about unhandled values.
    MOZ_ASSERT(false);
    break;
  }
}
Пример #14
0
void
nsComboboxControlFrame::SetDropDown(nsIFrame* aDropDownFrame)
{
  mDropdownFrame = aDropDownFrame;
  mListControlFrame = do_QueryFrame(mDropdownFrame);
}
Пример #15
0
NS_IMETHODIMP 
nsComboboxControlFrame::Reflow(nsPresContext*          aPresContext, 
                               nsHTMLReflowMetrics&     aDesiredSize,
                               const nsHTMLReflowState& aReflowState, 
                               nsReflowStatus&          aStatus)
{
  // Constraints we try to satisfy:

  // 1) Default width of button is the vertical scrollbar size
  // 2) If the width of button is bigger than our width, set width of
  //    button to 0.
  // 3) Default height of button is height of display area
  // 4) Width of display area is whatever is left over from our width after
  //    allocating width for the button.
  // 5) Height of display area is GetHeightOfARow() on the
  //    mListControlFrame.

  if (!mDisplayFrame || !mButtonFrame || !mDropdownFrame) {
    NS_ERROR("Why did the frame constructor allow this to happen?  Fix it!!");
    return NS_ERROR_UNEXPECTED;
  }

  // Make sure the displayed text is the same as the selected option, bug 297389.
  PRInt32 selectedIndex;
  nsAutoString selectedOptionText;
  if (!mDroppedDown) {
    selectedIndex = mListControlFrame->GetSelectedIndex();
  }
  else {
    // In dropped down mode the "selected index" is the hovered menu item,
    // we want the last selected item which is |mDisplayedIndex| in this case.
    selectedIndex = mDisplayedIndex;
  }
  if (selectedIndex != -1) {
    mListControlFrame->GetOptionText(selectedIndex, selectedOptionText);
  }
  if (mDisplayedOptionText != selectedOptionText) {
    RedisplayText(selectedIndex);
  }

  // First reflow our dropdown so that we know how tall we should be.
  ReflowDropdown(aPresContext, aReflowState);

  // Get the width of the vertical scrollbar.  That will be the width of the
  // dropdown button.
  nscoord buttonWidth;
  const nsStyleDisplay *disp = GetStyleDisplay();
  if (IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) {
    buttonWidth = 0;
  }
  else {
    nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
    NS_ASSERTION(scrollable, "List must be a scrollable frame");
    buttonWidth =
      scrollable->GetDesiredScrollbarSizes(PresContext(), 
                                           aReflowState.rendContext).LeftRight();
    if (buttonWidth > aReflowState.ComputedWidth()) {
      buttonWidth = 0;
    }
  }

  mDisplayWidth = aReflowState.ComputedWidth() - buttonWidth;

  nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState,
                                    aStatus);
  NS_ENSURE_SUCCESS(rv, rv);

  // Now set the correct width and height on our button.  The width we need to
  // set always, the height only if we had an auto height.
  nsRect buttonRect = mButtonFrame->GetRect();
  // If we have a non-intrinsic computed height, our kids should have sized
  // themselves properly on their own.
  if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
    // The display frame is going to be the right height and width at this
    // point. Use its height as the button height.
    nsRect displayRect = mDisplayFrame->GetRect();
    buttonRect.height = displayRect.height;
    buttonRect.y = displayRect.y;
  }
#ifdef DEBUG
  else {
    nscoord buttonHeight = mButtonFrame->GetSize().height;
    nscoord displayHeight = mDisplayFrame->GetSize().height;

    // The button and display area should be equal heights, unless the computed
    // height on the combobox is too small to fit their borders and padding.
    NS_ASSERTION(buttonHeight == displayHeight ||
                 (aReflowState.ComputedHeight() < buttonHeight &&
                  buttonHeight ==
                    mButtonFrame->GetUsedBorderAndPadding().TopBottom()) ||
                 (aReflowState.ComputedHeight() < displayHeight &&
                  displayHeight ==
                    mDisplayFrame->GetUsedBorderAndPadding().TopBottom()),
                 "Different heights?");
  }
#endif
  
  if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
    // Make sure the right edge of the button frame stays where it is now
    buttonRect.x -= buttonWidth - buttonRect.width;
  }
  buttonRect.width = buttonWidth;
  mButtonFrame->SetRect(buttonRect);
  
  return rv;
}
Пример #16
0
nsTextControlFrame*
nsFileControlFrame::GetTextControlFrame()
{
  nsITextControlFrame* tc = do_QueryFrame(mTextContent->GetPrimaryFrame());
  return static_cast<nsTextControlFrame*>(tc);
}
Пример #17
0
NS_IMETHODIMP
nsSubDocumentFrame::AttributeChanged(PRInt32 aNameSpaceID,
                                     nsIAtom* aAttribute,
                                     PRInt32 aModType)
{
  if (aNameSpaceID != kNameSpaceID_None) {
    return NS_OK;
  }
  
  // If the noResize attribute changes, dis/allow frame to be resized
  if (aAttribute == nsGkAtoms::noresize) {
    // Note that we're not doing content type checks, but that's ok -- if
    // they'd fail we will just end up with a null framesetFrame.
    if (mContent->GetParent()->Tag() == nsGkAtoms::frameset) {
      nsIFrame* parentFrame = GetParent();

      if (parentFrame) {
        // There is no interface for nsHTMLFramesetFrame so QI'ing to
        // concrete class, yay!
        nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
        if (framesetFrame) {
          framesetFrame->RecalculateBorderResize();
        }
      }
    }
  }
  else if (aAttribute == nsGkAtoms::type) {
    if (!mFrameLoader) 
      return NS_OK;

    if (!mContent->IsNodeOfType(nsINode::eXUL)) {
      return NS_OK;
    }

    // Note: This logic duplicates a lot of logic in
    // nsFrameLoader::EnsureDocShell.  We should fix that.

    // Notify our enclosing chrome that our type has changed.  We only do this
    // if our parent is chrome, since in all other cases we're random content
    // subframes and the treeowner shouldn't worry about us.

    nsCOMPtr<nsIDocShell> docShell;
    mFrameLoader->GetDocShell(getter_AddRefs(docShell));
    nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
    if (!docShellAsItem) {
      return NS_OK;
    }

    nsCOMPtr<nsIDocShellTreeItem> parentItem;
    docShellAsItem->GetParent(getter_AddRefs(parentItem));
    if (!parentItem) {
      return NS_OK;
    }

    PRInt32 parentType;
    parentItem->GetItemType(&parentType);

    if (parentType != nsIDocShellTreeItem::typeChrome) {
      return NS_OK;
    }

    nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
    parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
    if (parentTreeOwner) {
      nsAutoString value;
      mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);

      PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary");

#ifdef MOZ_XUL
      // when a content panel is no longer primary, hide any open popups it may have
      if (!is_primary) {
        nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
        if (pm)
          pm->HidePopupsInDocShell(docShellAsItem);
      }
#endif

      parentTreeOwner->ContentShellRemoved(docShellAsItem);

      if (value.LowerCaseEqualsLiteral("content") ||
          StringBeginsWith(value, NS_LITERAL_STRING("content-"),
                           nsCaseInsensitiveStringComparator())) {
        PRBool is_targetable = is_primary ||
          value.LowerCaseEqualsLiteral("content-targetable");

        parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
                                           is_targetable, value);
      }
    }
  }

  return NS_OK;
}
Пример #18
0
NS_IMETHODIMP
nsPopupSetFrame::List(FILE* out, PRInt32 aIndent) const
{
  IndentBy(out, aIndent);
  ListTag(out);
#ifdef DEBUG_waterson
  fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
#endif
  if (HasView()) {
    fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
  }
  if (nsnull != mNextSibling) {
    fprintf(out, " next=%p", static_cast<void*>(mNextSibling));
  }
  if (nsnull != GetPrevContinuation()) {
    fprintf(out, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
  }
  if (nsnull != GetNextContinuation()) {
    fprintf(out, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
  }
  fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
  if (0 != mState) {
    fprintf(out, " [state=%08x]", mState);
  }
  fprintf(out, " [content=%p]", static_cast<void*>(mContent));
  nsPopupSetFrame* f = const_cast<nsPopupSetFrame*>(this);
  if (f->HasOverflowRect()) {
    nsRect overflowArea = f->GetOverflowRect();
    fprintf(out, " [overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
            overflowArea.width, overflowArea.height);
  }
  fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
  nsIAtom* pseudoTag = mStyleContext->GetPseudoType();
  if (pseudoTag) {
    nsAutoString atomString;
    pseudoTag->ToString(atomString);
    fprintf(out, " pst=%s",
            NS_LossyConvertUTF16toASCII(atomString).get());
  }

  // Output the children
  nsIAtom* listName = nsnull;
  PRInt32 listIndex = 0;
  PRBool outputOneList = PR_FALSE;
  do {
    nsIFrame* kid = GetFirstChild(listName);
    if (nsnull != kid) {
      if (outputOneList) {
        IndentBy(out, aIndent);
      }
      outputOneList = PR_TRUE;
      nsAutoString tmp;
      if (nsnull != listName) {
        listName->ToString(tmp);
        fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
      }
      fputs("<\n", out);
      while (nsnull != kid) {
        // Verify the child frame's parent frame pointer is correct
        NS_ASSERTION(kid->GetParent() == (nsIFrame*)this, "bad parent frame pointer");

        // Have the child frame list
        nsIFrameDebug*  frameDebug = do_QueryFrame(kid);
        if (frameDebug) {
          frameDebug->List(out, aIndent + 1);
        }
        kid = kid->GetNextSibling();
      }
      IndentBy(out, aIndent);
      fputs(">\n", out);
    }
    listName = GetAdditionalChildListName(listIndex++);
  } while(nsnull != listName);

  // XXXmats the above is copy-pasted from nsContainerFrame::List which is lame,
  // clean this up after bug 399111 is implemented.

  if (mPopupList) {
    fputs("<\n", out);
    ++aIndent;
    IndentBy(out, aIndent);
    nsAutoString tmp;
    nsGkAtoms::popupList->ToString(tmp);
    fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
    fputs(" for ", out);
    ListTag(out);
    fputs(" <\n", out);
    ++aIndent;
    for (nsPopupFrameList* l = mPopupList; l; l = l->mNextPopup) {
      nsIFrameDebug* frameDebug = do_QueryFrame(l->mPopupFrame);
      if (frameDebug) {
        frameDebug->List(out, aIndent);
      }
    }
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    --aIndent;
    IndentBy(out, aIndent);
    fputs(">\n", out);
    outputOneList = PR_TRUE;
  }

  if (!outputOneList) {
    fputs("<>\n", out);
  }

  return NS_OK;
}
Пример #19
0
void
nsFindContentIterator::SetupInnerIterator(nsIContent* aContent)
{
  if (!aContent) {
    return;
  }
  NS_ASSERTION(!aContent->IsRootOfNativeAnonymousSubtree(), "invalid call");

  nsITextControlFrame* tcFrame = do_QueryFrame(aContent->GetPrimaryFrame());
  if (!tcFrame)
    return;

  nsCOMPtr<nsIEditor> editor;
  tcFrame->GetEditor(getter_AddRefs(editor));
  if (!editor)
    return;

  // don't mess with disabled input fields
  PRUint32 editorFlags = 0;
  editor->GetFlags(&editorFlags);
  if (editorFlags & nsIPlaintextEditor::eEditorDisabledMask)
    return;

  nsCOMPtr<nsIDOMElement> rootElement;
  editor->GetRootElement(getter_AddRefs(rootElement));
  nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement));

  nsCOMPtr<nsIDOMRange> innerRange = nsFind::CreateRange();
  nsCOMPtr<nsIDOMRange> outerRange = nsFind::CreateRange();
  if (!innerRange || !outerRange) {
    return;
  }
     
  // now create the inner-iterator
  mInnerIterator = do_CreateInstance(kCPreContentIteratorCID);

  if (mInnerIterator) {
    innerRange->SelectNodeContents(rootElement);

    // fix up the inner bounds, we may have to only lookup a portion
    // of the text control if the current node is a boundary point
    if (aContent == mStartOuterContent) {
      innerRange->SetStart(mStartNode, mStartOffset);
    }
    if (aContent == mEndOuterContent) {
      innerRange->SetEnd(mEndNode, mEndOffset);
    }
    // Note: we just init here. We do First() or Last() later. 
    mInnerIterator->Init(innerRange);

    // make sure to place the outer-iterator outside
    // the text control so that we don't go there again.
    nsresult res;
    nsCOMPtr<nsIDOMNode> outerNode(do_QueryInterface(aContent));
    if (!mFindBackward) { // find forward
      // cut the outer-iterator after the current node
      res = outerRange->SetEnd(mEndNode, mEndOffset);
      res |= outerRange->SetStartAfter(outerNode);
    }
    else { // find backward
      // cut the outer-iterator before the current node
      res = outerRange->SetStart(mStartNode, mStartOffset);
      res |= outerRange->SetEndBefore(outerNode);
    }
    if (NS_FAILED(res)) {
      // we are done with the outer-iterator, the 
      // inner-iterator will traverse what we want
      outerRange->Collapse(true);
    }

    // Note: we just re-init here, using the segment of our search range that
    // is yet to be visited. Thus when we later do mOuterIterator->First() [or
    // mOuterIterator->Last()], we will effectively be on the next node [or
    // the previous node] _with respect to_ the search range.
    mOuterIterator->Init(outerRange);
  }
}
Пример #20
0
already_AddRefed<gfxPattern>
nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
                                 nsIFrame* aParent,
                                 const gfxMatrix &aMatrix,
                                 float aOpacity)
{
  // If the flag is set when we get here, it means this mask frame
  // has already been used painting the current mask, and the document
  // has a mask reference loop.
  if (mInUse) {
    NS_WARNING("Mask loop detected!");
    return nsnull;
  }
  AutoMaskReferencer maskRef(this);

  nsSVGMaskElement *mask = static_cast<nsSVGMaskElement*>(mContent);

  PRUint16 units =
    mask->mEnumAttributes[nsSVGMaskElement::MASKUNITS].GetAnimValue();
  gfxRect bbox;
  if (units == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    bbox = nsSVGUtils::GetBBox(aParent);
  }

  gfxRect maskArea = nsSVGUtils::GetRelativeRect(units,
    &mask->mLengthAttributes[nsSVGMaskElement::X], bbox, aParent);

  gfxContext *gfx = aContext->GetGfxContext();

  gfx->Save();
  nsSVGUtils::SetClipRect(gfx, aMatrix, maskArea);
  gfxRect clipExtents = gfx->GetClipExtents();
  clipExtents.RoundOut();
  gfx->Restore();

#ifdef DEBUG_tor
  fprintf(stderr, "clip extent: %f,%f %fx%f\n",
          clipExtents.X(), clipExtents.Y(),
          clipExtents.Width(), clipExtents.Height());
#endif

  bool resultOverflows;
  gfxIntSize surfaceSize =
    nsSVGUtils::ConvertToSurfaceSize(gfxSize(clipExtents.Width(),
                                             clipExtents.Height()),
                                     &resultOverflows);

  // 0 disables mask, < 0 is an error
  if (surfaceSize.width <= 0 || surfaceSize.height <= 0)
    return nsnull;

  if (resultOverflows)
    return nsnull;

  nsRefPtr<gfxImageSurface> image =
    new gfxImageSurface(surfaceSize, gfxASurface::ImageFormatARGB32);
  if (!image || image->CairoStatus())
    return nsnull;
  image->SetDeviceOffset(-clipExtents.TopLeft());

  nsSVGRenderState tmpState(image);

  mMaskParent = aParent;
  if (mMaskParentMatrix) {
    *mMaskParentMatrix = aMatrix;
  } else {
    mMaskParentMatrix = new gfxMatrix(aMatrix);
  }

  for (nsIFrame* kid = mFrames.FirstChild(); kid;
       kid = kid->GetNextSibling()) {
    // The CTM of each frame referencing us can be different
    nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
    if (SVGFrame) {
      SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
                                 nsISVGChildFrame::TRANSFORM_CHANGED);
    }
    nsSVGUtils::PaintFrameWithEffects(&tmpState, nsnull, kid);
  }

  PRUint8 *data   = image->Data();
  PRInt32  stride = image->Stride();

  nsIntRect rect(0, 0, surfaceSize.width, surfaceSize.height);
  nsSVGUtils::UnPremultiplyImageDataAlpha(data, stride, rect);
  if (GetStyleSVG()->mColorInterpolation ==
      NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
    nsSVGUtils::ConvertImageDataToLinearRGB(data, stride, rect);
  }

  for (PRInt32 y = 0; y < surfaceSize.height; y++)
    for (PRInt32 x = 0; x < surfaceSize.width; x++) {
      PRUint8 *pixel = data + stride * y + 4 * x;

      /* linearRGB -> intensity */
      PRUint8 alpha =
        static_cast<PRUint8>
                   ((pixel[GFX_ARGB32_OFFSET_R] * 0.2125 +
                        pixel[GFX_ARGB32_OFFSET_G] * 0.7154 +
                        pixel[GFX_ARGB32_OFFSET_B] * 0.0721) *
                       (pixel[GFX_ARGB32_OFFSET_A] / 255.0) * aOpacity);

      memset(pixel, alpha, 4);
    }

  gfxPattern *retval = new gfxPattern(image);
  NS_IF_ADDREF(retval);
  return retval;
}
Пример #21
0
/**
  * Helper method for getting the focused DOM Node from our parent(list) node. We
  *  need to use the frame to get the focused option because for some reason we
  *  weren't getting the proper notification when the focus changed using the DOM
  */
nsresult nsHTMLSelectOptionAccessible::GetFocusedOptionNode(nsIDOMNode *aListNode, 
                                                            nsIDOMNode **aFocusedOptionNode)
{
  *aFocusedOptionNode = nsnull;
  NS_ASSERTION(aListNode, "Called GetFocusedOptionNode without a valid list node");

  nsCOMPtr<nsIContent> content(do_QueryInterface(aListNode));
  nsCOMPtr<nsIDocument> document = content->GetDocument();
  nsIPresShell *shell = nsnull;
  if (document)
    shell = document->GetPrimaryShell();
  if (!shell)
    return NS_ERROR_FAILURE;

  nsIFrame *frame = shell->GetPrimaryFrameFor(content);
  if (!frame)
    return NS_ERROR_FAILURE;

  PRInt32 focusedOptionIndex = 0;

  // Get options
  nsCOMPtr<nsIDOMHTMLSelectElement> selectElement(do_QueryInterface(aListNode));
  NS_ASSERTION(selectElement, "No select element where it should be");

  nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
  nsresult rv = selectElement->GetOptions(getter_AddRefs(options));
  
  if (NS_SUCCEEDED(rv)) {
    nsIListControlFrame *listFrame = do_QueryFrame(frame);
    if (listFrame) {
      // Get what's focused in listbox by asking frame for "selected item". 
      // Can't use dom interface for this, because it will always return the first selected item
      // when there is more than 1 item selected. We need the focused item, not
      // the first selected item.
      focusedOptionIndex = listFrame->GetSelectedIndex();
      if (focusedOptionIndex == -1) {
        nsCOMPtr<nsIDOMNode> nextOption;
        while (PR_TRUE) {
          ++ focusedOptionIndex;
          options->Item(focusedOptionIndex, getter_AddRefs(nextOption));
          nsCOMPtr<nsIDOMHTMLOptionElement> optionElement = do_QueryInterface(nextOption);
          if (!optionElement) {
            break;
          }
          PRBool disabled;
          optionElement->GetDisabled(&disabled);
          if (!disabled) {
            break;
          }
        }
      }
    }
    else  // Combo boxes can only have 1 selected option, so they can use the dom interface for this
      rv = selectElement->GetSelectedIndex(&focusedOptionIndex);
  }

  // Either use options and focused index, or default return null
  if (NS_SUCCEEDED(rv) && options && focusedOptionIndex >= 0) {  // Something is focused
    rv = options->Item(focusedOptionIndex, aFocusedOptionNode);
  }

  return rv;
}
Пример #22
0
nsRefreshDriver*
ScrollbarActivity::GetRefreshDriver()
{
  nsIFrame* scrollableFrame = do_QueryFrame(mScrollableFrame);
  return scrollableFrame->PresContext()->RefreshDriver();
}
already_AddRefed<gfxPattern>
nsSVGMaskFrame::ComputeMaskAlpha(nsRenderingContext *aContext,
                                 nsIFrame* aParent,
                                 const gfxMatrix &aMatrix,
                                 float aOpacity)
{
  // If the flag is set when we get here, it means this mask frame
  // has already been used painting the current mask, and the document
  // has a mask reference loop.
  if (mInUse) {
    NS_WARNING("Mask loop detected!");
    return nullptr;
  }
  AutoMaskReferencer maskRef(this);

  nsSVGMaskElement *mask = static_cast<nsSVGMaskElement*>(mContent);

  uint16_t units =
    mask->mEnumAttributes[nsSVGMaskElement::MASKUNITS].GetAnimValue();
  gfxRect bbox;
  if (units == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    bbox = nsSVGUtils::GetBBox(aParent);
  }

  gfxRect maskArea = nsSVGUtils::GetRelativeRect(units,
    &mask->mLengthAttributes[nsSVGMaskElement::X], bbox, aParent);

  gfxContext *gfx = aContext->ThebesContext();

  // Get the clip extents in device space:
  gfx->Save();
  nsSVGUtils::SetClipRect(gfx, aMatrix, maskArea);
  gfx->IdentityMatrix();
  gfxRect clipExtents = gfx->GetClipExtents();
  clipExtents.RoundOut();
  gfx->Restore();

  bool resultOverflows;
  gfxIntSize surfaceSize =
    nsSVGUtils::ConvertToSurfaceSize(gfxSize(clipExtents.Width(),
                                             clipExtents.Height()),
                                     &resultOverflows);

  // 0 disables mask, < 0 is an error
  if (surfaceSize.width <= 0 || surfaceSize.height <= 0)
    return nullptr;

  if (resultOverflows)
    return nullptr;

  nsRefPtr<gfxImageSurface> image =
    new gfxImageSurface(surfaceSize, gfxASurface::ImageFormatARGB32);
  if (!image || image->CairoStatus())
    return nullptr;

  // We would like to use gfxImageSurface::SetDeviceOffset() to position
  // 'image'. However, we need to set the same matrix on the temporary context
  // and pattern that we create below as is currently set on 'gfx'.
  // Unfortunately, any device offset set by SetDeviceOffset() is affected by
  // the transform passed to the SetMatrix() calls, so to avoid that we account
  // for the device offset in the transform rather than use SetDeviceOffset().
  gfxMatrix matrix =
    gfx->CurrentMatrix() * gfxMatrix().Translate(-clipExtents.TopLeft());

  nsRenderingContext tmpCtx;
  tmpCtx.Init(this->PresContext()->DeviceContext(), image);
  tmpCtx.ThebesContext()->SetMatrix(matrix);

  mMaskParent = aParent;
  if (mMaskParentMatrix) {
    *mMaskParentMatrix = aMatrix;
  } else {
    mMaskParentMatrix = new gfxMatrix(aMatrix);
  }

  for (nsIFrame* kid = mFrames.FirstChild(); kid;
       kid = kid->GetNextSibling()) {
    // The CTM of each frame referencing us can be different
    nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
    if (SVGFrame) {
      SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
    }
    nsSVGUtils::PaintFrameWithEffects(&tmpCtx, nullptr, kid);
  }

  uint8_t *data   = image->Data();
  int32_t  stride = image->Stride();

  nsIntRect rect(0, 0, surfaceSize.width, surfaceSize.height);
  nsSVGUtils::UnPremultiplyImageDataAlpha(data, stride, rect);
  if (GetStyleSVG()->mColorInterpolation ==
      NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
    nsSVGUtils::ConvertImageDataToLinearRGB(data, stride, rect);
  }

  for (int32_t y = 0; y < surfaceSize.height; y++)
    for (int32_t x = 0; x < surfaceSize.width; x++) {
      uint8_t *pixel = data + stride * y + 4 * x;

      /* linearRGB -> intensity */
      uint8_t alpha =
        static_cast<uint8_t>
                   ((pixel[GFX_ARGB32_OFFSET_R] * 0.2125 +
                        pixel[GFX_ARGB32_OFFSET_G] * 0.7154 +
                        pixel[GFX_ARGB32_OFFSET_B] * 0.0721) *
                       (pixel[GFX_ARGB32_OFFSET_A] / 255.0) * aOpacity);

      memset(pixel, alpha, 4);
    }

  gfxPattern *retval = new gfxPattern(image);
  retval->SetMatrix(matrix);
  NS_IF_ADDREF(retval);
  return retval;
}
Пример #24
0
// get our 'form' and lookup in the Operator Dictionary to fetch 
// our default data that may come from there. Then complete our setup
// using attributes that we may have. To stay in sync, this function is
// called very often. We depend on many things that may change around us.
// However, we re-use unchanged values.
void
nsMathMLmoFrame::ProcessOperatorData()
{
  // if we have been here before, we will just use our cached form
  nsOperatorFlags form = NS_MATHML_OPERATOR_GET_FORM(mFlags);
  nsAutoString value;

  // special bits are always kept in mFlags.
  // remember the mutable bit from ProcessTextData().
  // Some chars are listed under different forms in the dictionary,
  // and there could be a form under which the char is mutable.
  // If the char is the core of an embellished container, we will keep
  // it mutable irrespective of the form of the embellished container.
  // Also remember the other special bits that we want to carry forward.
  mFlags &= NS_MATHML_OPERATOR_MUTABLE |
            NS_MATHML_OPERATOR_ACCENT | 
            NS_MATHML_OPERATOR_MOVABLELIMITS |
            NS_MATHML_OPERATOR_CENTERED |
            NS_MATHML_OPERATOR_INVISIBLE;

  if (!mEmbellishData.coreFrame) {
    // i.e., we haven't been here before, the default form is infix
    form = NS_MATHML_OPERATOR_FORM_INFIX;

    // reset everything so that we don't keep outdated values around
    // in case of dynamic changes
    mEmbellishData.flags = 0;
    mEmbellishData.coreFrame = nullptr;
    mEmbellishData.leadingSpace = 0;
    mEmbellishData.trailingSpace = 0;
    if (mMathMLChar.Length() != 1)
      mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;  
    // else... retain the native direction obtained in ProcessTextData()

    if (!mFrames.FirstChild()) {
      return;
    }

    mEmbellishData.flags |= NS_MATHML_EMBELLISH_OPERATOR;
    mEmbellishData.coreFrame = this;

    // there are two particular things that we also need to record so that if our
    // parent is <mover>, <munder>, or <munderover>, they will treat us properly:
    // 1) do we have accent="true"
    // 2) do we have movablelimits="true"

    // they need the extra information to decide how to treat their scripts/limits
    // (note: <mover>, <munder>, or <munderover> need not necessarily be our
    // direct parent -- case of embellished operators)

    // default values from the Operator Dictionary were obtained in ProcessTextData()
    // and these special bits are always kept in mFlags
    if (NS_MATHML_OPERATOR_IS_ACCENT(mFlags))
      mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
    if (NS_MATHML_OPERATOR_IS_MOVABLELIMITS(mFlags))
      mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;

    // see if the accent attribute is there
    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accent_, value);
    if (value.EqualsLiteral("true"))
      mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
    else if (value.EqualsLiteral("false"))
      mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT;

    // see if the movablelimits attribute is there
    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::movablelimits_, value);
    if (value.EqualsLiteral("true"))
      mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
    else if (value.EqualsLiteral("false"))
      mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_MOVABLELIMITS;

     // ---------------------------------------------------------------------
     // we will be called again to re-sync the rest of our state next time...
     // (nobody needs the other values below at this stage)
     mFlags |= form;
     return;
  }

  nsPresContext* presContext = PresContext();

  // beware of bug 133814 - there is a two-way dependency in the
  // embellished hierarchy: our embellished ancestors need to set
  // their flags based on some of our state (set above), and here we
  // need to re-sync our 'form' depending on our outermost embellished
  // container. A null form here means that an earlier attempt to stretch
  // our mMathMLChar failed, in which case we don't bother re-stretching again
  if (form) {
    // get our outermost embellished container and its parent. 
    // (we ensure that we are the core, not just a sibling of the core)
    nsIFrame* embellishAncestor = this;
    nsEmbellishData embellishData;
    nsIFrame* parentAncestor = this;
    do {
      embellishAncestor = parentAncestor;
      parentAncestor = embellishAncestor->GetParent();
      GetEmbellishDataFrom(parentAncestor, embellishData);
    } while (embellishData.coreFrame == this);

    // flag if we have an embellished ancestor
    if (embellishAncestor != this)
      mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;
    else
      mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ANCESTOR;

    // find the position of our outermost embellished container w.r.t
    // its siblings.

    nsIFrame* nextSibling = embellishAncestor->GetNextSibling();
    nsIFrame* prevSibling = embellishAncestor->GetPrevSibling();

    // flag to distinguish from a real infix.  Set for (embellished) operators
    // that live in (inferred) mrows.
    nsIMathMLFrame* mathAncestor = do_QueryFrame(parentAncestor);
    bool zeroSpacing = false;
    if (mathAncestor) {
      zeroSpacing =  !mathAncestor->IsMrowLike();
    } else {
      nsMathMLmathBlockFrame* blockFrame = do_QueryFrame(parentAncestor);
      if (blockFrame) {
        zeroSpacing = !blockFrame->IsMrowLike();
      }
    }
    if (zeroSpacing) {
      mFlags |= NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
    } else {
      mFlags &= ~NS_MATHML_OPERATOR_EMBELLISH_ISOLATED;
    }

    // find our form
    form = NS_MATHML_OPERATOR_FORM_INFIX;
    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::form, value);
    if (!value.IsEmpty()) {
      if (value.EqualsLiteral("prefix"))
        form = NS_MATHML_OPERATOR_FORM_PREFIX;
      else if (value.EqualsLiteral("postfix"))
        form = NS_MATHML_OPERATOR_FORM_POSTFIX;
    }
    else {
      // set our form flag depending on the position
      if (!prevSibling && nextSibling)
        form = NS_MATHML_OPERATOR_FORM_PREFIX;
      else if (prevSibling && !nextSibling)
        form = NS_MATHML_OPERATOR_FORM_POSTFIX;
    }
    mFlags &= ~NS_MATHML_OPERATOR_FORM; // clear the old form bits
    mFlags |= form;

    // Use the default value suggested by the MathML REC.
    // http://www.w3.org/TR/MathML/chapter3.html#presm.mo.attrs
    // thickmathspace = 5/18em
    float lspace = 5.0f/18.0f;
    float rspace = 5.0f/18.0f;
    // lookup the operator dictionary
    nsAutoString data;
    mMathMLChar.GetData(data);
    nsMathMLOperators::LookupOperator(data, form, &mFlags, &lspace, &rspace);
    // Spacing is zero if our outermost embellished operator is not in an
    // inferred mrow.
    if (!NS_MATHML_OPERATOR_EMBELLISH_IS_ISOLATED(mFlags) &&
        (lspace || rspace)) {
      // Cache the default values of lspace and rspace.
      // since these values are relative to the 'em' unit, convert to twips now
      nscoord em;
      nsRefPtr<nsFontMetrics> fm;
      nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
      GetEmHeight(fm, em);

      mEmbellishData.leadingSpace = NSToCoordRound(lspace * em);
      mEmbellishData.trailingSpace = NSToCoordRound(rspace * em);

      // tuning if we don't want too much extra space when we are a script.
      // (with its fonts, TeX sets lspace=0 & rspace=0 as soon as scriptlevel>0.
      // Our fonts can be anything, so...)
      if (StyleFont()->mScriptLevel > 0 &&
          !NS_MATHML_OPERATOR_HAS_EMBELLISH_ANCESTOR(mFlags)) {
        mEmbellishData.leadingSpace /= 2;
        mEmbellishData.trailingSpace /= 2;
      }
    }
  }

  // If we are an accent without explicit lspace="." or rspace=".",
  // we will ignore our default leading/trailing space

  // lspace
  //
  // "Specifies the leading space appearing before the operator"
  //
  // values: length
  // default: set by dictionary (thickmathspace) 
  //
  // XXXfredw Support for negative and relative values is not implemented
  // (bug 805926).
  // Relative values will give a multiple of the current leading space,
  // which is not necessarily the default one.
  //
  nscoord leadingSpace = mEmbellishData.leadingSpace;
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::lspace_, value);
  if (!value.IsEmpty()) {
    nsCSSValue cssValue;
    if (nsMathMLElement::ParseNumericValue(value, cssValue, 0,
                                           mContent->OwnerDoc())) {
      if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
        leadingSpace = 0;
      else if (cssValue.IsLengthUnit())
        leadingSpace = CalcLength(presContext, mStyleContext, cssValue);
      mFlags |= NS_MATHML_OPERATOR_LSPACE_ATTR;
    }
  }

  // rspace
  //
  // "Specifies the trailing space appearing after the operator"
  //
  // values: length
  // default: set by dictionary (thickmathspace) 
  //
  // XXXfredw Support for negative and relative values is not implemented
  // (bug 805926).
  // Relative values will give a multiple of the current leading space,
  // which is not necessarily the default one.
  //
  nscoord trailingSpace = mEmbellishData.trailingSpace;
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rspace_, value);
  if (!value.IsEmpty()) {
    nsCSSValue cssValue;
    if (nsMathMLElement::ParseNumericValue(value, cssValue, 0,
                                           mContent->OwnerDoc())) {
      if ((eCSSUnit_Number == cssValue.GetUnit()) && !cssValue.GetFloatValue())
        trailingSpace = 0;
      else if (cssValue.IsLengthUnit())
        trailingSpace = CalcLength(presContext, mStyleContext, cssValue);
      mFlags |= NS_MATHML_OPERATOR_RSPACE_ATTR;
    }
  }

  // little extra tuning to round lspace & rspace to at least a pixel so that
  // operators don't look as if they are colliding with their operands
  if (leadingSpace || trailingSpace) {
    nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
    if (leadingSpace && leadingSpace < onePixel)
      leadingSpace = onePixel;
    if (trailingSpace && trailingSpace < onePixel)
      trailingSpace = onePixel;
  }

  // the values that we get from our attributes override the dictionary
  mEmbellishData.leadingSpace = leadingSpace;
  mEmbellishData.trailingSpace = trailingSpace;

  // Now see if there are user-defined attributes that override the dictionary.
  // XXX If an attribute can be forced to be true when it is false in the
  // dictionary, then the following code has to change...

  // For each attribute overriden by the user, turn off its bit flag.
  // symmetric|movablelimits|separator|largeop|accent|fence|stretchy|form
  // special: accent and movablelimits are handled above,
  // don't process them here

  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::stretchy_, value);
  if (value.EqualsLiteral("false")) {
    mFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
  } else if (value.EqualsLiteral("true")) {
    mFlags |= NS_MATHML_OPERATOR_STRETCHY;
  }
  if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) {
    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::fence_, value);
    if (value.EqualsLiteral("false"))
      mFlags &= ~NS_MATHML_OPERATOR_FENCE;
  }
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::largeop_, value);
  if (value.EqualsLiteral("false")) {
    mFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
  } else if (value.EqualsLiteral("true")) {
    mFlags |= NS_MATHML_OPERATOR_LARGEOP;
  }
  if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) {
    mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::separator_, value);
    if (value.EqualsLiteral("false"))
      mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
  }
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::symmetric_, value);
  if (value.EqualsLiteral("false"))
    mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC;
  else if (value.EqualsLiteral("true"))
    mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;


  // minsize
  //
  // "Specifies the minimum size of the operator when stretchy"
  //
  // values: length
  // default: set by dictionary (1em)
  //
  // We don't allow negative values.
  // Note: Contrary to other "length" values, unitless and percentage do not
  // give a multiple of the defaut value but a multiple of the operator at
  // normal size.
  //
  mMinSize = 0;
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::minsize_, value);
  if (!value.IsEmpty()) {
    nsCSSValue cssValue;
    if (nsMathMLElement::ParseNumericValue(value, cssValue,
                                           nsMathMLElement::
                                           PARSE_ALLOW_UNITLESS,
                                           mContent->OwnerDoc())) {
      nsCSSUnit unit = cssValue.GetUnit();
      if (eCSSUnit_Number == unit)
        mMinSize = cssValue.GetFloatValue();
      else if (eCSSUnit_Percent == unit)
        mMinSize = cssValue.GetPercentValue();
      else if (eCSSUnit_Null != unit) {
        mMinSize = float(CalcLength(presContext, mStyleContext, cssValue));
        mFlags |= NS_MATHML_OPERATOR_MINSIZE_ABSOLUTE;
      }
    }
  }

  // maxsize
  //
  // "Specifies the maximum size of the operator when stretchy"
  //
  // values: length | "infinity"
  // default: set by dictionary (infinity)
  //
  // We don't allow negative values.
  // Note: Contrary to other "length" values, unitless and percentage do not
  // give a multiple of the defaut value but a multiple of the operator at
  // normal size.
  //
  mMaxSize = NS_MATHML_OPERATOR_SIZE_INFINITY;
  mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::maxsize_, value);
  if (!value.IsEmpty()) {
    nsCSSValue cssValue;
    if (nsMathMLElement::ParseNumericValue(value, cssValue,
                                           nsMathMLElement::
                                           PARSE_ALLOW_UNITLESS,
                                           mContent->OwnerDoc())) {
      nsCSSUnit unit = cssValue.GetUnit();
      if (eCSSUnit_Number == unit)
        mMaxSize = cssValue.GetFloatValue();
      else if (eCSSUnit_Percent == unit)
        mMaxSize = cssValue.GetPercentValue();
      else if (eCSSUnit_Null != unit) {
        mMaxSize = float(CalcLength(presContext, mStyleContext, cssValue));
        mFlags |= NS_MATHML_OPERATOR_MAXSIZE_ABSOLUTE;
      }
    }
  }
}
NS_IMETHODIMP
nsMathMLmfencedFrame::Reflow(nsPresContext*          aPresContext,
                             nsHTMLReflowMetrics&     aDesiredSize,
                             const nsHTMLReflowState& aReflowState,
                             nsReflowStatus&          aStatus)
{
  nsresult rv;
  aDesiredSize.width = aDesiredSize.height = 0;
  aDesiredSize.ascent = 0;
  aDesiredSize.mBoundingMetrics = nsBoundingMetrics();

  PRInt32 i;
  const nsStyleFont* font = GetStyleFont();
  nsRefPtr<nsFontMetrics> fm;
  nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
  aReflowState.rendContext->SetFont(fm);
  nscoord axisHeight, em;
  GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
  GetEmHeight(fm, em);
  // leading to be left at the top and the bottom of stretched chars
  nscoord leading = NSToCoordRound(0.2f * em); 

  /////////////
  // Reflow children
  // Asking each child to cache its bounding metrics

  // Note that we don't use the base method nsMathMLContainerFrame::Reflow()
  // because we want to stretch our fences, separators and stretchy frames using
  // the *same* initial aDesiredSize.mBoundingMetrics. If we were to use the base
  // method here, our stretchy frames will be stretched and placed, and we may
  // end up stretching our fences/separators with a different aDesiredSize.
  // XXX The above decision was revisited in bug 121748 and this code can be
  // refactored to use nsMathMLContainerFrame::Reflow() at some stage.

  nsReflowStatus childStatus;
  nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE);
  nsIFrame* firstChild = GetFirstChild(nsnull);
  nsIFrame* childFrame = firstChild;
  nscoord ascent = 0, descent = 0;
  if (firstChild || mOpenChar || mCloseChar || mSeparatorsCount > 0) {
    // We use the ASCII metrics to get our minimum height. This way,
    // if we have borders or a background, they will fit better with
    // other elements on the line.
    ascent = fm->MaxAscent();
    descent = fm->MaxDescent();
  }
  while (childFrame) {
    nsHTMLReflowMetrics childDesiredSize(aDesiredSize.mFlags
                                         | NS_REFLOW_CALC_BOUNDING_METRICS);
    nsHTMLReflowState childReflowState(aPresContext, aReflowState,
                                       childFrame, availSize);
    rv = ReflowChild(childFrame, aPresContext, childDesiredSize,
                     childReflowState, childStatus);
    //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
    if (NS_FAILED(rv)) {
      // Call DidReflow() for the child frames we successfully did reflow.
      DidReflowChildren(firstChild, childFrame);
      return rv;
    }

    SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
                                    childDesiredSize.mBoundingMetrics);

    nscoord childDescent = childDesiredSize.height - childDesiredSize.ascent;
    if (descent < childDescent)
      descent = childDescent;
    if (ascent < childDesiredSize.ascent)
      ascent = childDesiredSize.ascent;

    childFrame = childFrame->GetNextSibling();
  }

  /////////////
  // Ask stretchy children to stretch themselves

  nsBoundingMetrics containerSize;
  nsStretchDirection stretchDir = NS_STRETCH_DIRECTION_VERTICAL;

  GetPreferredStretchSize(*aReflowState.rendContext,
                          0, /* i.e., without embellishments */
                          stretchDir, containerSize);
  childFrame = firstChild;
  while (childFrame) {
    nsIMathMLFrame* mathmlChild = do_QueryFrame(childFrame);
    if (mathmlChild) {
      nsHTMLReflowMetrics childDesiredSize;
      // retrieve the metrics that was stored at the previous pass
      GetReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
                                     childDesiredSize.mBoundingMetrics);
      
      mathmlChild->Stretch(*aReflowState.rendContext, 
                           stretchDir, containerSize, childDesiredSize);
      // store the updated metrics
      SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
                                      childDesiredSize.mBoundingMetrics);
      
      nscoord childDescent = childDesiredSize.height - childDesiredSize.ascent;
      if (descent < childDescent)
        descent = childDescent;
      if (ascent < childDesiredSize.ascent)
        ascent = childDesiredSize.ascent;
    }
    childFrame = childFrame->GetNextSibling();
  }

  // bug 121748: for surrounding fences & separators, use a size that covers everything
  GetPreferredStretchSize(*aReflowState.rendContext,
                          STRETCH_CONSIDER_EMBELLISHMENTS,
                          stretchDir, containerSize);

  //////////////////////////////////////////
  // Prepare the opening fence, separators, and closing fence, and
  // adjust the origin of children.

  // we need to center around the axis
  nscoord delta = NS_MAX(containerSize.ascent - axisHeight, 
                         containerSize.descent + axisHeight);
  containerSize.ascent = delta + axisHeight;
  containerSize.descent = delta - axisHeight;

  /////////////////
  // opening fence ...
  ReflowChar(aPresContext, *aReflowState.rendContext, mOpenChar,
             NS_MATHML_OPERATOR_FORM_PREFIX, font->mScriptLevel, 
             axisHeight, leading, em, containerSize, ascent, descent);
  /////////////////
  // separators ...
  for (i = 0; i < mSeparatorsCount; i++) {
    ReflowChar(aPresContext, *aReflowState.rendContext, &mSeparatorsChar[i],
               NS_MATHML_OPERATOR_FORM_INFIX, font->mScriptLevel,
               axisHeight, leading, em, containerSize, ascent, descent);
  }
  /////////////////
  // closing fence ...
  ReflowChar(aPresContext, *aReflowState.rendContext, mCloseChar,
             NS_MATHML_OPERATOR_FORM_POSTFIX, font->mScriptLevel,
             axisHeight, leading, em, containerSize, ascent, descent);

  //////////////////
  // Adjust the origins of each child.
  // and update our bounding metrics

  i = 0;
  nscoord dx = 0;
  nsBoundingMetrics bm;
  PRBool firstTime = PR_TRUE;
  if (mOpenChar) {
    PlaceChar(mOpenChar, ascent, bm, dx);
    aDesiredSize.mBoundingMetrics = bm;
    firstTime = PR_FALSE;
  }

  childFrame = firstChild;
  while (childFrame) {
    nsHTMLReflowMetrics childSize;
    GetReflowAndBoundingMetricsFor(childFrame, childSize, bm);
    if (firstTime) {
      firstTime = PR_FALSE;
      aDesiredSize.mBoundingMetrics  = bm;
    }
    else  
      aDesiredSize.mBoundingMetrics += bm;

    FinishReflowChild(childFrame, aPresContext, nsnull, childSize, 
                      dx, ascent - childSize.ascent, 0);
    dx += childSize.width;

    if (i < mSeparatorsCount) {
      PlaceChar(&mSeparatorsChar[i], ascent, bm, dx);
      aDesiredSize.mBoundingMetrics += bm;
    }
    i++;

    childFrame = childFrame->GetNextSibling();
  }

  if (mCloseChar) {
    PlaceChar(mCloseChar, ascent, bm, dx);
    if (firstTime)
      aDesiredSize.mBoundingMetrics  = bm;
    else  
      aDesiredSize.mBoundingMetrics += bm;
  }

  aDesiredSize.width = aDesiredSize.mBoundingMetrics.width;
  aDesiredSize.height = ascent + descent;
  aDesiredSize.ascent = ascent;

  SetBoundingMetrics(aDesiredSize.mBoundingMetrics);
  SetReference(nsPoint(0, aDesiredSize.ascent));

  // see if we should fix the spacing
  FixInterFrameSpacing(aDesiredSize);

  // Finished with these:
  ClearSavedChildMetrics();

  // Set our overflow area
  GatherAndStoreOverflow(&aDesiredSize);

  aStatus = NS_FRAME_COMPLETE;
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  return NS_OK;
}
Пример #26
0
NS_IMETHODIMP
nsSliderFrame::AttributeChanged(PRInt32 aNameSpaceID,
                                nsIAtom* aAttribute,
                                PRInt32 aModType)
{
  nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
                                             aModType);
  // if the current position changes
  if (aAttribute == nsGkAtoms::curpos) {
     rv = CurrentPositionChanged(PresContext(), PR_FALSE);
     NS_ASSERTION(NS_SUCCEEDED(rv), "failed to change position");
     if (NS_FAILED(rv))
        return rv;
  } else if (aAttribute == nsGkAtoms::minpos ||
             aAttribute == nsGkAtoms::maxpos) {
      // bounds check it.

      nsIBox* scrollbarBox = GetScrollbar();
      nsCOMPtr<nsIContent> scrollbar;
      scrollbar = GetContentOfBox(scrollbarBox);
      PRInt32 current = GetCurrentPosition(scrollbar);
      PRInt32 min = GetMinPosition(scrollbar);
      PRInt32 max = GetMaxPosition(scrollbar);

      // inform the parent <scale> that the minimum or maximum changed
      nsIFrame* parent = GetParent();
      if (parent) {
        nsCOMPtr<nsISliderListener> sliderListener = do_QueryInterface(parent->GetContent());
        if (sliderListener) {
          nsContentUtils::AddScriptRunner(
            new nsValueChangedRunnable(sliderListener, aAttribute,
                                       aAttribute == nsGkAtoms::minpos ? min : max, PR_FALSE));
        }
      }

      if (current < min || current > max)
      {
        if (current < min || max < min)
            current = min;
        else if (current > max)
            current = max;

        // set the new position and notify observers
        nsIScrollbarFrame* scrollbarFrame = do_QueryFrame(scrollbarBox);
        if (scrollbarFrame) {
          nsIScrollbarMediator* mediator = scrollbarFrame->GetScrollbarMediator();
          if (mediator) {
            mediator->PositionChanged(scrollbarFrame, GetCurrentPosition(scrollbar), current);
          }
        }

        nsAutoString currentStr;
        currentStr.AppendInt(current);
        nsContentUtils::AddScriptRunner(
          new nsSetAttrRunnable(scrollbar, nsGkAtoms::curpos, currentStr));
      }
  }

  if (aAttribute == nsGkAtoms::minpos ||
      aAttribute == nsGkAtoms::maxpos ||
      aAttribute == nsGkAtoms::pageincrement ||
      aAttribute == nsGkAtoms::increment) {

      PresContext()->PresShell()->
        FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  }

  return rv;
}
Пример #27
0
void nsWebBrowserFind::SetSelectionAndScroll(nsIDOMWindow* aWindow,
                                             nsIDOMRange*  aRange)
{
  nsCOMPtr<nsIDOMDocument> domDoc;    
  aWindow->GetDocument(getter_AddRefs(domDoc));
  if (!domDoc) return;

  nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
  nsIPresShell* presShell = doc->GetShell();
  if (!presShell) return;

  nsCOMPtr<nsIDOMNode> node;
  aRange->GetStartContainer(getter_AddRefs(node));
  nsCOMPtr<nsIContent> content(do_QueryInterface(node));
  nsIFrame* frame = content->GetPrimaryFrame();
  if (!frame)
      return;
  nsCOMPtr<nsISelectionController> selCon;
  frame->GetSelectionController(presShell->GetPresContext(),
                                getter_AddRefs(selCon));
  
  // since the match could be an anonymous textnode inside a
  // <textarea> or text <input>, we need to get the outer frame
  nsITextControlFrame *tcFrame = nullptr;
  for ( ; content; content = content->GetParent()) {
    if (!IsInNativeAnonymousSubtree(content)) {
      nsIFrame* f = content->GetPrimaryFrame();
      if (!f)
        return;
      tcFrame = do_QueryFrame(f);
      break;
    }
  }

  nsCOMPtr<nsISelection> selection;

  selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
  selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
    getter_AddRefs(selection));
  if (selection) {
    selection->RemoveAllRanges();
    selection->AddRange(aRange);

    nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
    if (fm) {
      if (tcFrame) {
        nsCOMPtr<nsIDOMElement> newFocusedElement(do_QueryInterface(content));
        fm->SetFocus(newFocusedElement, nsIFocusManager::FLAG_NOSCROLL);
      }
      else  {
        nsCOMPtr<nsIDOMElement> result;
        fm->MoveFocus(aWindow, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
                      nsIFocusManager::FLAG_NOSCROLL,
                      getter_AddRefs(result));
      }
    }

    // Scroll if necessary to make the selection visible:
    // Must be the last thing to do - bug 242056

    // After ScrollSelectionIntoView(), the pending notifications might be
    // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
    selCon->ScrollSelectionIntoView
      (nsISelectionController::SELECTION_NORMAL,
       nsISelectionController::SELECTION_WHOLE_SELECTION,
       nsISelectionController::SCROLL_CENTER_VERTICALLY |
       nsISelectionController::SCROLL_SYNCHRONOUS);
  }
}
Пример #28
0
nsIScrollableFrame* ScrollBoxObject::GetScrollFrame()
{
  return do_QueryFrame(GetFrame(false));
}
void
nsGridRowLeafLayout::ComputeChildSizes(nsIBox* aBox,
                           nsBoxLayoutState& aState, 
                           nscoord& aGivenSize, 
                           nsBoxSize* aBoxSizes, 
                           nsComputedBoxSize*& aComputedBoxSizes)
{ 
  // see if we are in a scrollable frame. If we are then there could be scrollbars present
  // if so we need to subtract them out to make sure our columns line up.
  if (aBox) {
    PRBool isHorizontal = aBox->IsHorizontal();

    // go up the parent chain looking for scrollframes
    nscoord diff = 0;
    nsIBox* parentBox;
    nsIGridPart* parent = GetParentGridPart(aBox, &parentBox);
    while (parentBox) {
      nsIBox* scrollbox = nsGrid::GetScrollBox(parentBox);
      nsIScrollableFrame *scrollable = do_QueryFrame(scrollbox);
      if (scrollable) {
        // Don't call GetActualScrollbarSizes here because it's not safe
        // to call that while we're reflowing the contents of the scrollframe,
        // which we are here.
        nsMargin scrollbarSizes = scrollable->GetDesiredScrollbarSizes(&aState);
        PRUint32 visible = scrollable->GetScrollbarVisibility();

        if (isHorizontal && (visible & nsIScrollableFrame::VERTICAL)) {
          diff += scrollbarSizes.left + scrollbarSizes.right;
        } else if (!isHorizontal && (visible & nsIScrollableFrame::HORIZONTAL)) {
          diff += scrollbarSizes.top + scrollbarSizes.bottom;
        }
      }

      parent = GetParentGridPart(parentBox, &parentBox);
    }

    if (diff > 0) {
      aGivenSize += diff;

      nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes);

      aGivenSize -= diff;

      nsComputedBoxSize* s    = aComputedBoxSizes;
      nsComputedBoxSize* last = aComputedBoxSizes;
      while(s)
      {
        last = s;
        s = s->next;
      }
  
      if (last) 
        last->size -= diff;                         

      return;
    }
  }
      
  nsSprocketLayout::ComputeChildSizes(aBox, aState, aGivenSize, aBoxSizes, aComputedBoxSizes);

}
Пример #30
0
// Returns true if this function managed to successfully move a frame, and
// false if it could not process the position change, and a reflow should
// be performed instead.
bool
RecomputePosition(nsIFrame* aFrame)
{
  // Don't process position changes on table frames, since we already handle
  // the dynamic position change on the table wrapper frame, and the
  // reflow-based fallback code path also ignores positions on inner table
  // frames.
  if (aFrame->GetType() == nsGkAtoms::tableFrame) {
    return true;
  }

  const nsStyleDisplay* display = aFrame->StyleDisplay();
  // Changes to the offsets of a non-positioned element can safely be ignored.
  if (display->mPosition == NS_STYLE_POSITION_STATIC) {
    return true;
  }

  // Don't process position changes on frames which have views or the ones which
  // have a view somewhere in their descendants, because the corresponding view
  // needs to be repositioned properly as well.
  if (aFrame->HasView() ||
      (aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
    StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
    return false;
  }

  aFrame->SchedulePaint();

  // For relative positioning, we can simply update the frame rect
  if (display->IsRelativelyPositionedStyle()) {
    // Move the frame
    if (display->mPosition == NS_STYLE_POSITION_STICKY) {
      if (display->IsInnerTableStyle()) {
        // We don't currently support sticky positioning of inner table
        // elements (bug 975644). Bail.
        //
        // When this is fixed, remove the null-check for the computed
        // offsets in nsTableRowFrame::ReflowChildren.
        return true;
      }

      // Update sticky positioning for an entire element at once, starting with
      // the first continuation or ib-split sibling.
      // It's rare that the frame we already have isn't already the first
      // continuation or ib-split sibling, but it can happen when styles differ
      // across continuations such as ::first-line or ::first-letter, and in
      // those cases we will generally (but maybe not always) do the work twice.
      nsIFrame* firstContinuation =
        nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);

      StickyScrollContainer::ComputeStickyOffsets(firstContinuation);
      StickyScrollContainer* ssc =
        StickyScrollContainer::GetStickyScrollContainerForFrame(
          firstContinuation);
      if (ssc) {
        ssc->PositionContinuations(firstContinuation);
      }
    } else {
      MOZ_ASSERT(NS_STYLE_POSITION_RELATIVE == display->mPosition,
                 "Unexpected type of positioning");
      for (nsIFrame* cont = aFrame; cont;
           cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
        nsIFrame* cb = cont->GetContainingBlock();
        nsMargin newOffsets;
        WritingMode wm = cb->GetWritingMode();
        const LogicalSize size(wm, cb->GetContentRectRelativeToSelf().Size());

        ReflowInput::ComputeRelativeOffsets(wm, cont, size, newOffsets);
        NS_ASSERTION(newOffsets.left == -newOffsets.right &&
                     newOffsets.top == -newOffsets.bottom,
                     "ComputeRelativeOffsets should return valid results");

        // ReflowInput::ApplyRelativePositioning would work here, but
        // since we've already checked mPosition and aren't changing the frame's
        // normal position, go ahead and add the offsets directly.
        cont->SetPosition(cont->GetNormalPosition() +
                          nsPoint(newOffsets.left, newOffsets.top));
      }
    }

    return true;
  }

  // For the absolute positioning case, set up a fake HTML reflow state for
  // the frame, and then get the offsets and size from it. If the frame's size
  // doesn't need to change, we can simply update the frame position. Otherwise
  // we fall back to a reflow.
  nsRenderingContext rc(
    aFrame->PresContext()->PresShell()->CreateReferenceRenderingContext());

  // Construct a bogus parent reflow state so that there's a usable
  // containing block reflow state.
  nsIFrame* parentFrame = aFrame->GetParent();
  WritingMode parentWM = parentFrame->GetWritingMode();
  WritingMode frameWM = aFrame->GetWritingMode();
  LogicalSize parentSize = parentFrame->GetLogicalSize();

  nsFrameState savedState = parentFrame->GetStateBits();
  ReflowInput parentReflowInput(aFrame->PresContext(), parentFrame, &rc,
                                parentSize);
  parentFrame->RemoveStateBits(~nsFrameState(0));
  parentFrame->AddStateBits(savedState);

  // The bogus parent state here was created with no parent state of its own,
  // and therefore it won't have an mCBReflowInput set up.
  // But we may need one (for InitCBReflowInput in a child state), so let's
  // try to create one here for the cases where it will be needed.
  Maybe<ReflowInput> cbReflowInput;
  nsIFrame* cbFrame = parentFrame->GetContainingBlock();
  if (cbFrame && (aFrame->GetContainingBlock() != parentFrame ||
                  parentFrame->GetType() == nsGkAtoms::tableFrame)) {
    LogicalSize cbSize = cbFrame->GetLogicalSize();
    cbReflowInput.emplace(cbFrame->PresContext(), cbFrame, &rc, cbSize);
    cbReflowInput->ComputedPhysicalMargin() = cbFrame->GetUsedMargin();
    cbReflowInput->ComputedPhysicalPadding() = cbFrame->GetUsedPadding();
    cbReflowInput->ComputedPhysicalBorderPadding() =
      cbFrame->GetUsedBorderAndPadding();
    parentReflowInput.mCBReflowInput = cbReflowInput.ptr();
  }

  NS_WARN_IF_FALSE(parentSize.ISize(parentWM) != NS_INTRINSICSIZE &&
                   parentSize.BSize(parentWM) != NS_INTRINSICSIZE,
                   "parentSize should be valid");
  parentReflowInput.SetComputedISize(std::max(parentSize.ISize(parentWM), 0));
  parentReflowInput.SetComputedBSize(std::max(parentSize.BSize(parentWM), 0));
  parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);

  parentReflowInput.ComputedPhysicalPadding() = parentFrame->GetUsedPadding();
  parentReflowInput.ComputedPhysicalBorderPadding() =
    parentFrame->GetUsedBorderAndPadding();
  LogicalSize availSize = parentSize.ConvertTo(frameWM, parentWM);
  availSize.BSize(frameWM) = NS_INTRINSICSIZE;

  ViewportFrame* viewport = do_QueryFrame(parentFrame);
  nsSize cbSize = viewport ?
    viewport->AdjustReflowInputAsContainingBlock(&parentReflowInput).Size()
    : aFrame->GetContainingBlock()->GetSize();
  const nsMargin& parentBorder =
    parentReflowInput.mStyleBorder->GetComputedBorder();
  cbSize -= nsSize(parentBorder.LeftRight(), parentBorder.TopBottom());
  LogicalSize lcbSize(frameWM, cbSize);
  ReflowInput reflowInput(aFrame->PresContext(), parentReflowInput, aFrame,
                          availSize, &lcbSize);
  nsSize computedSize(reflowInput.ComputedWidth(),
                      reflowInput.ComputedHeight());
  computedSize.width += reflowInput.ComputedPhysicalBorderPadding().LeftRight();
  if (computedSize.height != NS_INTRINSICSIZE) {
    computedSize.height +=
      reflowInput.ComputedPhysicalBorderPadding().TopBottom();
  }
  nsSize size = aFrame->GetSize();
  // The RecomputePosition hint is not used if any offset changed between auto
  // and non-auto. If computedSize.height == NS_INTRINSICSIZE then the new
  // element height will be its intrinsic height, and since 'top' and 'bottom''s
  // auto-ness hasn't changed, the old height must also be its intrinsic
  // height, which we can assume hasn't changed (or reflow would have
  // been triggered).
  if (computedSize.width == size.width &&
      (computedSize.height == NS_INTRINSICSIZE || computedSize.height == size.height)) {
    // If we're solving for 'left' or 'top', then compute it here, in order to
    // match the reflow code path.
    if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().left) {
      reflowInput.ComputedPhysicalOffsets().left = cbSize.width -
                                          reflowInput.ComputedPhysicalOffsets().right -
                                          reflowInput.ComputedPhysicalMargin().right -
                                          size.width -
                                          reflowInput.ComputedPhysicalMargin().left;
    }

    if (NS_AUTOOFFSET == reflowInput.ComputedPhysicalOffsets().top) {
      reflowInput.ComputedPhysicalOffsets().top = cbSize.height -
                                         reflowInput.ComputedPhysicalOffsets().bottom -
                                         reflowInput.ComputedPhysicalMargin().bottom -
                                         size.height -
                                         reflowInput.ComputedPhysicalMargin().top;
    }

    // Move the frame
    nsPoint pos(parentBorder.left + reflowInput.ComputedPhysicalOffsets().left +
                reflowInput.ComputedPhysicalMargin().left,
                parentBorder.top + reflowInput.ComputedPhysicalOffsets().top +
                reflowInput.ComputedPhysicalMargin().top);
    aFrame->SetPosition(pos);

    return true;
  }

  // Fall back to a reflow
  StyleChangeReflow(aFrame, nsChangeHint_NeedReflow);
  return false;
}