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(); }
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; }
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; }
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); }
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 ); } } }
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 } }
nsINode* PopupBoxObject::GetTriggerNode() const { nsMenuPopupFrame *menuPopupFrame = mContent ? do_QueryFrame(mContent->GetPrimaryFrame()) : nullptr; return nsMenuPopupFrame::GetTriggerContent(menuPopupFrame); }
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; } }
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; }
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; }
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; } }
void nsComboboxControlFrame::SetDropDown(nsIFrame* aDropDownFrame) { mDropdownFrame = aDropDownFrame; mListControlFrame = do_QueryFrame(mDropdownFrame); }
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; }
nsTextControlFrame* nsFileControlFrame::GetTextControlFrame() { nsITextControlFrame* tc = do_QueryFrame(mTextContent->GetPrimaryFrame()); return static_cast<nsTextControlFrame*>(tc); }
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; }
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; }
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); } }
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; }
/** * 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; }
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; }
// 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; }
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; }
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); } }
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); }
// 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; }